All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/37] dccp: Feature negotiation - last call for comments
@ 2008-08-28 17:44   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev

This is a last call for comments and review for the DCCP feature negotiation set,
before sending a pull request.

This set replaces the initial implementation of feature negotiation with a fairly 
complete set of routines to support negotiation between endpoints. 

It fixes the (known) problems with the old infrastructure, which was an initial
implementation that apparently never was developed further.

The patches have been publicly available in the test tree for about a year
and were widely tested.

Since several applications are using this API and since there is already at
least one publicly available application (gstreamer) based on the new API,
it would be good to have this available in mainline.

This set deals with the negotiation of capabilities, before a connection is
established. There is also support for dynamically updating feature values,
this will follow in a second set -- a much smaller set since it builds upon
the new basis.

Please send any comments or issues you find with the code before the end of the
week. I will then prepare a second submission / pull request.


Part I - Basis
---------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  
Patch #6: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #7: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #8: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #9: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

Part II - Core	  
--------------
Patch #10: Provides a mechanism to then resolve CCID-dependent features. Since
           CCIDs are a server-priority feature, this is done by the server.
Patch #11: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #12: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #13: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #14: Tidies up the setsockopt interface for new additions.
Patch #15: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #16: Socket API to query the current CCID from userspace.
Patch #17: Prepares the variable-length htonl/ntohl functions for 48 bits.
           Such a length is needed by e.g. the Sequence Window feature.
Patch #18: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #19: Routine to insert feature-negotiation header options.
Patch #20: Complements #19, to add feature-negotiation options onto the skb.
Patch #21: Complements #20 and completes the insertion of featneg options.
Patch #22: Logic/algorithm to actually reconcile negotiation options.
Patch #23: Receiver support to process incoming Change L/R options. 
Patch #24: Receiver support to process incoming Confirm R/L options.
Patch #25: Handlers for activating successfully negotiated features.

Part III - Integration and cleanup
----------------------------------
Patch #26: Integration of dynamic negotiation, part I (socket setup).
Patch #27: Integration of dynamic negotiation, part II (server side).
Patch #28: Integration of dynamic negotiation, part III (client side).

Patch #29: Cleans up the older infrastructure.
Patch #30: Removes obsolete parts of the old CCID interface.
Patch #31: Removes manual intervention on NDP count (now automatic).
Patch #32: Removes Ack Vector sysctl (handled automatically now).

Patch #33: Initialisation framework for the supported features.
Patch #34: Auto-loading of CCID modules so that the modules are available
           when the negotiation is completed.
Patch #35: Adds full support for local/remote Sequence Window.
Patch #36: Initialisation and type-checking of involved sysctls.
Patch #37: A set of (useful) debugging/printing helper functions.


As always, patches are available on 

	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']

There is also a gitweb view on the server.


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/37] dccp: Feature negotiation - last call for comments
@ 2008-08-28 17:44   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This is a last call for comments and review for the DCCP feature negotiation set,
before sending a pull request.

This set replaces the initial implementation of feature negotiation with a fairly 
complete set of routines to support negotiation between endpoints. 

It fixes the (known) problems with the old infrastructure, which was an initial
implementation that apparently never was developed further.

The patches have been publicly available in the test tree for about a year
and were widely tested.

Since several applications are using this API and since there is already at
least one publicly available application (gstreamer) based on the new API,
it would be good to have this available in mainline.

This set deals with the negotiation of capabilities, before a connection is
established. There is also support for dynamically updating feature values,
this will follow in a second set -- a much smaller set since it builds upon
the new basis.

Please send any comments or issues you find with the code before the end of the
week. I will then prepare a second submission / pull request.


Part I - Basis
---------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  
Patch #6: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #7: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #8: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #9: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

Part II - Core	  
--------------
Patch #10: Provides a mechanism to then resolve CCID-dependent features. Since
           CCIDs are a server-priority feature, this is done by the server.
Patch #11: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #12: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #13: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #14: Tidies up the setsockopt interface for new additions.
Patch #15: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #16: Socket API to query the current CCID from userspace.
Patch #17: Prepares the variable-length htonl/ntohl functions for 48 bits.
           Such a length is needed by e.g. the Sequence Window feature.
Patch #18: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #19: Routine to insert feature-negotiation header options.
Patch #20: Complements #19, to add feature-negotiation options onto the skb.
Patch #21: Complements #20 and completes the insertion of featneg options.
Patch #22: Logic/algorithm to actually reconcile negotiation options.
Patch #23: Receiver support to process incoming Change L/R options. 
Patch #24: Receiver support to process incoming Confirm R/L options.
Patch #25: Handlers for activating successfully negotiated features.

Part III - Integration and cleanup
----------------------------------
Patch #26: Integration of dynamic negotiation, part I (socket setup).
Patch #27: Integration of dynamic negotiation, part II (server side).
Patch #28: Integration of dynamic negotiation, part III (client side).

Patch #29: Cleans up the older infrastructure.
Patch #30: Removes obsolete parts of the old CCID interface.
Patch #31: Removes manual intervention on NDP count (now automatic).
Patch #32: Removes Ack Vector sysctl (handled automatically now).

Patch #33: Initialisation framework for the supported features.
Patch #34: Auto-loading of CCID modules so that the modules are available
           when the negotiation is completed.
Patch #35: Adds full support for local/remote Sequence Window.
Patch #36: Initialisation and type-checking of involved sysctls.
Patch #37: A set of (useful) debugging/printing helper functions.


As always, patches are available on 

	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']

There is also a gitweb view on the server.


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 01/37] dccp: Basic data structure for feature negotiation
@ 2008-08-28 17:44     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   14 ++++++++++++
 net/dccp/feat.h |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,66 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @feat_num: one of %dccp_feature_numbers
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	u8                      feat_num;
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	bool			needs_mandatory:1,
+				needs_confirm:1,
+				empty_confirm:1,
+				is_local:1;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 01/37] dccp: Basic data structure for feature negotiation
@ 2008-08-28 17:44     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   14 ++++++++++++
 net/dccp/feat.h |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec = NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,66 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @feat_num: one of %dccp_feature_numbers
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	u8                      feat_num;
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	bool			needs_mandatory:1,
+				needs_confirm:1,
+				empty_confirm:1,
+				is_local:1;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 02/37] dccp: Implement lookup table for feature-negotiation information
@ 2008-08-28 17:44       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,80 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	return idx < 0 ? : dccp_feat_table[idx].default_value;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +111,42 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (val && dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +763,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 02/37] dccp: Implement lookup table for feature-negotiation information
@ 2008-08-28 17:44       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  112 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,80 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	return idx < 0 ? : dccp_feat_table[idx].default_value;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +111,42 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (val && dccp_feat_type(feat_num) = FEAT_SP)
+		kfree(val->sp.vec);
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type = FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new = NULL)
+		return NULL;
+
+	if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +763,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-28 17:44         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -147,6 +147,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 	}
 }
 
+/*
+ *	List management functions
+ */
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @fn: list to add to
+ * @feat: feature number
+ * @is_local: whether the local (1) or remote feature with number @feat is meant
+ * The function maintains and relies on the following invariants:
+ *  - each feat_num in the list is known, ie. we know its type and default value
+ *  - each feat_num/is_local combination is unique (old entries are overwritten)
+ *  - SP values are always freshly allocated
+ *  - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
+{
+	struct dccp_feat_entry *entry;
+	struct list_head *pos_head = fn;
+
+	list_for_each(pos_head, fn) {
+		entry = list_entry(pos_head, struct dccp_feat_entry, node);
+		if (feat < entry->feat_num)
+			break;
+		if (entry->feat_num == feat && entry->is_local == is_local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		}
+	}
+	entry = kmalloc(sizeof(struct dccp_feat_entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = is_local;
+		list_add_tail(&entry->node, pos_head);
+	}
+	return entry;
+}
+
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, u8 is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval == NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-28 17:44         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -147,6 +147,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 	}
 }
 
+/*
+ *	List management functions
+ */
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @fn: list to add to
+ * @feat: feature number
+ * @is_local: whether the local (1) or remote feature with number @feat is meant
+ * The function maintains and relies on the following invariants:
+ *  - each feat_num in the list is known, ie. we know its type and default value
+ *  - each feat_num/is_local combination is unique (old entries are overwritten)
+ *  - SP values are always freshly allocated
+ *  - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
+{
+	struct dccp_feat_entry *entry;
+	struct list_head *pos_head = fn;
+
+	list_for_each(pos_head, fn) {
+		entry = list_entry(pos_head, struct dccp_feat_entry, node);
+		if (feat < entry->feat_num)
+			break;
+		if (entry->feat_num = feat && entry->is_local = is_local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		}
+	}
+	entry = kmalloc(sizeof(struct dccp_feat_entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = is_local;
+		list_add_tail(&entry->node, pos_head);
+	}
+	return entry;
+}
+
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, u8 is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num = feat_num && entry->is_local = is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval = NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 04/37] dccp: Per-socket initialisation of feature negotiation
@ 2008-08-28 17:44           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 ++++
 net/dccp/dccp.h      |    3 ++-
 net/dccp/feat.c      |   19 +++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 --
 net/dccp/ipv4.c      |    3 ++-
 net/dccp/ipv6.c      |    3 ++-
 net/dccp/minisocks.c |    7 ++++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 37 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -276,6 +276,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new == NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -95,6 +95,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type == DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 04/37] dccp: Per-socket initialisation of feature negotiation
@ 2008-08-28 17:44           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 ++++
 net/dccp/dccp.h      |    3 ++-
 net/dccp/feat.c      |   19 +++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 --
 net/dccp/ipv4.c      |    3 ++-
 net/dccp/ipv6.c      |    3 ++-
 net/dccp/minisocks.c |    7 ++++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 37 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -276,6 +276,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new = NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -95,6 +95,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type = DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 05/37] dccp: Cleanup routines for feature negotiation
@ 2008-08-28 17:44             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h  |    2 ++
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 4 files changed, 5 insertions(+), 1 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 05/37] dccp: Cleanup routines for feature negotiation
@ 2008-08-28 17:44             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h  |    2 ++
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 4 files changed, 5 insertions(+), 1 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase
@ 2008-08-28 17:44               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch starts the new implementation of feature negotiation:
 1. Although it is theoretically possible to perform feature negotiation at any
    time (and RFC 4340 supports this), in practice this is prohibitively complex,
    as it requires to put traffic on hold for each new negotiation.
 2. As a byproduct of restricting feature negotiation to connection setup, the
    feature-negotiation retransmit timer is no longer required. This part is now
    mapped onto the protocol-level retransmission.
    Details indicating why timers are no longer needed can be found on
    http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
	                                      implementation_notes.html

This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |   19 ++++++++-----------
 net/dccp/options.c |   18 ------------------
 net/dccp/timer.c   |   12 ------------
 3 files changed, 8 insertions(+), 41 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -6,6 +6,8 @@
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  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.
@@ -649,6 +651,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 {
 	int rc;
 
+	/* Ignore Change requests other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* figure out if it's SP or NN feature */
@@ -698,6 +703,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 	int found = 0;
 	int all_confirmed = 1;
 
+	/* Ignore Confirm options other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* locate our change request */
@@ -732,17 +740,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			all_confirmed = 0;
 	}
 
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
 	if (!found)
 		dccp_pr_debug("%s(%d, ...) never requested\n",
 			      dccp_feat_typename(type), feature);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 
 static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct dccp_opt_pend *opt, *next;
 	int change = 0;
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 		}
 	}
 
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
 	return 0;
 }
 
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head == NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state == DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase
@ 2008-08-28 17:44               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This patch starts the new implementation of feature negotiation:
 1. Although it is theoretically possible to perform feature negotiation at any
    time (and RFC 4340 supports this), in practice this is prohibitively complex,
    as it requires to put traffic on hold for each new negotiation.
 2. As a byproduct of restricting feature negotiation to connection setup, the
    feature-negotiation retransmit timer is no longer required. This part is now
    mapped onto the protocol-level retransmission.
    Details indicating why timers are no longer needed can be found on
    http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
	                                      implementation_notes.html

This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |   19 ++++++++-----------
 net/dccp/options.c |   18 ------------------
 net/dccp/timer.c   |   12 ------------
 3 files changed, 8 insertions(+), 41 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -6,6 +6,8 @@
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  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.
@@ -649,6 +651,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 {
 	int rc;
 
+	/* Ignore Change requests other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* figure out if it's SP or NN feature */
@@ -698,6 +703,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 	int found = 0;
 	int all_confirmed = 1;
 
+	/* Ignore Confirm options other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* locate our change request */
@@ -732,17 +740,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			all_confirmed = 0;
 	}
 
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
 	if (!found)
 		dccp_pr_debug("%s(%d, ...) never requested\n",
 			      dccp_feat_typename(type), feature);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 
 static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct dccp_opt_pend *opt, *next;
 	int change = 0;
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 		}
 	}
 
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
 	return 0;
 }
 
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head = NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state = DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 07/37] dccp: Registration routines for changing feature values
@ 2008-08-28 17:44                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.

These are internal-only routines and therefore start with `__feat_register'.

It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccids/ccid2.c |    6 +-
 net/dccp/feat.c        |  123 +++++++++++++++++++++++++++++++++++++++---------
 net/dccp/feat.h        |   25 +++++++++-
 net/dccp/proto.c       |    2 +-
 4 files changed, 128 insertions(+), 28 deletions(-)

--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val == dp->dccps_l_ack_ratio)
 		return;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -297,6 +297,95 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list == NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -833,42 +922,30 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
-{
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
-
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
-	}
-	return rc;
-}
-
-int dccp_feat_init(struct dccp_minisock *dmsk)
+int dccp_feat_init(struct sock *sk)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
+				&dmsk->dccpms_tx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
+				&dmsk->dccpms_rx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dmsk->dccpms_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,15 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+/*
+ * Known limits of feature values.
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
 	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
@@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
 	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
 }
 
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -96,6 +119,6 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_init(struct sock *sk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
+		int rc = dccp_feat_init(sk);
 
 		if (rc)
 			return rc;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 07/37] dccp: Registration routines for changing feature values
@ 2008-08-28 17:44                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.

These are internal-only routines and therefore start with `__feat_register'.

It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccids/ccid2.c |    6 +-
 net/dccp/feat.c        |  123 +++++++++++++++++++++++++++++++++++++++---------
 net/dccp/feat.h        |   25 +++++++++-
 net/dccp/proto.c       |    2 +-
 4 files changed, 128 insertions(+), 28 deletions(-)

--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val = dp->dccps_l_ack_ratio)
 		return;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -297,6 +297,95 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val = DCCPC_CCID2 || val = DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list = NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) = 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -833,42 +922,30 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
-{
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
-
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
-	}
-	return rc;
-}
-
-int dccp_feat_init(struct dccp_minisock *dmsk)
+int dccp_feat_init(struct sock *sk)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
+				&dmsk->dccpms_tx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
+				&dmsk->dccpms_rx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dmsk->dccpms_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,15 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+/*
+ * Known limits of feature values.
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin2 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
 	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
@@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
 	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
 }
 
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -96,6 +119,6 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_init(struct sock *sk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
+		int rc = dccp_feat_init(sk);
 
 		if (rc)
 			return rc;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 08/37] dccp: Query supported CCIDs
@ 2008-08-28 17:44                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides a data structure to record which CCIDs are locally supported
and three accessor functions:
 - a test function for internal use which is used to validate CCID requests
   made by the user;
 - a copy function so that the list can be used for feature-negotiation;
 - documented getsockopt() support so that the user can query capabilities.

The data structure is a table which is filled in at compile-time with the
list of available CCIDs (which in turn depends on the Kconfig choices).

Using the copy function for cloning the list of supported CCIDs is useful for
feature negotiation, since the negotiation is now with the full list of available
CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
will not fail if the peer requests to use CCID3 instead of CCID2.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    4 +++
 include/linux/dccp.h              |    1 +
 net/dccp/ccid.c                   |   48 +++++++++++++++++++++++++++++++++++++
 net/dccp/ccid.h                   |    5 ++++
 net/dccp/feat.c                   |    4 +++
 net/dccp/proto.c                  |    2 +
 6 files changed, 64 insertions(+), 0 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] == builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array == NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const struct ccid *ccid)
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -380,6 +380,10 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
 		return -EINVAL;
 
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
 	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
 		return -ENOMEM;
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 08/37] dccp: Query supported CCIDs
@ 2008-08-28 17:44                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This provides a data structure to record which CCIDs are locally supported
and three accessor functions:
 - a test function for internal use which is used to validate CCID requests
   made by the user;
 - a copy function so that the list can be used for feature-negotiation;
 - documented getsockopt() support so that the user can query capabilities.

The data structure is a table which is filled in at compile-time with the
list of available CCIDs (which in turn depends on the Kconfig choices).

Using the copy function for cloning the list of supported CCIDs is useful for
feature negotiation, since the negotiation is now with the full list of available
CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
will not fail if the peer requests to use CCID3 instead of CCID2.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    4 +++
 include/linux/dccp.h              |    1 +
 net/dccp/ccid.c                   |   48 +++++++++++++++++++++++++++++++++++++
 net/dccp/ccid.h                   |    5 ++++
 net/dccp/feat.c                   |    4 +++
 net/dccp/proto.c                  |    2 +
 6 files changed, 64 insertions(+), 0 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] = builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array = NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const struct ccid *ccid)
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -380,6 +380,10 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
 		return -EINVAL;
 
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat = DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
 	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
 		return -ENOMEM;
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID
@ 2008-08-28 17:44                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides a missing link in the code chain, as several features implicitly
depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).

For Send Ack Vector, the situation is as follows:
 * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
   endpoints which use CCID2 to disable Ack Vector features such a connection;

 * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
   with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);

 * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
   negotiable. However, this implies that the code negotiating the use of Ack
   Vectors also supports it (i.e. is able to supply and to either parse or
   ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
   Vector support), the use of Ack Vectors is here disabled, with a comment
   in the source code.

An analogous consideration arises for the Send Loss Event Rate feature,
since the CCID-3 implementation does not support the loss interval options
of RFC 4342. To make such use explicit, corresponding feature-negotiation
options are inserted which signal the use of the loss event rate option,
as it is used by the CCID3 code.

Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.

The patch implements this as a function which is called after the user has
made all other registrations for changing default values of features.

The table is variable-length, the reserved (and hence for feature-negotiation
invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
is used to mark the end of the table.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |    4 +
 net/dccp/proto.c  |    3 +
 4 files changed, 168 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -438,6 +438,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table == NULL);
+
+	for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
+	return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID
@ 2008-08-28 17:44                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This provides a missing link in the code chain, as several features implicitly
depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).

For Send Ack Vector, the situation is as follows:
 * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
   endpoints which use CCID2 to disable Ack Vector features such a connection;

 * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
   with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);

 * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
   negotiable. However, this implies that the code negotiating the use of Ack
   Vectors also supports it (i.e. is able to supply and to either parse or
   ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
   Vector support), the use of Ack Vectors is here disabled, with a comment
   in the source code.

An analogous consideration arises for the Send Loss Event Rate feature,
since the CCID-3 implementation does not support the loss interval options
of RFC 4342. To make such use explicit, corresponding feature-negotiation
options are inserted which signal the use of the loss event rate option,
as it is used by the CCID3 code.

Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.

The patch implements this as a function which is called after the user has
made all other registrations for changing default values of features.

The table is variable-length, the reserved (and hence for feature-negotiation
invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
is used to mark the end of the table.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |    4 +
 net/dccp/proto.c  |    3 +
 4 files changed, 168 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -438,6 +438,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table = NULL);
+
+	for (i = 0; rc = 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) = FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
+	return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num = DCCPF_CCID && entry->val.sp.len = 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 10/37] dccp: Mechanism to resolve CCID dependencies
@ 2008-08-28 17:44                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This adds a hook to resolve features whose value depends on the choice of
CCID. It is done at the server since it can only be done after the CCID
values have been negotiated; i.e. the client will add its CCID preference
list on the Change options sent in the Request, which will be reconciled
with the local preference list of the server.

The concept is documented on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
				implementation_notes.html#ccid_dependencies

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |   25 +++++++++++++++++++++++++
 net/dccp/output.c |   13 +++++++++----
 3 files changed, 35 insertions(+), 4 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 }
 
 extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
+extern int  dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -598,6 +598,31 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	return 0;
 }
 
+/**
+ * dccp_feat_server_ccid_dependencies  -  Resolve CCID-dependent features
+ * It is the server which resolves the dependencies once the CCID has been
+ * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
+ */
+int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
+{
+	struct list_head *fn = &dreq->dreq_featneg;
+	struct dccp_feat_entry *entry;
+	u8 is_local, ccid;
+
+	for (is_local = 0; is_local <= 1; is_local++) {
+		entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
+
+		if (entry != NULL && !entry->empty_confirm)
+			ccid = entry->val.sp.vec[0];
+		else
+			ccid = dccp_feat_default_value(DCCPF_CCID);
+
+		if (dccp_feat_propagate_ccid(fn, ccid, is_local))
+			return -1;
+	}
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -339,10 +339,12 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
 
-	if (dccp_insert_options_rsk(dreq, skb)) {
-		kfree_skb(skb);
-		return NULL;
-	}
+	/* Resolve feature dependencies resulting from choice of CCID */
+	if (dccp_feat_server_ccid_dependencies(dreq))
+		goto response_failed;
+
+	if (dccp_insert_options_rsk(dreq, skb))
+		goto response_failed;
 
 	/* Build and checksum header */
 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
@@ -363,6 +365,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	inet_rsk(req)->acked = 1;
 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 	return skb;
+response_failed:
+	kfree_skb(skb);
+	return NULL;
 }
 
 EXPORT_SYMBOL_GPL(dccp_make_response);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 10/37] dccp: Mechanism to resolve CCID dependencies
@ 2008-08-28 17:44                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This adds a hook to resolve features whose value depends on the choice of
CCID. It is done at the server since it can only be done after the CCID
values have been negotiated; i.e. the client will add its CCID preference
list on the Change options sent in the Request, which will be reconciled
with the local preference list of the server.

The concept is documented on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
				implementation_notes.html#ccid_dependencies

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |   25 +++++++++++++++++++++++++
 net/dccp/output.c |   13 +++++++++----
 3 files changed, 35 insertions(+), 4 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 }
 
 extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
+extern int  dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -598,6 +598,31 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	return 0;
 }
 
+/**
+ * dccp_feat_server_ccid_dependencies  -  Resolve CCID-dependent features
+ * It is the server which resolves the dependencies once the CCID has been
+ * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
+ */
+int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
+{
+	struct list_head *fn = &dreq->dreq_featneg;
+	struct dccp_feat_entry *entry;
+	u8 is_local, ccid;
+
+	for (is_local = 0; is_local <= 1; is_local++) {
+		entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
+
+		if (entry != NULL && !entry->empty_confirm)
+			ccid = entry->val.sp.vec[0];
+		else
+			ccid = dccp_feat_default_value(DCCPF_CCID);
+
+		if (dccp_feat_propagate_ccid(fn, ccid, is_local))
+			return -1;
+	}
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -339,10 +339,12 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
 
-	if (dccp_insert_options_rsk(dreq, skb)) {
-		kfree_skb(skb);
-		return NULL;
-	}
+	/* Resolve feature dependencies resulting from choice of CCID */
+	if (dccp_feat_server_ccid_dependencies(dreq))
+		goto response_failed;
+
+	if (dccp_insert_options_rsk(dreq, skb))
+		goto response_failed;
 
 	/* Build and checksum header */
 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
@@ -363,6 +365,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	inet_rsk(req)->acked = 1;
 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 	return skb;
+response_failed:
+	kfree_skb(skb);
+	return NULL;
 }
 
 EXPORT_SYMBOL_GPL(dccp_make_response);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 11/37] dccp: Deprecate old setsockopt framework
@ 2008-08-28 17:44                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

The previous setsockopt interface, which passed socket options via struct
dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
ugly code since the old approach did not distinguish between NN and SP values.

This patch removes the old setsockopt interface and replaces it with two new
functions to register NN/SP values for feature negotiation. These are
essentially wrappers around the internal __feat_register functions, with
checking added to avoid
 * wrong usage (type);
 * changing values while the connection is in progress.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 include/linux/dccp.h |    7 -----
 net/dccp/feat.c      |   72 ++++++++++++++++++-------------------------------
 net/dccp/feat.h      |    5 ++-
 net/dccp/proto.c     |   53 +-----------------------------------
 4 files changed, 32 insertions(+), 105 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -193,13 +193,6 @@ enum dccp_feature_numbers {
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
-/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
-struct dccp_so_feat {
-	__u8 dccpsf_feat;
-	__u8 __user *dccpsf_val;
-	__u8 dccpsf_len;
-};
-
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE	1 /* XXX deprecated, without effect */
 #define DCCP_SOCKOPT_SERVICE		2
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -390,53 +390,35 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
 }
 
-int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-		     u8 *val, u8 len, gfp_t gfp)
-{
-	struct dccp_opt_pend *opt;
-
-	dccp_feat_debug(type, feature, *val);
-
-	if (len > 3) {
-		DCCP_WARN("invalid length %d\n", len);
+/**
+ * dccp_feat_register_sp  -  Register requests to change SP feature values
+ * @sk: client or listening socket
+ * @feat: one of %dccp_feature_numbers
+ * @is_local: whether the local (1) or remote (0) @feat is meant
+ * @list: array of preferred values, in descending order of preference
+ * @len: length of @list in bytes
+ */
+int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+			  u8 const *list, u8 len)
+{	 /* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_SP)
 		return -EINVAL;
-	}
-	/* XXX add further sanity checks */
-
-	/* check if that feature is already being negotiated */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* ok we found a negotiation for this option already */
-		if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
-			dccp_pr_debug("Replacing old\n");
-			/* replace */
-			BUG_ON(opt->dccpop_val == NULL);
-			kfree(opt->dccpop_val);
-			opt->dccpop_val	 = val;
-			opt->dccpop_len	 = len;
-			opt->dccpop_conf = 0;
-			return 0;
-		}
-	}
-
-	/* negotiation for a new feature */
-	opt = kmalloc(sizeof(*opt), gfp);
-	if (opt == NULL)
-		return -ENOMEM;
-
-	opt->dccpop_type = type;
-	opt->dccpop_feat = feature;
-	opt->dccpop_len	 = len;
-	opt->dccpop_val	 = val;
-	opt->dccpop_conf = 0;
-	opt->dccpop_sc	 = NULL;
-
-	BUG_ON(opt->dccpop_val == NULL);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
-	return 0;
+	return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
+				  0, list, len);
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_change);
+/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
+int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
+{
+	/* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_NN)
+		return -EINVAL;
+	return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
+}
 
 /*
  *	Tracking features whose value depend on the choice of CCID
@@ -1134,7 +1116,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dmsk->dccpms_ack_ratio);
+				dp->dccps_l_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -110,8 +110,9 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
-extern int  dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-			     u8 *val, u8 len, gfp_t gfp);
+extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+				  u8 const *list, u8 len);
+extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
 				  u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,44 +470,6 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
-/* byte 1 is feature.  the rest is the preference list */
-static int dccp_setsockopt_change(struct sock *sk, int type,
-				  struct dccp_so_feat __user *optval)
-{
-	struct dccp_so_feat opt;
-	u8 *val;
-	int rc;
-
-	if (copy_from_user(&opt, optval, sizeof(opt)))
-		return -EFAULT;
-	/*
-	 * rfc4340: 6.1. Change Options
-	 */
-	if (opt.dccpsf_len < 1)
-		return -EINVAL;
-
-	val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
-	if (!val)
-		return -ENOMEM;
-
-	if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
-		rc = -EFAULT;
-		goto out_free_val;
-	}
-
-	rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
-			      val, opt.dccpsf_len, GFP_KERNEL);
-	if (rc)
-		goto out_free_val;
-
-out:
-	return rc;
-
-out_free_val:
-	kfree(val);
-	goto out;
-}
-
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -530,20 +492,9 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = 0;
 		break;
 	case DCCP_SOCKOPT_CHANGE_L:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
-						     (struct dccp_so_feat __user *)
-						     optval);
-		break;
 	case DCCP_SOCKOPT_CHANGE_R:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
-						     (struct dccp_so_feat __user *)
-						     optval);
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		err = 0;
 		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 11/37] dccp: Deprecate old setsockopt framework
@ 2008-08-28 17:44                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

The previous setsockopt interface, which passed socket options via struct
dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
ugly code since the old approach did not distinguish between NN and SP values.

This patch removes the old setsockopt interface and replaces it with two new
functions to register NN/SP values for feature negotiation. These are
essentially wrappers around the internal __feat_register functions, with
checking added to avoid
 * wrong usage (type);
 * changing values while the connection is in progress.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 include/linux/dccp.h |    7 -----
 net/dccp/feat.c      |   72 ++++++++++++++++++-------------------------------
 net/dccp/feat.h      |    5 ++-
 net/dccp/proto.c     |   53 +-----------------------------------
 4 files changed, 32 insertions(+), 105 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -193,13 +193,6 @@ enum dccp_feature_numbers {
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
-/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
-struct dccp_so_feat {
-	__u8 dccpsf_feat;
-	__u8 __user *dccpsf_val;
-	__u8 dccpsf_len;
-};
-
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE	1 /* XXX deprecated, without effect */
 #define DCCP_SOCKOPT_SERVICE		2
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -390,53 +390,35 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
 }
 
-int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-		     u8 *val, u8 len, gfp_t gfp)
-{
-	struct dccp_opt_pend *opt;
-
-	dccp_feat_debug(type, feature, *val);
-
-	if (len > 3) {
-		DCCP_WARN("invalid length %d\n", len);
+/**
+ * dccp_feat_register_sp  -  Register requests to change SP feature values
+ * @sk: client or listening socket
+ * @feat: one of %dccp_feature_numbers
+ * @is_local: whether the local (1) or remote (0) @feat is meant
+ * @list: array of preferred values, in descending order of preference
+ * @len: length of @list in bytes
+ */
+int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+			  u8 const *list, u8 len)
+{	 /* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_SP)
 		return -EINVAL;
-	}
-	/* XXX add further sanity checks */
-
-	/* check if that feature is already being negotiated */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* ok we found a negotiation for this option already */
-		if (opt->dccpop_feat = feature && opt->dccpop_type = type) {
-			dccp_pr_debug("Replacing old\n");
-			/* replace */
-			BUG_ON(opt->dccpop_val = NULL);
-			kfree(opt->dccpop_val);
-			opt->dccpop_val	 = val;
-			opt->dccpop_len	 = len;
-			opt->dccpop_conf = 0;
-			return 0;
-		}
-	}
-
-	/* negotiation for a new feature */
-	opt = kmalloc(sizeof(*opt), gfp);
-	if (opt = NULL)
-		return -ENOMEM;
-
-	opt->dccpop_type = type;
-	opt->dccpop_feat = feature;
-	opt->dccpop_len	 = len;
-	opt->dccpop_val	 = val;
-	opt->dccpop_conf = 0;
-	opt->dccpop_sc	 = NULL;
-
-	BUG_ON(opt->dccpop_val = NULL);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
-	return 0;
+	return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
+				  0, list, len);
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_change);
+/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
+int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
+{
+	/* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_NN)
+		return -EINVAL;
+	return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
+}
 
 /*
  *	Tracking features whose value depend on the choice of CCID
@@ -1134,7 +1116,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dmsk->dccpms_ack_ratio);
+				dp->dccps_l_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -110,8 +110,9 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
-extern int  dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-			     u8 *val, u8 len, gfp_t gfp);
+extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+				  u8 const *list, u8 len);
+extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
 				  u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,44 +470,6 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
-/* byte 1 is feature.  the rest is the preference list */
-static int dccp_setsockopt_change(struct sock *sk, int type,
-				  struct dccp_so_feat __user *optval)
-{
-	struct dccp_so_feat opt;
-	u8 *val;
-	int rc;
-
-	if (copy_from_user(&opt, optval, sizeof(opt)))
-		return -EFAULT;
-	/*
-	 * rfc4340: 6.1. Change Options
-	 */
-	if (opt.dccpsf_len < 1)
-		return -EINVAL;
-
-	val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
-	if (!val)
-		return -ENOMEM;
-
-	if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
-		rc = -EFAULT;
-		goto out_free_val;
-	}
-
-	rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
-			      val, opt.dccpsf_len, GFP_KERNEL);
-	if (rc)
-		goto out_free_val;
-
-out:
-	return rc;
-
-out_free_val:
-	kfree(val);
-	goto out;
-}
-
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -530,20 +492,9 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = 0;
 		break;
 	case DCCP_SOCKOPT_CHANGE_L:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
-						     (struct dccp_so_feat __user *)
-						     optval);
-		break;
 	case DCCP_SOCKOPT_CHANGE_R:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
-						     (struct dccp_so_feat __user *)
-						     optval);
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		err = 0;
 		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage
@ 2008-08-28 17:44                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +-
 net/dccp/proto.c     |   52 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 41 insertions(+), 15 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,6 +470,41 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
+{
+	u8 *list, len;
+	int i, rc;
+
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
+
+	if (rx)
+		dccp_sk(sk)->dccps_pcrlen = cscov;
+	else
+		dccp_sk(sk)->dccps_pcslen = cscov;
+	/*
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
+	 */
+	if (cscov == 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list == NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	kfree(list);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -502,20 +537,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage
@ 2008-08-28 17:44                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +-
 net/dccp/proto.c     |   52 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 41 insertions(+), 15 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,6 +470,41 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
+{
+	u8 *list, len;
+	int i, rc;
+
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
+
+	if (rx)
+		dccp_sk(sk)->dccps_pcrlen = cscov;
+	else
+		dccp_sk(sk)->dccps_pcslen = cscov;
+	/*
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
+	 */
+	if (cscov = 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list = NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	kfree(list);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -502,20 +537,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 13/37] dccp: Deprecate Ack Ratio sysctl
@ 2008-08-28 17:44                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch deprecates the Ack Ratio sysctl, since
 * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
 * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
 * even if it would work in CCID-2, there is no point for a user to change it:
   - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
   - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
     (since waiting for Acks which will never arrive in this window),
   - cwnd is not a user-configurable value.

The only reasonable place for Ack Ratio is to print it for debugging. It is
planned to do this later on, as part of e.g. dccp_probe.

With this patch Ack Ratio is now under full control of feature negotiation:
 * Ack Ratio is resolved as a dependency of the selected CCID;
 * if the chosen CCID supports it (i.e. CCID == CCID-2), Ack Ratio is set to
   the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
   Ratio 2 for both endpoints";
 * what happens then is part of another patch set, since it concerns the
   dynamic update of Ack Ratio while the connection is in full flight.

Thanks to Tomasz Grobelny for discussion leading up to this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    2 --
 net/dccp/dccp.h                   |    1 -
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    1 -
 net/dccp/sysctl.c                 |    7 -------
 6 files changed, 0 insertions(+), 15 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -125,9 +125,6 @@ send_ndp = 1
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
-ack_ratio = 2
-	The default Ack Ratio (sec. 11.3) to use.
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection.
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -368,7 +368,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
-  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
@@ -378,7 +377,6 @@ struct dccp_minisock {
 	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
-	__u8			dccpms_ack_ratio;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_ack_ratio;
 extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -47,7 +47,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
 	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
-	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "ack_ratio",
-		.data		= &sysctl_dccp_feat_ack_ratio,
-		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "send_ackvec",
 		.data		= &sysctl_dccp_feat_send_ack_vector,
 		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 13/37] dccp: Deprecate Ack Ratio sysctl
@ 2008-08-28 17:44                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This patch deprecates the Ack Ratio sysctl, since
 * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
 * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
 * even if it would work in CCID-2, there is no point for a user to change it:
   - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
   - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
     (since waiting for Acks which will never arrive in this window),
   - cwnd is not a user-configurable value.

The only reasonable place for Ack Ratio is to print it for debugging. It is
planned to do this later on, as part of e.g. dccp_probe.

With this patch Ack Ratio is now under full control of feature negotiation:
 * Ack Ratio is resolved as a dependency of the selected CCID;
 * if the chosen CCID supports it (i.e. CCID = CCID-2), Ack Ratio is set to
   the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
   Ratio 2 for both endpoints";
 * what happens then is part of another patch set, since it concerns the
   dynamic update of Ack Ratio while the connection is in full flight.

Thanks to Tomasz Grobelny for discussion leading up to this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    2 --
 net/dccp/dccp.h                   |    1 -
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    1 -
 net/dccp/sysctl.c                 |    7 -------
 6 files changed, 0 insertions(+), 15 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -125,9 +125,6 @@ send_ndp = 1
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
-ack_ratio = 2
-	The default Ack Ratio (sec. 11.3) to use.
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection.
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -368,7 +368,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
-  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
@@ -378,7 +377,6 @@ struct dccp_minisock {
 	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
-	__u8			dccpms_ack_ratio;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_ack_ratio;
 extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -47,7 +47,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
 	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
-	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "ack_ratio",
-		.data		= &sysctl_dccp_feat_ack_ratio,
-		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "send_ackvec",
 		.data		= &sysctl_dccp_feat_send_ack_vector,
 		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 14/37] dccp: Tidy up setsockopt calls
@ 2008-08-28 17:44                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This splits the setsockopt calls into two groups, depending on whether an
integer argument (val) is required and whether routines being called do
their own locking.

Some options (such as setting the CCID) use u8 rather than int, so that for
these the test with regard to integer-sizeof can not be used.

The second switch-case statement now only has those statements which need
locking and which make use of `val'.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/proto.c |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -511,26 +511,27 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
-		return -EINVAL;
-
-	if (get_user(val, (int __user *)optval))
-		return -EFAULT;
-
-	if (optname == DCCP_SOCKOPT_SERVICE)
-		return dccp_setsockopt_service(sk, val, optval, optlen);
-
-	lock_sock(sk);
 	switch (optname) {
 	case DCCP_SOCKOPT_PACKET_SIZE:
 		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
+		return 0;
 	case DCCP_SOCKOPT_CHANGE_L:
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
-		err = 0;
-		break;
+		return 0;
+	default:
+		if (optlen < sizeof(int))
+			return -EINVAL;
+
+		if (get_user(val, (int __user *)optval))
+			return -EFAULT;
+
+		if (optname == DCCP_SOCKOPT_SERVICE)
+			return dccp_setsockopt_service(sk, val, optval, optlen);
+	}
+
+	lock_sock(sk);
+	switch (optname) {
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
@@ -547,8 +548,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 14/37] dccp: Tidy up setsockopt calls
@ 2008-08-28 17:44                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This splits the setsockopt calls into two groups, depending on whether an
integer argument (val) is required and whether routines being called do
their own locking.

Some options (such as setting the CCID) use u8 rather than int, so that for
these the test with regard to integer-sizeof can not be used.

The second switch-case statement now only has those statements which need
locking and which make use of `val'.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/proto.c |   31 ++++++++++++++++---------------
 1 files changed, 16 insertions(+), 15 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -511,26 +511,27 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
-		return -EINVAL;
-
-	if (get_user(val, (int __user *)optval))
-		return -EFAULT;
-
-	if (optname = DCCP_SOCKOPT_SERVICE)
-		return dccp_setsockopt_service(sk, val, optval, optlen);
-
-	lock_sock(sk);
 	switch (optname) {
 	case DCCP_SOCKOPT_PACKET_SIZE:
 		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
+		return 0;
 	case DCCP_SOCKOPT_CHANGE_L:
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
-		err = 0;
-		break;
+		return 0;
+	default:
+		if (optlen < sizeof(int))
+			return -EINVAL;
+
+		if (get_user(val, (int __user *)optval))
+			return -EFAULT;
+
+		if (optname = DCCP_SOCKOPT_SERVICE)
+			return dccp_setsockopt_service(sk, val, optval, optlen);
+	}
+
+	lock_sock(sk);
+	switch (optname) {
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
@@ -547,8 +548,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
@ 2008-08-28 17:44                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
overrides the defaults set by the global sysctl variables for TX/RX CCIDs.

To make full use of this facility, the remaining patches of this patch set are
needed, which track dependencies and activate negotiated feature values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |   14 ++++++++++++++
 include/linux/dccp.h              |    5 +++++
 net/dccp/proto.c                  |   32 ++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 0 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
 supported by the endpoint (see include/linux/dccp.h for symbolic constants).
 The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
 
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -203,11 +203,16 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
+/* maximum number of CCID preferences that can be registered at one time */
+#define DCCP_CCID_LIST_MAX_LEN	       16
 
 #ifdef __KERNEL__
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -505,6 +505,34 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 	return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
+		return -EINVAL;
+
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(val, optval, optlen))
+		rc = -EFAULT;
+
+	lock_sock(sk);
+	if (!rc && (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
+
+	kfree(val);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -519,6 +547,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
 		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
 	default:
 		if (optlen < sizeof(int))
 			return -EINVAL;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
@ 2008-08-28 17:44                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
overrides the defaults set by the global sysctl variables for TX/RX CCIDs.

To make full use of this facility, the remaining patches of this patch set are
needed, which track dependencies and activate negotiated feature values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |   14 ++++++++++++++
 include/linux/dccp.h              |    5 +++++
 net/dccp/proto.c                  |   32 ++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 0 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
 supported by the endpoint (see include/linux/dccp.h for symbolic constants).
 The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
 
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -203,11 +203,16 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
+/* maximum number of CCID preferences that can be registered at one time */
+#define DCCP_CCID_LIST_MAX_LEN	       16
 
 #ifdef __KERNEL__
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -505,6 +505,34 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 	return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
+		return -EINVAL;
+
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val = NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(val, optval, optlen))
+		rc = -EFAULT;
+
+	lock_sock(sk);
+	if (!rc && (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+	if (!rc && (type = DCCP_SOCKOPT_RX_CCID || type = DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
+
+	kfree(val);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -519,6 +547,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
 		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
 	default:
 		if (optlen < sizeof(int))
 			return -EINVAL;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 16/37] dccp: API to query the current TX/RX CCID
@ 2008-08-28 17:44                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides function to query the current TX/RX CCID dynamically, without
reliance on the minisock value, using dynamic information available in the
currently loaded CCID module.

This query function is then used to
 (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
 (b) replace the current test for "which CCID is in use" in probe.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h  |    9 +++++++++
 net/dccp/probe.c |    7 ++-----
 net/dccp/proto.c |    6 ++++++
 3 files changed, 17 insertions(+), 5 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -116,6 +116,15 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
 extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
 				   gfp_t gfp);
 
+static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
+{
+	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
 
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
+	if (ccid_get_current_id(dccp_sk(sk), false) == DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port == 0 || ntohs(inet->dport) == port ||
 	    ntohs(inet->sport) == port) {
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -664,6 +664,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 		break;
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_id(dp, optname == DCCP_SOCKOPT_RX_CCID);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 16/37] dccp: API to query the current TX/RX CCID
@ 2008-08-28 17:44                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This provides function to query the current TX/RX CCID dynamically, without
reliance on the minisock value, using dynamic information available in the
currently loaded CCID module.

This query function is then used to
 (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
 (b) replace the current test for "which CCID is in use" in probe.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h  |    9 +++++++++
 net/dccp/probe.c |    7 ++-----
 net/dccp/proto.c |    6 ++++++
 3 files changed, 17 insertions(+), 5 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -116,6 +116,15 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
 extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
 				   gfp_t gfp);
 
+static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
+{
+	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
+
+	if (ccid = NULL || ccid->ccid_ops = NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
 
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid = DCCPC_CCID3)
+	if (ccid_get_current_id(dccp_sk(sk), false) = DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port = 0 || ntohs(inet->dport) = port ||
 	    ntohs(inet->sport) = port) {
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -664,6 +664,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 		break;
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_id(dp, optname = DCCP_SOCKOPT_RX_CCID);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 17/37] dccp: Increase the scope of variable-length htonl/ntohl functions
@ 2008-08-28 17:44                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This extends the scope of two available functions, encode|decode_value_var,
to work up to 6 (8) bytes, to match maximum requirements in the RFC.

These functions are going to be used both by general option processing and
feature negotiation code, hence declarations have been put into feat.h.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |   14 ++++++++++++++
 net/dccp/options.c |   21 ++++++++++++++-------
 2 files changed, 28 insertions(+), 7 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -122,4 +122,18 @@ extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
+/*
+ * Encoding variable-length options and their maximum length.
+ *
+ * This affects NN options (SP options are all u8) and other variable-length
+ * options (see table 3 in RFC 4340). The limit is currently given the Sequence
+ * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
+ * options consume less than 6 bytes (timestamps are 4 bytes).
+ * When updating this constant (e.g. due to new internet drafts / RFCs), make
+ * sure that you also update all code which refers to it.
+ */
+#define DCCP_OPTVAL_MAXLEN	6
+
+extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
+extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -29,16 +29,20 @@ int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
+u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
-	u32 value = 0;
+	u64 value = 0;
 
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		value += ((u64)*bf++) << 40;
+	if (len > 4)
+		value += ((u64)*bf++) << 32;
 	if (len > 3)
-		value += *bf++ << 24;
+		value += ((u64)*bf++) << 24;
 	if (len > 2)
-		value += *bf++ << 16;
+		value += ((u64)*bf++) << 16;
 	if (len > 1)
-		value += *bf++ << 8;
+		value += ((u64)*bf++) << 8;
 	if (len > 0)
 		value += *bf;
 
@@ -298,9 +302,12 @@ out_invalid_option:
 
 EXPORT_SYMBOL_GPL(dccp_parse_options);
 
-static void dccp_encode_value_var(const u32 value, unsigned char *to,
-				  const unsigned int len)
+void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
 {
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		*to++ = (value & 0xFF0000000000ull) >> 40;
+	if (len > 4)
+		*to++ = (value & 0xFF00000000ull) >> 32;
 	if (len > 3)
 		*to++ = (value & 0xFF000000) >> 24;
 	if (len > 2)
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 17/37] dccp: Increase the scope of variable-length htonl/ntohl functions
@ 2008-08-28 17:44                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This extends the scope of two available functions, encode|decode_value_var,
to work up to 6 (8) bytes, to match maximum requirements in the RFC.

These functions are going to be used both by general option processing and
feature negotiation code, hence declarations have been put into feat.h.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |   14 ++++++++++++++
 net/dccp/options.c |   21 ++++++++++++++-------
 2 files changed, 28 insertions(+), 7 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -122,4 +122,18 @@ extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
+/*
+ * Encoding variable-length options and their maximum length.
+ *
+ * This affects NN options (SP options are all u8) and other variable-length
+ * options (see table 3 in RFC 4340). The limit is currently given the Sequence
+ * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
+ * options consume less than 6 bytes (timestamps are 4 bytes).
+ * When updating this constant (e.g. due to new internet drafts / RFCs), make
+ * sure that you also update all code which refers to it.
+ */
+#define DCCP_OPTVAL_MAXLEN	6
+
+extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
+extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -29,16 +29,20 @@ int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
+u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
-	u32 value = 0;
+	u64 value = 0;
 
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		value += ((u64)*bf++) << 40;
+	if (len > 4)
+		value += ((u64)*bf++) << 32;
 	if (len > 3)
-		value += *bf++ << 24;
+		value += ((u64)*bf++) << 24;
 	if (len > 2)
-		value += *bf++ << 16;
+		value += ((u64)*bf++) << 16;
 	if (len > 1)
-		value += *bf++ << 8;
+		value += ((u64)*bf++) << 8;
 	if (len > 0)
 		value += *bf;
 
@@ -298,9 +302,12 @@ out_invalid_option:
 
 EXPORT_SYMBOL_GPL(dccp_parse_options);
 
-static void dccp_encode_value_var(const u32 value, unsigned char *to,
-				  const unsigned int len)
+void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
 {
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		*to++ = (value & 0xFF0000000000ull) >> 40;
+	if (len > 4)
+		*to++ = (value & 0xFF00000000ull) >> 32;
 	if (len > 3)
 		*to++ = (value & 0xFF000000) >> 24;
 	if (len > 2)
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 18/37] dccp: Support for Mandatory options
@ 2008-08-28 17:44                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

Support for Mandatory options is provided by this patch, which will
be used by subsequent feature-negotiation patches.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |    2 ++
 net/dccp/options.c |   15 +++++++++++++++
 2 files changed, 17 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -136,4 +136,6 @@ extern int  dccp_feat_init(struct sock *sk);
 
 extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
+
+extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -467,6 +467,21 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
 	return 0;
 }
 
+/**
+ * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
+ * Note that since we are using skb_push, this function needs to be called
+ * _after_ inserting the option it is supposed to influence (stack order).
+ */
+int dccp_insert_option_mandatory(struct sk_buff *skb)
+{
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
+		return -1;
+
+	DCCP_SKB_CB(skb)->dccpd_opt_len++;
+	*skb_push(skb, 1) = DCCPO_MANDATORY;
+	return 0;
+}
+
 static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 				u8 *val, u8 len)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 18/37] dccp: Support for Mandatory options
@ 2008-08-28 17:44                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

Support for Mandatory options is provided by this patch, which will
be used by subsequent feature-negotiation patches.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |    2 ++
 net/dccp/options.c |   15 +++++++++++++++
 2 files changed, 17 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -136,4 +136,6 @@ extern int  dccp_feat_init(struct sock *sk);
 
 extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
+
+extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -467,6 +467,21 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
 	return 0;
 }
 
+/**
+ * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
+ * Note that since we are using skb_push, this function needs to be called
+ * _after_ inserting the option it is supposed to influence (stack order).
+ */
+int dccp_insert_option_mandatory(struct sk_buff *skb)
+{
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
+		return -1;
+
+	DCCP_SKB_CB(skb)->dccpd_opt_len++;
+	*skb_push(skb, 1) = DCCPO_MANDATORY;
+	return 0;
+}
+
 static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 				u8 *val, u8 len)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
@ 2008-08-28 17:44                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

The patch extends existing code:
 * Confirm options divide into the confirmed value plus an optional preference
   list for SP values. Previously only the preference list was echoed for SP
   values, now the confirmed value is added as per RFC 4340, 6.1;
 * length and sanity checks are added to avoid illegal memory (or NULL) access;
 * clarified the use of TLV length constant, which does not have anything to do
   with ECN, but with the fact that Type-Length-Value options whose length is
   determined by an u8 field provide Value space for at most 255 - 2 = 253 bytes
   due to the Type/Length fields.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ackvec.c  |    8 ++--
 net/dccp/ackvec.h  |    6 ++--
 net/dccp/feat.h    |    2 +
 net/dccp/options.c |   91 ++++++++++++++++++----------------------------------
 4 files changed, 40 insertions(+), 67 deletions(-)

--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -68,7 +68,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +100,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +432,7 @@ found:
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -16,10 +16,10 @@
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
+/* maximum size of a single TLV-encoded option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -138,4 +138,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 
 extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
+extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+			       u8 *val, u8 len, bool repeat_first);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb)
 	return 0;
 }
 
-static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
-				u8 *val, u8 len)
+/**
+ * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
+ * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
+ * @feat: one out of %dccp_feature_numbers
+ * @val: NN value or SP array (preferred element first) to copy
+ * @len: true length of @val in bytes (excluding first element repetition)
+ * @repeat_first: whether to copy the first element of @val twice
+ * The last argument is used to construct Confirm options, where the preferred
+ * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
+ * lists are kept such that the preferred entry is always first, so we only need
+ * to copy twice, and avoid the overhead of cloning into a bigger array.
+ */
+int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+		       u8 *val, u8 len, bool repeat_first)
 {
-	u8 *to;
+	u8 tot_len, *to;
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
-		DCCP_WARN("packet too small for feature %d option!\n", feat);
+	/* take the `Feature' field and possible repetition into account */
+	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
+		DCCP_WARN("length %u for feature %u too large\n", len, feat);
 		return -1;
 	}
 
-	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+	if (unlikely(val == NULL || len == 0))
+		len = repeat_first = 0;
+	tot_len = 3 + repeat_first + len;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
+		DCCP_WARN("packet too small for feature %d option!\n", feat);
+		return -1;
+	}
+	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
 
-	to    = skb_push(skb, len + 3);
+	to    = skb_push(skb, tot_len);
 	*to++ = type;
-	*to++ = len + 3;
+	*to++ = tot_len;
 	*to++ = feat;
 
+	if (repeat_first)
+		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
 
@@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 	return 0;
 }
 
-static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt, *next;
-	int change = 0;
-
-	/* confirm any options [NN opts] */
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		dccp_insert_feat_opt(skb, opt->dccpop_type,
-				     opt->dccpop_feat, opt->dccpop_val,
-				     opt->dccpop_len);
-		/* fear empty confirms */
-		if (opt->dccpop_val)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-
-	/* see which features we need to send */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* see if we need to send any confirm */
-		if (opt->dccpop_sc) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
-					     opt->dccpop_feat,
-					     opt->dccpop_sc->dccpoc_val,
-					     opt->dccpop_sc->dccpoc_len);
-
-			BUG_ON(!opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-			opt->dccpop_sc = NULL;
-		}
-
-		/* any option not confirmed, re-send it */
-		if (!opt->dccpop_conf) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type,
-					     opt->dccpop_feat, opt->dccpop_val,
-					     opt->dccpop_len);
-			change++;
-		}
-	}
-
-	return 0;
-}
-
 /* The length of all options needs to be a multiple of 4 (5.8) */
 static void dccp_insert_option_padding(struct sk_buff *skb)
 {
@@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/* Feature negotiation */
-	/* Data packets can't do feat negotiation */
-	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
-	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
-	    dccp_insert_options_feat(sk, skb))
-		return -1;
-
 	/*
 	 * Obtain RTT sample from Request/Response exchange.
 	 * This is currently used in CCID 3 initialisation.
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
@ 2008-08-28 17:44                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

The patch extends existing code:
 * Confirm options divide into the confirmed value plus an optional preference
   list for SP values. Previously only the preference list was echoed for SP
   values, now the confirmed value is added as per RFC 4340, 6.1;
 * length and sanity checks are added to avoid illegal memory (or NULL) access;
 * clarified the use of TLV length constant, which does not have anything to do
   with ECN, but with the fact that Type-Length-Value options whose length is
   determined by an u8 field provide Value space for at most 255 - 2 = 253 bytes
   due to the Type/Length fields.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ackvec.c  |    8 ++--
 net/dccp/ackvec.h  |    6 ++--
 net/dccp/feat.h    |    2 +
 net/dccp/options.c |   91 ++++++++++++++++++----------------------------------
 4 files changed, 40 insertions(+), 67 deletions(-)

--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -68,7 +68,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +100,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +432,7 @@ found:
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -16,10 +16,10 @@
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
+/* maximum size of a single TLV-encoded option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -138,4 +138,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 
 extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
+extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+			       u8 *val, u8 len, bool repeat_first);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb)
 	return 0;
 }
 
-static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
-				u8 *val, u8 len)
+/**
+ * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
+ * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
+ * @feat: one out of %dccp_feature_numbers
+ * @val: NN value or SP array (preferred element first) to copy
+ * @len: true length of @val in bytes (excluding first element repetition)
+ * @repeat_first: whether to copy the first element of @val twice
+ * The last argument is used to construct Confirm options, where the preferred
+ * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
+ * lists are kept such that the preferred entry is always first, so we only need
+ * to copy twice, and avoid the overhead of cloning into a bigger array.
+ */
+int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+		       u8 *val, u8 len, bool repeat_first)
 {
-	u8 *to;
+	u8 tot_len, *to;
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
-		DCCP_WARN("packet too small for feature %d option!\n", feat);
+	/* take the `Feature' field and possible repetition into account */
+	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
+		DCCP_WARN("length %u for feature %u too large\n", len, feat);
 		return -1;
 	}
 
-	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+	if (unlikely(val = NULL || len = 0))
+		len = repeat_first = 0;
+	tot_len = 3 + repeat_first + len;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
+		DCCP_WARN("packet too small for feature %d option!\n", feat);
+		return -1;
+	}
+	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
 
-	to    = skb_push(skb, len + 3);
+	to    = skb_push(skb, tot_len);
 	*to++ = type;
-	*to++ = len + 3;
+	*to++ = tot_len;
 	*to++ = feat;
 
+	if (repeat_first)
+		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
 
@@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 	return 0;
 }
 
-static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt, *next;
-	int change = 0;
-
-	/* confirm any options [NN opts] */
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		dccp_insert_feat_opt(skb, opt->dccpop_type,
-				     opt->dccpop_feat, opt->dccpop_val,
-				     opt->dccpop_len);
-		/* fear empty confirms */
-		if (opt->dccpop_val)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-
-	/* see which features we need to send */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* see if we need to send any confirm */
-		if (opt->dccpop_sc) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
-					     opt->dccpop_feat,
-					     opt->dccpop_sc->dccpoc_val,
-					     opt->dccpop_sc->dccpoc_len);
-
-			BUG_ON(!opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-			opt->dccpop_sc = NULL;
-		}
-
-		/* any option not confirmed, re-send it */
-		if (!opt->dccpop_conf) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type,
-					     opt->dccpop_feat, opt->dccpop_val,
-					     opt->dccpop_len);
-			change++;
-		}
-	}
-
-	return 0;
-}
-
 /* The length of all options needs to be a multiple of 4 (5.8) */
 static void dccp_insert_option_padding(struct sk_buff *skb)
 {
@@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/* Feature negotiation */
-	/* Data packets can't do feat negotiation */
-	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
-	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
-	    dccp_insert_options_feat(sk, skb))
-		return -1;
-
 	/*
 	 * Obtain RTT sample from Request/Response exchange.
 	 * This is currently used in CCID 3 initialisation.
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 20/37] dccp: Insert feature-negotiation options into skb
@ 2008-08-28 17:44                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch replaces the earlier insertion routine from options.c, so that
code specific to feature negotiation can remain in feat.c. This is possible
by calling a function already existing in options.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 
 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*,
+				  struct sk_buff *skb);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -297,6 +297,20 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+/**
+ * dccp_feat_valid_nn_length  -  Enforce length constraints on NN options
+ * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only,
+ * incoming options are accepted as long as their values are valid.
+ */
+static u8 dccp_feat_valid_nn_length(u8 feat_num)
+{
+	if (feat_num == DCCPF_ACK_RATIO)	/* RFC 4340, 11.3 and 6.6.8 */
+		return 2;
+	if (feat_num == DCCPF_SEQUENCE_WINDOW)	/* RFC 4340, 7.5.2 and 6.5  */
+		return 6;
+	return 0;
+}
+
 static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
 {
 	switch (feat_num) {
@@ -339,6 +353,57 @@ static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
 }
 
 /**
+ * dccp_feat_insert_opts  -  Generate FN options from current list state
+ * @skb: next sk_buff to be sent to the peer
+ * @dp: for client during handshake and general negotiation
+ * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND)
+ */
+int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
+			  struct sk_buff *skb)
+{
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	struct dccp_feat_entry *pos, *next;
+	u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN];
+	bool rpt;
+
+	/* put entries into @skb in the order they appear in the list */
+	list_for_each_entry_safe_reverse(pos, next, fn, node) {
+		opt  = dccp_feat_genopt(pos);
+		type = dccp_feat_type(pos->feat_num);
+		rpt  = false;
+
+		if (pos->empty_confirm) {
+			len = 0;
+			ptr = NULL;
+		} else {
+			if (type == FEAT_SP) {
+				len = pos->val.sp.len;
+				ptr = pos->val.sp.vec;
+				rpt = pos->needs_confirm;
+			} else if (type == FEAT_NN) {
+				len = dccp_feat_valid_nn_length(pos->feat_num);
+				ptr = nn_in_nbo;
+				dccp_encode_value_var(pos->val.nn, ptr, len);
+			} else {
+				DCCP_BUG("unknown feature %u", pos->feat_num);
+				return -1;
+			}
+		}
+
+		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
+			return -1;
+		if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
+			return -1;
+		/*
+		 * Enter CHANGING after transmitting the Change option (6.6.2).
+		 */
+		if (pos->state == FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+	}
+	return 0;
+}
+
+/**
  * __feat_register_nn  -  Register new NN value on socket
  * @fn: feature-negotiation list to register with
  * @feat: an NN feature from %dccp_feature_numbers
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 20/37] dccp: Insert feature-negotiation options into skb
@ 2008-08-28 17:44                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This patch replaces the earlier insertion routine from options.c, so that
code specific to feature negotiation can remain in feat.c. This is possible
by calling a function already existing in options.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 
 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*,
+				  struct sk_buff *skb);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -297,6 +297,20 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+/**
+ * dccp_feat_valid_nn_length  -  Enforce length constraints on NN options
+ * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only,
+ * incoming options are accepted as long as their values are valid.
+ */
+static u8 dccp_feat_valid_nn_length(u8 feat_num)
+{
+	if (feat_num = DCCPF_ACK_RATIO)	/* RFC 4340, 11.3 and 6.6.8 */
+		return 2;
+	if (feat_num = DCCPF_SEQUENCE_WINDOW)	/* RFC 4340, 7.5.2 and 6.5  */
+		return 6;
+	return 0;
+}
+
 static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
 {
 	switch (feat_num) {
@@ -339,6 +353,57 @@ static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
 }
 
 /**
+ * dccp_feat_insert_opts  -  Generate FN options from current list state
+ * @skb: next sk_buff to be sent to the peer
+ * @dp: for client during handshake and general negotiation
+ * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND)
+ */
+int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
+			  struct sk_buff *skb)
+{
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	struct dccp_feat_entry *pos, *next;
+	u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN];
+	bool rpt;
+
+	/* put entries into @skb in the order they appear in the list */
+	list_for_each_entry_safe_reverse(pos, next, fn, node) {
+		opt  = dccp_feat_genopt(pos);
+		type = dccp_feat_type(pos->feat_num);
+		rpt  = false;
+
+		if (pos->empty_confirm) {
+			len = 0;
+			ptr = NULL;
+		} else {
+			if (type = FEAT_SP) {
+				len = pos->val.sp.len;
+				ptr = pos->val.sp.vec;
+				rpt = pos->needs_confirm;
+			} else if (type = FEAT_NN) {
+				len = dccp_feat_valid_nn_length(pos->feat_num);
+				ptr = nn_in_nbo;
+				dccp_encode_value_var(pos->val.nn, ptr, len);
+			} else {
+				DCCP_BUG("unknown feature %u", pos->feat_num);
+				return -1;
+			}
+		}
+
+		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
+			return -1;
+		if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
+			return -1;
+		/*
+		 * Enter CHANGING after transmitting the Change option (6.6.2).
+		 */
+		if (pos->state = FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+	}
+	return 0;
+}
+
+/**
  * __feat_register_nn  -  Register new NN value on socket
  * @fn: feature-negotiation list to register with
  * @feat: an NN feature from %dccp_feature_numbers
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 21/37] dccp: Integrate feature-negotiation insertion code
@ 2008-08-28 17:44                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

The patch implements insertion of feature negotiation at the server (listening
and request socket) and the client (connecting socket).

In dccp_insert_options(), several statements have been grouped together now
to achieve (I hope) better efficiency by reducing the number of tests each
packet has to go through:
 - Ack Vectors are sent if the packet is neither a Data or a Request packet;
 - a previous issue is corrected - feature negotiation options are allowed
   on DataAck packets (5.8).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/options.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -554,11 +554,25 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 	    dccp_insert_option_ndp(sk, skb))
 		return -1;
 
-	if (!dccp_packet_without_ack(skb)) {
-		if (dmsk->dccpms_send_ack_vector &&
-		    dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
-		    dccp_insert_option_ackvec(sk, skb))
+	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
+
+		/* Feature Negotiation */
+		if (dccp_feat_insert_opts(dp, NULL, skb))
 			return -1;
+
+		if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) {
+			/*
+			 * Obtain RTT sample from Request/Response exchange.
+			 * This is currently used in CCID 3 initialisation.
+			 */
+			if (dccp_insert_option_timestamp(sk, skb))
+				return -1;
+
+		} else if (dmsk->dccpms_send_ack_vector	&&
+			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
+			   dccp_insert_option_ackvec(sk, skb)) {
+				return -1;
+		}
 	}
 
 	if (dp->dccps_hc_rx_insert_options) {
@@ -567,14 +581,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/*
-	 * Obtain RTT sample from Request/Response exchange.
-	 * This is currently used in CCID 3 initialisation.
-	 */
-	if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST &&
-	    dccp_insert_option_timestamp(sk, skb))
-		return -1;
-
 	if (dp->dccps_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(dp, NULL, skb))
 		return -1;
@@ -587,6 +593,9 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
 {
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
+	if (dccp_feat_insert_opts(NULL, dreq, skb))
+		return -1;
+
 	if (dreq->dreq_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 		return -1;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 21/37] dccp: Integrate feature-negotiation insertion code
@ 2008-08-28 17:44                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

The patch implements insertion of feature negotiation at the server (listening
and request socket) and the client (connecting socket).

In dccp_insert_options(), several statements have been grouped together now
to achieve (I hope) better efficiency by reducing the number of tests each
packet has to go through:
 - Ack Vectors are sent if the packet is neither a Data or a Request packet;
 - a previous issue is corrected - feature negotiation options are allowed
   on DataAck packets (5.8).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/options.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -554,11 +554,25 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 	    dccp_insert_option_ndp(sk, skb))
 		return -1;
 
-	if (!dccp_packet_without_ack(skb)) {
-		if (dmsk->dccpms_send_ack_vector &&
-		    dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
-		    dccp_insert_option_ackvec(sk, skb))
+	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
+
+		/* Feature Negotiation */
+		if (dccp_feat_insert_opts(dp, NULL, skb))
 			return -1;
+
+		if (DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST) {
+			/*
+			 * Obtain RTT sample from Request/Response exchange.
+			 * This is currently used in CCID 3 initialisation.
+			 */
+			if (dccp_insert_option_timestamp(sk, skb))
+				return -1;
+
+		} else if (dmsk->dccpms_send_ack_vector	&&
+			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
+			   dccp_insert_option_ackvec(sk, skb)) {
+				return -1;
+		}
 	}
 
 	if (dp->dccps_hc_rx_insert_options) {
@@ -567,14 +581,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/*
-	 * Obtain RTT sample from Request/Response exchange.
-	 * This is currently used in CCID 3 initialisation.
-	 */
-	if (DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST &&
-	    dccp_insert_option_timestamp(sk, skb))
-		return -1;
-
 	if (dp->dccps_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(dp, NULL, skb))
 		return -1;
@@ -587,6 +593,9 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
 {
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
+	if (dccp_feat_insert_opts(NULL, dreq, skb))
+		return -1;
+
 	if (dreq->dreq_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 		return -1;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 22/37] dccp: Preference list reconciliation
@ 2008-08-28 17:44                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides two functions to
 * reconcile preference lists (with appropriate return codes) and
 * reorder the preference list if successful reconciliation changed the
   preferred value.

The patch also removes the old code for processing SP/NN Change options, since
new code to process these is mostly there already; related references have been
commented out.

The code for processing Change options follows in the next patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 2 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -715,6 +715,76 @@ static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
 	return 0;
 }
 
+/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
+static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
+{
+	u8 c, s;
+
+	for (s = 0; s < slen; s++)
+		for (c = 0; c < clen; c++)
+			if (servlist[s] == clilist[c])
+				return servlist[s];
+	return -1;
+}
+
+/**
+ * dccp_feat_prefer  -  Move preferred entry to the start of array
+ * Reorder the @array_len elements in @array so that @preferred_value comes
+ * first. Returns >0 to indicate that @preferred_value does occur in @array.
+ */
+static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len)
+{
+	u8 i, does_occur = 0;
+
+	if (array != NULL) {
+		for (i = 0; i < array_len; i++)
+			if (array[i] == preferred_value) {
+				array[i] = array[0];
+				does_occur++;
+			}
+		if (does_occur)
+			array[0] = preferred_value;
+	}
+	return does_occur;
+}
+
+/**
+ * dccp_feat_reconcile  -  Reconcile SP preference lists
+ *  @fval: SP list to reconcile into
+ *  @arr: received SP preference list
+ *  @len: length of @arr in bytes
+ *  @is_server: whether this side is the server (and @fv is the server's list)
+ *  @reorder: whether to reorder the list in @fv after reconciling with @arr
+ * When successful, > 0 is returned and the reconciled list is in @fval.
+ * A value of 0 means that negotiation failed (no shared entry).
+ */
+static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
+			       bool is_server, bool reorder)
+{
+	int rc;
+
+	if (!fv->sp.vec || !arr) {
+		DCCP_CRIT("NULL feature value or array");
+		return 0;
+	}
+
+	if (is_server)
+		rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len);
+	else
+		rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len);
+
+	if (!reorder)
+		return rc;
+	if (rc < 0)
+		return 0;
+
+	/*
+	 * Reorder list: used for activating features and in dccp_insert_fn_opt.
+	 */
+	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
+}
+
+#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
 static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
 			       u8 *rpref, u8 rlen)
 {
@@ -910,6 +980,7 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
+#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -985,12 +1056,14 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 	switch (feature) {
 	/* deal with SP features */
 	case DCCPF_CCID:
-		rc = dccp_feat_sp(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_sp(sk, type, feature, val, len); */
 		break;
 
 	/* deal with NN features */
 	case DCCPF_ACK_RATIO:
-		rc = dccp_feat_nn(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_nn(sk, type, feature, val, len); */
 		break;
 
 	/* XXX implement other features */
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 22/37] dccp: Preference list reconciliation
@ 2008-08-28 17:44                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This provides two functions to
 * reconcile preference lists (with appropriate return codes) and
 * reorder the preference list if successful reconciliation changed the
   preferred value.

The patch also removes the old code for processing SP/NN Change options, since
new code to process these is mostly there already; related references have been
commented out.

The code for processing Change options follows in the next patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 2 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -715,6 +715,76 @@ static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
 	return 0;
 }
 
+/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
+static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
+{
+	u8 c, s;
+
+	for (s = 0; s < slen; s++)
+		for (c = 0; c < clen; c++)
+			if (servlist[s] = clilist[c])
+				return servlist[s];
+	return -1;
+}
+
+/**
+ * dccp_feat_prefer  -  Move preferred entry to the start of array
+ * Reorder the @array_len elements in @array so that @preferred_value comes
+ * first. Returns >0 to indicate that @preferred_value does occur in @array.
+ */
+static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len)
+{
+	u8 i, does_occur = 0;
+
+	if (array != NULL) {
+		for (i = 0; i < array_len; i++)
+			if (array[i] = preferred_value) {
+				array[i] = array[0];
+				does_occur++;
+			}
+		if (does_occur)
+			array[0] = preferred_value;
+	}
+	return does_occur;
+}
+
+/**
+ * dccp_feat_reconcile  -  Reconcile SP preference lists
+ *  @fval: SP list to reconcile into
+ *  @arr: received SP preference list
+ *  @len: length of @arr in bytes
+ *  @is_server: whether this side is the server (and @fv is the server's list)
+ *  @reorder: whether to reorder the list in @fv after reconciling with @arr
+ * When successful, > 0 is returned and the reconciled list is in @fval.
+ * A value of 0 means that negotiation failed (no shared entry).
+ */
+static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
+			       bool is_server, bool reorder)
+{
+	int rc;
+
+	if (!fv->sp.vec || !arr) {
+		DCCP_CRIT("NULL feature value or array");
+		return 0;
+	}
+
+	if (is_server)
+		rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len);
+	else
+		rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len);
+
+	if (!reorder)
+		return rc;
+	if (rc < 0)
+		return 0;
+
+	/*
+	 * Reorder list: used for activating features and in dccp_insert_fn_opt.
+	 */
+	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
+}
+
+#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
 static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
 			       u8 *rpref, u8 rlen)
 {
@@ -910,6 +980,7 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
+#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -985,12 +1056,14 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 	switch (feature) {
 	/* deal with SP features */
 	case DCCPF_CCID:
-		rc = dccp_feat_sp(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_sp(sk, type, feature, val, len); */
 		break;
 
 	/* deal with NN features */
 	case DCCPF_ACK_RATIO:
-		rc = dccp_feat_nn(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_nn(sk, type, feature, val, len); */
 		break;
 
 	/* XXX implement other features */
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 23/37] dccp: Process incoming Change feature-negotiation options
@ 2008-08-28 17:44                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This adds/replaces code for processing incoming ChangeL/R options.
The main difference is that:
 * mandatory FN options are now interpreted inside the function
  (there are too many individual cases to do this externally);
 * the function returns an appropriate Reset code or 0,
   which is then used to fill in the data for the Reset packet.

Old code, which is no longer used or referenced, has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |  148 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/feat.h    |    4 +-
 net/dccp/options.c |   23 +++-----
 3 files changed, 157 insertions(+), 18 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -980,7 +980,6 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
-#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -1091,6 +1090,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
+#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1231,6 +1231,152 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
+/**
+ * dccp_feat_change_recv  -  Process incoming ChangeL/R options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether the Change was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is the server (1) or the client (0)
+ */
+static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 defval, type = dccp_feat_type(feat);
+	const bool local = (opt == DCCPO_CHANGE_R);
+	struct dccp_feat_entry *entry;
+	dccp_feat_val fval;
+
+	if (len == 0 || type == FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
+		goto unknown_feature_or_value;
+
+	/*
+	 *	Negotiation of NN features: Change R is invalid, so there is no
+	 *	simultaneous negotiation; hence we do not consult the list.
+	 */
+	if (type == FEAT_NN) {
+		if (local)
+			goto not_valid_or_not_known;
+
+		if (len > sizeof(fval.nn))
+			goto unknown_feature_or_value;
+
+		/* 6.3.2: "The feature remote MUST accept any valid value..." */
+		fval.nn = dccp_decode_value_var(val, len);
+		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+			goto unknown_feature_or_value;
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+	}
+
+	/*
+	 *	Unidirectional/simultaneous negotiation of SP features (6.3.1)
+	 */
+	entry = dccp_feat_list_lookup(fn, feat, local);
+	if (entry == NULL) {
+		if (!dccp_feat_sp_list_ok(feat, val, len))
+			goto unknown_feature_or_value;
+		/*
+		 * No particular preferences have been registered. We deal with
+		 * this situation by assuming that all valid values are equally
+		 * acceptable, and apply the following checks:
+		 * - if the peer's list is a singleton, we accept a valid value;
+		 * - if we are the server, we first try to see if the peer (the
+		 *   client) advertises the default value. If yes, we use it,
+		 *   otherwise we accept the preferred value;
+		 * - else if we are the client, we use the first list element.
+		 */
+		if (dccp_feat_clone_sp_val(&fval, val, 1))
+			return DCCP_RESET_CODE_TOO_BUSY;
+
+		if (len > 1 && server) {
+			defval = dccp_feat_default_value(feat);
+			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
+				fval.sp.vec[0] = defval;
+		}
+
+		/* Treat unsupported CCIDs like invalid values */
+		if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
+			kfree(fval.sp.vec);
+			goto not_valid_or_not_known;
+		}
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+
+	} else if (entry->state == FEAT_UNSTABLE) {	/* 6.6.2 */
+		return 0;
+	}
+
+	if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
+		entry->empty_confirm = 0;
+	} else if (is_mandatory) {
+		return DCCP_RESET_CODE_MANDATORY_ERROR;
+	} else if (entry->state == FEAT_INITIALISING) {
+		/*
+		 * Failed simultaneous negotiation (server only): try to `save'
+		 * the connection by checking whether entry contains the default
+		 * value for @feat. If yes, send an empty Confirm to signal that
+		 * the received Change was not understood - which implies using
+		 * the default value.
+		 * If this also fails, we use Reset as the last resort.
+		 */
+		WARN_ON(!server);
+		defval = dccp_feat_default_value(feat);
+		if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
+			return DCCP_RESET_CODE_OPTION_ERROR;
+		entry->empty_confirm = 1;
+	}
+	entry->needs_confirm   = 1;
+	entry->needs_mandatory = 0;
+	entry->state	       = FEAT_STABLE;
+	return 0;
+
+unknown_feature_or_value:
+	if (!is_mandatory)
+		return dccp_push_empty_confirm(fn, feat, local);
+
+not_valid_or_not_known:
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
+ * dccp_feat_parse_options  -  Process Feature-Negotiation Options
+ * @sk: for general use and used by the client during connection setup
+ * @dreq: used by the server during connection setup
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: value contents of @opt
+ * @len: length of @val in bytes
+ * Returns 0 on success, a Reset code for ending the connection otherwise.
+ */
+int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
+			    u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	bool server = false;
+
+	switch (sk->sk_state) {
+	/*
+	 *	Negotiation during connection setup
+	 */
+	case DCCP_LISTEN:
+		server = true;			/* fall through */
+	case DCCP_REQUESTING:
+		switch (opt) {
+		case DCCPO_CHANGE_L:
+		case DCCPO_CHANGE_R:
+			return dccp_feat_change_recv(fn, mandatory, opt, feat,
+						     val, len, server);
+		}
+	}
+	return 0;	/* ignore FN options in all other states */
+}
+
 int dccp_feat_init(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -113,8 +113,8 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
-extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
-				  u8 *val, u8 len);
+extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
+				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -135,22 +135,13 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
 		case DCCPO_CHANGE_L:
-			/* fall through */
 		case DCCPO_CHANGE_R:
 			if (pkt_type == DCCP_PKT_DATA)
 				break;
-			if (len < 2)
-				goto out_invalid_option;
-			rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
-						   len - 1);
-			/*
-			 * When there is a change error, change_recv is
-			 * responsible for dealing with it.  i.e. reply with an
-			 * empty confirm.
-			 * If the change was mandatory, then we need to die.
-			 */
-			if (rc && mandatory)
-				goto out_invalid_option;
+			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
+						    *value, value + 1, len - 1);
+			if (rc)
+				goto out_featneg_failed;
 			break;
 		case DCCPO_CONFIRM_L:
 			/* fall through */
@@ -292,8 +283,10 @@ out_nonsensical_length:
 
 out_invalid_option:
 	DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
-	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
-	DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
+	rc = DCCP_RESET_CODE_OPTION_ERROR;
+out_featneg_failed:
+	DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
+	DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 23/37] dccp: Process incoming Change feature-negotiation options
@ 2008-08-28 17:44                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

This adds/replaces code for processing incoming ChangeL/R options.
The main difference is that:
 * mandatory FN options are now interpreted inside the function
  (there are too many individual cases to do this externally);
 * the function returns an appropriate Reset code or 0,
   which is then used to fill in the data for the Reset packet.

Old code, which is no longer used or referenced, has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |  148 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/feat.h    |    4 +-
 net/dccp/options.c |   23 +++-----
 3 files changed, 157 insertions(+), 18 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -980,7 +980,6 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
-#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -1091,6 +1090,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
+#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1231,6 +1231,152 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
+/**
+ * dccp_feat_change_recv  -  Process incoming ChangeL/R options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether the Change was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is the server (1) or the client (0)
+ */
+static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 defval, type = dccp_feat_type(feat);
+	const bool local = (opt = DCCPO_CHANGE_R);
+	struct dccp_feat_entry *entry;
+	dccp_feat_val fval;
+
+	if (len = 0 || type = FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
+		goto unknown_feature_or_value;
+
+	/*
+	 *	Negotiation of NN features: Change R is invalid, so there is no
+	 *	simultaneous negotiation; hence we do not consult the list.
+	 */
+	if (type = FEAT_NN) {
+		if (local)
+			goto not_valid_or_not_known;
+
+		if (len > sizeof(fval.nn))
+			goto unknown_feature_or_value;
+
+		/* 6.3.2: "The feature remote MUST accept any valid value..." */
+		fval.nn = dccp_decode_value_var(val, len);
+		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+			goto unknown_feature_or_value;
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+	}
+
+	/*
+	 *	Unidirectional/simultaneous negotiation of SP features (6.3.1)
+	 */
+	entry = dccp_feat_list_lookup(fn, feat, local);
+	if (entry = NULL) {
+		if (!dccp_feat_sp_list_ok(feat, val, len))
+			goto unknown_feature_or_value;
+		/*
+		 * No particular preferences have been registered. We deal with
+		 * this situation by assuming that all valid values are equally
+		 * acceptable, and apply the following checks:
+		 * - if the peer's list is a singleton, we accept a valid value;
+		 * - if we are the server, we first try to see if the peer (the
+		 *   client) advertises the default value. If yes, we use it,
+		 *   otherwise we accept the preferred value;
+		 * - else if we are the client, we use the first list element.
+		 */
+		if (dccp_feat_clone_sp_val(&fval, val, 1))
+			return DCCP_RESET_CODE_TOO_BUSY;
+
+		if (len > 1 && server) {
+			defval = dccp_feat_default_value(feat);
+			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
+				fval.sp.vec[0] = defval;
+		}
+
+		/* Treat unsupported CCIDs like invalid values */
+		if (feat = DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
+			kfree(fval.sp.vec);
+			goto not_valid_or_not_known;
+		}
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+
+	} else if (entry->state = FEAT_UNSTABLE) {	/* 6.6.2 */
+		return 0;
+	}
+
+	if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
+		entry->empty_confirm = 0;
+	} else if (is_mandatory) {
+		return DCCP_RESET_CODE_MANDATORY_ERROR;
+	} else if (entry->state = FEAT_INITIALISING) {
+		/*
+		 * Failed simultaneous negotiation (server only): try to `save'
+		 * the connection by checking whether entry contains the default
+		 * value for @feat. If yes, send an empty Confirm to signal that
+		 * the received Change was not understood - which implies using
+		 * the default value.
+		 * If this also fails, we use Reset as the last resort.
+		 */
+		WARN_ON(!server);
+		defval = dccp_feat_default_value(feat);
+		if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
+			return DCCP_RESET_CODE_OPTION_ERROR;
+		entry->empty_confirm = 1;
+	}
+	entry->needs_confirm   = 1;
+	entry->needs_mandatory = 0;
+	entry->state	       = FEAT_STABLE;
+	return 0;
+
+unknown_feature_or_value:
+	if (!is_mandatory)
+		return dccp_push_empty_confirm(fn, feat, local);
+
+not_valid_or_not_known:
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
+ * dccp_feat_parse_options  -  Process Feature-Negotiation Options
+ * @sk: for general use and used by the client during connection setup
+ * @dreq: used by the server during connection setup
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: value contents of @opt
+ * @len: length of @val in bytes
+ * Returns 0 on success, a Reset code for ending the connection otherwise.
+ */
+int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
+			    u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	bool server = false;
+
+	switch (sk->sk_state) {
+	/*
+	 *	Negotiation during connection setup
+	 */
+	case DCCP_LISTEN:
+		server = true;			/* fall through */
+	case DCCP_REQUESTING:
+		switch (opt) {
+		case DCCPO_CHANGE_L:
+		case DCCPO_CHANGE_R:
+			return dccp_feat_change_recv(fn, mandatory, opt, feat,
+						     val, len, server);
+		}
+	}
+	return 0;	/* ignore FN options in all other states */
+}
+
 int dccp_feat_init(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -113,8 +113,8 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
-extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
-				  u8 *val, u8 len);
+extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
+				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -135,22 +135,13 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
 		case DCCPO_CHANGE_L:
-			/* fall through */
 		case DCCPO_CHANGE_R:
 			if (pkt_type = DCCP_PKT_DATA)
 				break;
-			if (len < 2)
-				goto out_invalid_option;
-			rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
-						   len - 1);
-			/*
-			 * When there is a change error, change_recv is
-			 * responsible for dealing with it.  i.e. reply with an
-			 * empty confirm.
-			 * If the change was mandatory, then we need to die.
-			 */
-			if (rc && mandatory)
-				goto out_invalid_option;
+			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
+						    *value, value + 1, len - 1);
+			if (rc)
+				goto out_featneg_failed;
 			break;
 		case DCCPO_CONFIRM_L:
 			/* fall through */
@@ -292,8 +283,10 @@ out_nonsensical_length:
 
 out_invalid_option:
 	DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
-	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
-	DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
+	rc = DCCP_RESET_CODE_OPTION_ERROR;
+out_featneg_failed:
+	DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
+	DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 24/37] dccp: Processing Confirm options
@ 2008-08-28 17:44                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

Analogous to the previous patch, this adds code to interpret incoming Confirm
feature-negotiation options. Both functions operate on the feature-negotiation
list of either the request_sock (server) or the dccp_sock (client).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c    |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/feat.h    |    2 -
 net/dccp/options.c |   16 +-------
 3 files changed, 100 insertions(+), 17 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -99,6 +99,13 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? : dccp_feat_table[idx].default_value;
 }
 
+/* Test for "Req'd" feature (RFC 4340, 6.4) */
+static inline int dccp_feat_must_be_understood(u8 feat_num)
+{
+	return	feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS ||
+		feat_num == DCCPF_SEQUENCE_WINDOW;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -1090,7 +1097,6 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1145,6 +1151,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
+#endif	/* (later) */
 
 void dccp_feat_clean(struct dccp_minisock *dmsk)
 {
@@ -1343,6 +1350,92 @@ not_valid_or_not_known:
 }
 
 /**
+ * dccp_feat_confirm_recv  -  Process received Confirm options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is server (1) or client (0)
+ */
+static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				 u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 *plist, plen, type = dccp_feat_type(feat);
+	const bool local = (opt == DCCPO_CONFIRM_R);
+	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
+
+	if (entry == NULL) {	/* nothing queued: ignore or handle error */
+		if (is_mandatory && type == FEAT_UNKNOWN)
+			return DCCP_RESET_CODE_MANDATORY_ERROR;
+
+		if (!local && type == FEAT_NN)		/* 6.3.2 */
+			goto confirmation_failed;
+		return 0;
+	}
+
+	if (entry->state != FEAT_CHANGING)		/* 6.6.2 */
+		return 0;
+
+	if (len == 0) {
+		if (dccp_feat_must_be_understood(feat))	/* 6.6.7 */
+			goto confirmation_failed;
+		/*
+		 * Empty Confirm during connection setup: this means reverting
+		 * to the `old' value, which in this case is the default. Since
+		 * we handle default values automatically when no other values
+		 * have been set, we revert to the old value by removing this
+		 * entry from the list.
+		 */
+		dccp_feat_list_pop(entry);
+		return 0;
+	}
+
+	if (type == FEAT_NN) {
+		if (len > sizeof(entry->val.nn))
+			goto confirmation_failed;
+
+		if (entry->val.nn == dccp_decode_value_var(val, len))
+			goto confirmation_succeeded;
+
+		DCCP_WARN("Bogus Confirm for non-existing value\n");
+		goto confirmation_failed;
+	}
+
+	/*
+	 * Parsing SP Confirms: the first element of @val is the preferred
+	 * SP value which the peer confirms, the remainder depends on @len.
+	 */
+	if (!dccp_feat_sp_list_ok(feat, val, len))
+		goto confirmation_failed;
+
+	if (len == 1) {		/* peer didn't supply a preference list */
+		plist = val;
+		plen  = len;
+	} else {		/* preferred value + preference list */
+		plist = val + 1;
+		plen  = len - 1;
+	}
+
+	/* Check whether the peer got the reconciliation right (6.6.8) */
+	if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
+		DCCP_WARN("Confirm selected the wrong value %u\n", *val);
+		return DCCP_RESET_CODE_OPTION_ERROR;
+	}
+	entry->val.sp.vec[0] = *val;
+
+confirmation_succeeded:
+	entry->state = FEAT_STABLE;
+	return 0;
+
+confirmation_failed:
+	DCCP_WARN("Confirmation failed\n");
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
  * dccp_feat_parse_options  -  Process Feature-Negotiation Options
  * @sk: for general use and used by the client during connection setup
  * @dreq: used by the server during connection setup
@@ -1372,6 +1465,10 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_CHANGE_R:
 			return dccp_feat_change_recv(fn, mandatory, opt, feat,
 						     val, len, server);
+		case DCCPO_CONFIRM_R:
+		case DCCPO_CONFIRM_L:
+			return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
+						      val, len, server);
 		}
 	}
 	return 0;	/* ignore FN options in all other states */
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -115,8 +115,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -134,26 +134,14 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 			dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
-		case DCCPO_CHANGE_L:
-		case DCCPO_CHANGE_R:
-			if (pkt_type == DCCP_PKT_DATA)
+		case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
+			if (pkt_type == DCCP_PKT_DATA)      /* RFC 4340, 6 */
 				break;
 			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
 						    *value, value + 1, len - 1);
 			if (rc)
 				goto out_featneg_failed;
 			break;
-		case DCCPO_CONFIRM_L:
-			/* fall through */
-		case DCCPO_CONFIRM_R:
-			if (pkt_type == DCCP_PKT_DATA)
-				break;
-			if (len < 2)	/* FIXME this disallows empty confirm */
-				goto out_invalid_option;
-			if (dccp_feat_confirm_recv(sk, opt, *value,
-						   value + 1, len - 1))
-				goto out_invalid_option;
-			break;
 		case DCCPO_ACK_VECTOR_0:
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 24/37] dccp: Processing Confirm options
@ 2008-08-28 17:44                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:44 UTC (permalink / raw)
  To: dccp

Analogous to the previous patch, this adds code to interpret incoming Confirm
feature-negotiation options. Both functions operate on the feature-negotiation
list of either the request_sock (server) or the dccp_sock (client).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c    |   99 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/feat.h    |    2 -
 net/dccp/options.c |   16 +-------
 3 files changed, 100 insertions(+), 17 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -99,6 +99,13 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? : dccp_feat_table[idx].default_value;
 }
 
+/* Test for "Req'd" feature (RFC 4340, 6.4) */
+static inline int dccp_feat_must_be_understood(u8 feat_num)
+{
+	return	feat_num = DCCPF_CCID || feat_num = DCCPF_SHORT_SEQNOS ||
+		feat_num = DCCPF_SEQUENCE_WINDOW;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -1090,7 +1097,6 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1145,6 +1151,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
+#endif	/* (later) */
 
 void dccp_feat_clean(struct dccp_minisock *dmsk)
 {
@@ -1343,6 +1350,92 @@ not_valid_or_not_known:
 }
 
 /**
+ * dccp_feat_confirm_recv  -  Process received Confirm options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is server (1) or client (0)
+ */
+static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				 u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 *plist, plen, type = dccp_feat_type(feat);
+	const bool local = (opt = DCCPO_CONFIRM_R);
+	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
+
+	if (entry = NULL) {	/* nothing queued: ignore or handle error */
+		if (is_mandatory && type = FEAT_UNKNOWN)
+			return DCCP_RESET_CODE_MANDATORY_ERROR;
+
+		if (!local && type = FEAT_NN)		/* 6.3.2 */
+			goto confirmation_failed;
+		return 0;
+	}
+
+	if (entry->state != FEAT_CHANGING)		/* 6.6.2 */
+		return 0;
+
+	if (len = 0) {
+		if (dccp_feat_must_be_understood(feat))	/* 6.6.7 */
+			goto confirmation_failed;
+		/*
+		 * Empty Confirm during connection setup: this means reverting
+		 * to the `old' value, which in this case is the default. Since
+		 * we handle default values automatically when no other values
+		 * have been set, we revert to the old value by removing this
+		 * entry from the list.
+		 */
+		dccp_feat_list_pop(entry);
+		return 0;
+	}
+
+	if (type = FEAT_NN) {
+		if (len > sizeof(entry->val.nn))
+			goto confirmation_failed;
+
+		if (entry->val.nn = dccp_decode_value_var(val, len))
+			goto confirmation_succeeded;
+
+		DCCP_WARN("Bogus Confirm for non-existing value\n");
+		goto confirmation_failed;
+	}
+
+	/*
+	 * Parsing SP Confirms: the first element of @val is the preferred
+	 * SP value which the peer confirms, the remainder depends on @len.
+	 */
+	if (!dccp_feat_sp_list_ok(feat, val, len))
+		goto confirmation_failed;
+
+	if (len = 1) {		/* peer didn't supply a preference list */
+		plist = val;
+		plen  = len;
+	} else {		/* preferred value + preference list */
+		plist = val + 1;
+		plen  = len - 1;
+	}
+
+	/* Check whether the peer got the reconciliation right (6.6.8) */
+	if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
+		DCCP_WARN("Confirm selected the wrong value %u\n", *val);
+		return DCCP_RESET_CODE_OPTION_ERROR;
+	}
+	entry->val.sp.vec[0] = *val;
+
+confirmation_succeeded:
+	entry->state = FEAT_STABLE;
+	return 0;
+
+confirmation_failed:
+	DCCP_WARN("Confirmation failed\n");
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
  * dccp_feat_parse_options  -  Process Feature-Negotiation Options
  * @sk: for general use and used by the client during connection setup
  * @dreq: used by the server during connection setup
@@ -1372,6 +1465,10 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_CHANGE_R:
 			return dccp_feat_change_recv(fn, mandatory, opt, feat,
 						     val, len, server);
+		case DCCPO_CONFIRM_R:
+		case DCCPO_CONFIRM_L:
+			return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
+						      val, len, server);
 		}
 	}
 	return 0;	/* ignore FN options in all other states */
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -115,8 +115,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -134,26 +134,14 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 			dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
-		case DCCPO_CHANGE_L:
-		case DCCPO_CHANGE_R:
-			if (pkt_type = DCCP_PKT_DATA)
+		case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
+			if (pkt_type = DCCP_PKT_DATA)      /* RFC 4340, 6 */
 				break;
 			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
 						    *value, value + 1, len - 1);
 			if (rc)
 				goto out_featneg_failed;
 			break;
-		case DCCPO_CONFIRM_L:
-			/* fall through */
-		case DCCPO_CONFIRM_R:
-			if (pkt_type = DCCP_PKT_DATA)
-				break;
-			if (len < 2)	/* FIXME this disallows empty confirm */
-				goto out_invalid_option;
-			if (dccp_feat_confirm_recv(sk, opt, *value,
-						   value + 1, len - 1))
-				goto out_invalid_option;
-			break;
 		case DCCPO_ACK_VECTOR_0:
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 25/37] dccp: Feature activation handlers
@ 2008-08-28 17:45                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch provides the post-processing of feature negotiation state, after
the negotiation has completed.

To this purpose, handlers are used and added to the dccp_feat_table. Each
handler is passed a boolean flag whether the RX or TX side of the feature
is meant.

Several handlers are provided already, new handlers can easily be added.

The initialisation is now fully dynamic, i.e. CCIDs are activated only
after the feature negotiation. The integration of this dynamic activation
is done in the subsequent patches.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    1 +
 net/dccp/feat.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 211 insertions(+), 10 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -445,6 +445,7 @@ 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*,
 				  struct sk_buff *skb);
+extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,11 +25,101 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/*
+ * Feature activation handlers.
+ *
+ * These all use an u64 argument, to provide enough room for NN/SP features. At
+ * this stage the negotiated values have been checked to be within their range.
+ */
+static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
+
+	if (new_ccid == NULL)
+		return -ENOMEM;
+
+	if (rx) {
+		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+		dp->dccps_hc_rx_ccid = new_ccid;
+	} else {
+		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+		dp->dccps_hc_tx_ccid = new_ccid;
+	}
+	return 0;
+}
+
+static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	return 0;
+}
+
+static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
+{
+	if (rx)
+		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
+	else
+		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
+	return 0;
+}
+
+static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		if (enable && dp->dccps_hc_rx_ackvec == NULL) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
+			if (dp->dccps_hc_rx_ackvec == NULL)
+				return -ENOMEM;
+		} else if (!enable) {
+			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+			dp->dccps_hc_rx_ackvec = NULL;
+		}
+	}
+	return 0;
+}
+
+static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+	return 0;
+}
+
+/*
+ * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
+ * `rx' holds when the sending peer informs about his partial coverage via a
+ * ChangeR() option. In the other case, we are the sender and the receiver
+ * announces its coverage via ChangeL() options. The policy here is to honour
+ * such communication by enabling the corresponding partial coverage - but only
+ * if it has not been set manually before; the warning here means that all
+ * packets will be dropped.
+ */
+static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx)
+		dp->dccps_pcrlen = cscov;
+	else {
+		if (dp->dccps_pcslen == 0)
+			dp->dccps_pcslen = cscov;
+		else if (cscov > dp->dccps_pcslen)
+			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
+				  dp->dccps_pcslen, (u8)cscov);
+	}
+	return 0;
+}
+
 static const struct {
 	u8			feat_num;		/* DCCPF_xxx */
 	enum dccp_feat_type	rxtx;			/* RX or TX  */
 	enum dccp_feat_type	reconciliation;		/* SP or NN  */
 	u8			default_value;		/* as in 6.4 */
+	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
 /*
  *    Lookup table for location and type of features (from RFC 4340/4342)
  *  +--------------------------+----+-----+----+----+---------+-----------+
@@ -49,16 +139,16 @@ static const struct {
  *  +--------------------------+----+-----+----+----+---------+-----------+
  */
 } dccp_feat_table[] = {
-	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
-	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
-	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
-	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
@@ -99,6 +189,55 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? : dccp_feat_table[idx].default_value;
 }
 
+static int __dccp_feat_activate(struct sock *sk, const int idx,
+				const bool is_local, dccp_feat_val const *fval)
+{
+	bool rx;
+	u64 val;
+
+	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
+		return -1;
+	if (dccp_feat_table[idx].activation_hdlr == NULL)
+		return 0;
+
+	if (fval == NULL) {
+		val = dccp_feat_table[idx].default_value;
+	} else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
+		if (fval->sp.vec == NULL) {
+			/*
+			 * This can happen when an empty Confirm is sent
+			 * for an SP (i.e. known) feature. In this case
+			 * we would be using the default anyway.
+			 */
+			DCCP_CRIT("Feature #%d undefined: using default", idx);
+			val = dccp_feat_table[idx].default_value;
+		} else {
+			val = fval->sp.vec[0];
+		}
+	} else {
+		val = fval->nn;
+	}
+
+	/* Location is RX if this is a local-RX or remote-TX feature */
+	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
+
+	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 mean 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)
 {
@@ -1504,6 +1643,67 @@ out:
 
 EXPORT_SYMBOL_GPL(dccp_feat_init);
 
+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_feat_entry *cur, *next;
+	int idx;
+	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
+		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
+	};
+
+	list_for_each_entry(cur, fn_list, node) {
+
+		idx = dccp_feat_index(cur->feat_num);
+		if (idx < 0) {
+			DCCP_BUG("Unknown feature %u", cur->feat_num);
+			goto activation_failed;
+		}
+		if (cur->state != FEAT_STABLE) {
+			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+				  cur->is_local ? "local" : "remote",
+				  cur->feat_num, cur->state);
+			goto activation_failed;
+		}
+		fvals[idx][cur->is_local] = &cur->val;
+	}
+
+	/*
+	 * Activate in decreasing order of index, so that the CCIDs are always
+	 * activated as the last feature. This avoids the case where a CCID
+	 * relies on the initialisation of one or more features that it depends
+	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
+	 */
+	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
+		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
+		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
+			DCCP_CRIT("Could not activate %d", idx);
+			goto activation_failed;
+		}
+
+	/* Clean up Change options which have been confirmed already */
+	list_for_each_entry_safe(cur, next, fn_list, node)
+		if (!cur->needs_confirm)
+			dccp_feat_list_pop(cur);
+
+	dccp_pr_debug("Activation OK\n");
+	return 0;
+
+activation_failed:
+	/*
+	 * We clean up everything that may have been allocated, since
+	 * it is difficult to track at which stage negotiation failed.
+	 * This is ok, since all allocation functions below are robust
+	 * against NULL arguments.
+	 */
+	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+	dp->dccps_hc_rx_ackvec = NULL;
+	return -1;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 const char *dccp_feat_typename(const u8 type)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 25/37] dccp: Feature activation handlers
@ 2008-08-28 17:45                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This patch provides the post-processing of feature negotiation state, after
the negotiation has completed.

To this purpose, handlers are used and added to the dccp_feat_table. Each
handler is passed a boolean flag whether the RX or TX side of the feature
is meant.

Several handlers are provided already, new handlers can easily be added.

The initialisation is now fully dynamic, i.e. CCIDs are activated only
after the feature negotiation. The integration of this dynamic activation
is done in the subsequent patches.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    1 +
 net/dccp/feat.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 211 insertions(+), 10 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -445,6 +445,7 @@ 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*,
 				  struct sk_buff *skb);
+extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,11 +25,101 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/*
+ * Feature activation handlers.
+ *
+ * These all use an u64 argument, to provide enough room for NN/SP features. At
+ * this stage the negotiated values have been checked to be within their range.
+ */
+static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
+
+	if (new_ccid = NULL)
+		return -ENOMEM;
+
+	if (rx) {
+		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+		dp->dccps_hc_rx_ccid = new_ccid;
+	} else {
+		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+		dp->dccps_hc_tx_ccid = new_ccid;
+	}
+	return 0;
+}
+
+static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	return 0;
+}
+
+static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
+{
+	if (rx)
+		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
+	else
+		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
+	return 0;
+}
+
+static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		if (enable && dp->dccps_hc_rx_ackvec = NULL) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
+			if (dp->dccps_hc_rx_ackvec = NULL)
+				return -ENOMEM;
+		} else if (!enable) {
+			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+			dp->dccps_hc_rx_ackvec = NULL;
+		}
+	}
+	return 0;
+}
+
+static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+	return 0;
+}
+
+/*
+ * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
+ * `rx' holds when the sending peer informs about his partial coverage via a
+ * ChangeR() option. In the other case, we are the sender and the receiver
+ * announces its coverage via ChangeL() options. The policy here is to honour
+ * such communication by enabling the corresponding partial coverage - but only
+ * if it has not been set manually before; the warning here means that all
+ * packets will be dropped.
+ */
+static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx)
+		dp->dccps_pcrlen = cscov;
+	else {
+		if (dp->dccps_pcslen = 0)
+			dp->dccps_pcslen = cscov;
+		else if (cscov > dp->dccps_pcslen)
+			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
+				  dp->dccps_pcslen, (u8)cscov);
+	}
+	return 0;
+}
+
 static const struct {
 	u8			feat_num;		/* DCCPF_xxx */
 	enum dccp_feat_type	rxtx;			/* RX or TX  */
 	enum dccp_feat_type	reconciliation;		/* SP or NN  */
 	u8			default_value;		/* as in 6.4 */
+	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
 /*
  *    Lookup table for location and type of features (from RFC 4340/4342)
  *  +--------------------------+----+-----+----+----+---------+-----------+
@@ -49,16 +139,16 @@ static const struct {
  *  +--------------------------+----+-----+----+----+---------+-----------+
  */
 } dccp_feat_table[] = {
-	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
-	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
-	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
-	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
@@ -99,6 +189,55 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? : dccp_feat_table[idx].default_value;
 }
 
+static int __dccp_feat_activate(struct sock *sk, const int idx,
+				const bool is_local, dccp_feat_val const *fval)
+{
+	bool rx;
+	u64 val;
+
+	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
+		return -1;
+	if (dccp_feat_table[idx].activation_hdlr = NULL)
+		return 0;
+
+	if (fval = NULL) {
+		val = dccp_feat_table[idx].default_value;
+	} else if (dccp_feat_table[idx].reconciliation = FEAT_SP) {
+		if (fval->sp.vec = NULL) {
+			/*
+			 * This can happen when an empty Confirm is sent
+			 * for an SP (i.e. known) feature. In this case
+			 * we would be using the default anyway.
+			 */
+			DCCP_CRIT("Feature #%d undefined: using default", idx);
+			val = dccp_feat_table[idx].default_value;
+		} else {
+			val = fval->sp.vec[0];
+		}
+	} else {
+		val = fval->nn;
+	}
+
+	/* Location is RX if this is a local-RX or remote-TX feature */
+	rx = (is_local = (dccp_feat_table[idx].rxtx = FEAT_AT_RX));
+
+	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 mean 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)
 {
@@ -1504,6 +1643,67 @@ out:
 
 EXPORT_SYMBOL_GPL(dccp_feat_init);
 
+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_feat_entry *cur, *next;
+	int idx;
+	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
+		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
+	};
+
+	list_for_each_entry(cur, fn_list, node) {
+
+		idx = dccp_feat_index(cur->feat_num);
+		if (idx < 0) {
+			DCCP_BUG("Unknown feature %u", cur->feat_num);
+			goto activation_failed;
+		}
+		if (cur->state != FEAT_STABLE) {
+			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+				  cur->is_local ? "local" : "remote",
+				  cur->feat_num, cur->state);
+			goto activation_failed;
+		}
+		fvals[idx][cur->is_local] = &cur->val;
+	}
+
+	/*
+	 * Activate in decreasing order of index, so that the CCIDs are always
+	 * activated as the last feature. This avoids the case where a CCID
+	 * relies on the initialisation of one or more features that it depends
+	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
+	 */
+	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
+		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
+		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
+			DCCP_CRIT("Could not activate %d", idx);
+			goto activation_failed;
+		}
+
+	/* Clean up Change options which have been confirmed already */
+	list_for_each_entry_safe(cur, next, fn_list, node)
+		if (!cur->needs_confirm)
+			dccp_feat_list_pop(cur);
+
+	dccp_pr_debug("Activation OK\n");
+	return 0;
+
+activation_failed:
+	/*
+	 * We clean up everything that may have been allocated, since
+	 * it is difficult to track at which stage negotiation failed.
+	 * This is ok, since all allocation functions below are robust
+	 * against NULL arguments.
+	 */
+	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+	dp->dccps_hc_rx_ackvec = NULL;
+	return -1;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 const char *dccp_feat_typename(const u8 type)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 26/37] dccp: Integration of dynamic feature activation - part 1 (socket setup)
@ 2008-08-28 17:45                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This first patch out of three replaces the hardcoded default settings with
initialisation code for the dynamic feature negotiation.

Note on retransmitting Confirm options:
---------------------------------------
This patch also defers flushing the client feature-negotiation queue,
due to the following considerations.

As long as the client is in PARTOPEN, it needs to retransmit the Confirm
options for the Change options received on the DCCP-Response from the server.

Otherwise, if the packet containing the Confirm options gets dropped in the
network, the connection aborts due to undefined feature negotiation state.

Thanks to Leandro Melo de Sales who reported a bug in an earlier revision
of the patch set, resulting from not retransmitting the Confirm options.

The patch now ensures that the client feature-negotiation queue is flushed only
when entering the OPEN state. Since confirmed Change options are removed as
soon as they are confirmed (in the DCCP-Response), this ensures that Confirm
options are retransmitted.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/proto.c |   46 ++++++----------------------------------------
 1 files changed, 6 insertions(+), 40 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -67,6 +67,9 @@ void dccp_set_state(struct sock *sk, const int state)
 	case DCCP_OPEN:
 		if (oldstate != DCCP_OPEN)
 			DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+		/* Client retransmits all Confirm options until entering OPEN */
+		if (oldstate == DCCP_PARTOPEN)
+			dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
 		break;
 
 	case DCCP_CLOSED:
@@ -175,7 +178,6 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
 int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	dccp_minisock_init(&dp->dccps_minisock);
@@ -194,45 +196,9 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	dccp_init_xmit_timers(sk);
 
 	INIT_LIST_HEAD(&dp->dccps_featneg);
-	/*
-	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
-	 * the listening (master) sock get CCID control blocks, which is not
-	 * necessary, but for now, to not mess with the test userspace apps,
-	 * lets leave it here, later the real solution is to do this in a
-	 * setsockopt(CCIDs-I-want/accept). -acme
-	 */
-	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(sk);
-
-		if (rc)
-			return rc;
-
-		if (dmsk->dccpms_send_ack_vector) {
-			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
-			if (dp->dccps_hc_rx_ackvec == NULL)
-				return -ENOMEM;
-		}
-		dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
-						      sk, GFP_KERNEL);
-		dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
-						      sk, GFP_KERNEL);
-		if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
-			     dp->dccps_hc_tx_ccid == NULL)) {
-			ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-			ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-			if (dmsk->dccpms_send_ack_vector) {
-				dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-				dp->dccps_hc_rx_ackvec = NULL;
-			}
-			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		/* control socket doesn't need feat nego */
-		INIT_LIST_HEAD(&dmsk->dccpms_pending);
-		INIT_LIST_HEAD(&dmsk->dccpms_conf);
-	}
-
+	/* control socket doesn't need feat nego */
+	if (likely(ctl_sock_initialized))
+		return dccp_feat_init(sk);
 	return 0;
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 26/37] dccp: Integration of dynamic feature activation - part 1 (socket setup)
@ 2008-08-28 17:45                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This first patch out of three replaces the hardcoded default settings with
initialisation code for the dynamic feature negotiation.

Note on retransmitting Confirm options:
---------------------------------------
This patch also defers flushing the client feature-negotiation queue,
due to the following considerations.

As long as the client is in PARTOPEN, it needs to retransmit the Confirm
options for the Change options received on the DCCP-Response from the server.

Otherwise, if the packet containing the Confirm options gets dropped in the
network, the connection aborts due to undefined feature negotiation state.

Thanks to Leandro Melo de Sales who reported a bug in an earlier revision
of the patch set, resulting from not retransmitting the Confirm options.

The patch now ensures that the client feature-negotiation queue is flushed only
when entering the OPEN state. Since confirmed Change options are removed as
soon as they are confirmed (in the DCCP-Response), this ensures that Confirm
options are retransmitted.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/proto.c |   46 ++++++----------------------------------------
 1 files changed, 6 insertions(+), 40 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -67,6 +67,9 @@ void dccp_set_state(struct sock *sk, const int state)
 	case DCCP_OPEN:
 		if (oldstate != DCCP_OPEN)
 			DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+		/* Client retransmits all Confirm options until entering OPEN */
+		if (oldstate = DCCP_PARTOPEN)
+			dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
 		break;
 
 	case DCCP_CLOSED:
@@ -175,7 +178,6 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
 int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	dccp_minisock_init(&dp->dccps_minisock);
@@ -194,45 +196,9 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	dccp_init_xmit_timers(sk);
 
 	INIT_LIST_HEAD(&dp->dccps_featneg);
-	/*
-	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
-	 * the listening (master) sock get CCID control blocks, which is not
-	 * necessary, but for now, to not mess with the test userspace apps,
-	 * lets leave it here, later the real solution is to do this in a
-	 * setsockopt(CCIDs-I-want/accept). -acme
-	 */
-	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(sk);
-
-		if (rc)
-			return rc;
-
-		if (dmsk->dccpms_send_ack_vector) {
-			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
-			if (dp->dccps_hc_rx_ackvec = NULL)
-				return -ENOMEM;
-		}
-		dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
-						      sk, GFP_KERNEL);
-		dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
-						      sk, GFP_KERNEL);
-		if (unlikely(dp->dccps_hc_rx_ccid = NULL ||
-			     dp->dccps_hc_tx_ccid = NULL)) {
-			ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-			ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-			if (dmsk->dccpms_send_ack_vector) {
-				dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-				dp->dccps_hc_rx_ackvec = NULL;
-			}
-			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		/* control socket doesn't need feat nego */
-		INIT_LIST_HEAD(&dmsk->dccpms_pending);
-		INIT_LIST_HEAD(&dmsk->dccpms_conf);
-	}
-
+	/* control socket doesn't need feat nego */
+	if (likely(ctl_sock_initialized))
+		return dccp_feat_init(sk);
 	return 0;
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side)
@ 2008-08-28 17:45                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch integrates the activation of features at the end of negotiation
into the server-side code.

Note:
  In dccp_create_openreq_child the request_sock argument is no longer constant,
  since dccp_activate_values() uses the feature-negotiation list on dreq to sort
  out the initialisation values for the different features of the child socket;
  and purges this queue after use (but the `req' argument to openreq_child
  can and does still remain constant).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/minisocks.c |   42 ++++++++++++------------------------------
 1 files changed, 12 insertions(+), 30 deletions(-)

--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -111,7 +111,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 	struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
 	if (newsk != NULL) {
-		const struct dccp_request_sock *dreq = dccp_rsk(req);
+		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
 		struct dccp_minisock *newdmsk = dccp_msk(newsk);
@@ -125,35 +125,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
 		INIT_LIST_HEAD(&newdp->dccps_featneg);
-		if (dccp_feat_clone(sk, newsk))
-			goto out_free;
-
-		if (newdmsk->dccpms_send_ack_vector) {
-			newdp->dccps_hc_rx_ackvec =
-						dccp_ackvec_alloc(GFP_ATOMIC);
-			if (unlikely(newdp->dccps_hc_rx_ackvec == NULL))
-				goto out_free;
-		}
-
-		newdp->dccps_hc_rx_ccid =
-			    ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
-					   newsk, GFP_ATOMIC);
-		newdp->dccps_hc_tx_ccid =
-			    ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
-					   newsk, GFP_ATOMIC);
-		if (unlikely(newdp->dccps_hc_rx_ccid == NULL ||
-			     newdp->dccps_hc_tx_ccid == NULL)) {
-			dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-			ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
-			ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
-out_free:
-			/* It is still raw copy of parent, so invalidate
-			 * destructor and make plain sk_free() */
-			newsk->sk_destruct = NULL;
-			sk_free(newsk);
-			return NULL;
-		}
-
 		/*
 		 * Step 3: Process LISTEN state
 		 *
@@ -184,6 +155,17 @@ out_free:
 		dccp_set_seqno(&newdp->dccps_awl,
 			       max48(newdp->dccps_awl, newdp->dccps_iss));
 
+		/*
+		 * Activate features after initialising the sequence numbers,
+		 * since CCID initialisation may depend on GSS, ISR, ISS etc.
+		 */
+		if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
+			/* It is still raw copy of parent, so invalidate
+			 * destructor and make plain sk_free() */
+			newsk->sk_destruct = NULL;
+			sk_free(newsk);
+			return NULL;
+		}
 		dccp_init_xmit_timers(newsk);
 
 		DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side)
@ 2008-08-28 17:45                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This patch integrates the activation of features at the end of negotiation
into the server-side code.

Note:
  In dccp_create_openreq_child the request_sock argument is no longer constant,
  since dccp_activate_values() uses the feature-negotiation list on dreq to sort
  out the initialisation values for the different features of the child socket;
  and purges this queue after use (but the `req' argument to openreq_child
  can and does still remain constant).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/minisocks.c |   42 ++++++++++++------------------------------
 1 files changed, 12 insertions(+), 30 deletions(-)

--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -111,7 +111,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 	struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
 	if (newsk != NULL) {
-		const struct dccp_request_sock *dreq = dccp_rsk(req);
+		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
 		struct dccp_minisock *newdmsk = dccp_msk(newsk);
@@ -125,35 +125,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
 		INIT_LIST_HEAD(&newdp->dccps_featneg);
-		if (dccp_feat_clone(sk, newsk))
-			goto out_free;
-
-		if (newdmsk->dccpms_send_ack_vector) {
-			newdp->dccps_hc_rx_ackvec -						dccp_ackvec_alloc(GFP_ATOMIC);
-			if (unlikely(newdp->dccps_hc_rx_ackvec = NULL))
-				goto out_free;
-		}
-
-		newdp->dccps_hc_rx_ccid -			    ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
-					   newsk, GFP_ATOMIC);
-		newdp->dccps_hc_tx_ccid -			    ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
-					   newsk, GFP_ATOMIC);
-		if (unlikely(newdp->dccps_hc_rx_ccid = NULL ||
-			     newdp->dccps_hc_tx_ccid = NULL)) {
-			dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-			ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
-			ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
-out_free:
-			/* It is still raw copy of parent, so invalidate
-			 * destructor and make plain sk_free() */
-			newsk->sk_destruct = NULL;
-			sk_free(newsk);
-			return NULL;
-		}
-
 		/*
 		 * Step 3: Process LISTEN state
 		 *
@@ -184,6 +155,17 @@ out_free:
 		dccp_set_seqno(&newdp->dccps_awl,
 			       max48(newdp->dccps_awl, newdp->dccps_iss));
 
+		/*
+		 * Activate features after initialising the sequence numbers,
+		 * since CCID initialisation may depend on GSS, ISR, ISS etc.
+		 */
+		if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
+			/* It is still raw copy of parent, so invalidate
+			 * destructor and make plain sk_free() */
+			newsk->sk_destruct = NULL;
+			sk_free(newsk);
+			return NULL;
+		}
 		dccp_init_xmit_timers(newsk);
 
 		DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS);
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 28/37] dccp: Integration of dynamic feature activation - part 3 (client side)
@ 2008-08-28 17:45                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This integrates feature-activation in the client, with these details:

 1. When dccp_parse_options() fails, the reset code is already set, request_sent
    _state_process() currently overrides this with `Packet Error', which is not
    intended - so changed to use the reset code set in dccp_parse_options();

 2. There was a FIXME to change the error code when dccp_ackvec_add() fails.
    I have looked this up and found that:
    * the check whether ackno < ISN is already made earlier,
    * this Response is likely the 1st packet with an Ackno that the client gets,
    * so when dccp_ackvec_add() fails, the reason is likely not a packet error.

 3. When feature negotiation fails, the socket should be marked as not usable,
    so that the application is notified that an error occurs. This is achieved
    by a new label, which uses an error code of `Aborted' and which sets the
    socket state to CLOSED, as well as sk_err.

 4. Avoids parsing the Ack twice in Respond state by not doing option processing
    again in dccp_rcv_respond_partopen_state_process (as option processing has
    already been done on the request_sock in dccp_check_req).

Since this addresses congestion-control initialisation, a corresponding
FIXME has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/input.c |   30 ++++++++++++++++++++++++++----
 1 files changed, 26 insertions(+), 4 deletions(-)

--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -421,8 +421,13 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			goto out_invalid_packet;
 		}
 
+		/*
+		 * If option processing (Step 8) failed, return 1 here so that
+		 * dccp_v4_do_rcv() sends a Reset. The Reset code depends on
+		 * the option type and is set in dccp_parse_options().
+		 */
 		if (dccp_parse_options(sk, NULL, skb))
-			goto out_invalid_packet;
+			return 1;
 
 		/* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
 		if (likely(dp->dccps_options_received.dccpor_timestamp_echo))
@@ -475,6 +480,15 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 		 */
 		dccp_set_state(sk, DCCP_PARTOPEN);
 
+		/*
+		 * If feature negotiation was successful, activate features now;
+		 * an activation failure means that this host could not activate
+		 * one ore more features (e.g. insufficient memory), which would
+		 * leave at least one feature in an undefined state.
+		 */
+		if (dccp_feat_activate_values(sk, &dp->dccps_featneg))
+			goto unable_to_proceed;
+
 		/* Make sure socket is routed, for correct metrics. */
 		icsk->icsk_af_ops->rebuild_header(sk);
 
@@ -509,6 +523,16 @@ out_invalid_packet:
 	/* dccp_v4_do_rcv will send a reset */
 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
 	return 1;
+
+unable_to_proceed:
+	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_ABORTED;
+	/*
+	 * We mark this socket as no longer usable, so that the loop in
+	 * dccp_sendmsg() terminates and the application gets notified.
+	 */
+	dccp_set_state(sk, DCCP_CLOSED);
+	sk->sk_err = ECOMM;
+	return 1;
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -600,7 +624,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 	}
 
-	if (sk->sk_state != DCCP_REQUESTING) {
+	if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
 		if (dccp_check_seqno(sk, skb))
 			goto discard;
 
@@ -665,8 +689,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 
 	case DCCP_REQUESTING:
-		/* FIXME: do congestion control initialization */
-
 		queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
 		if (queued >= 0)
 			return queued;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 28/37] dccp: Integration of dynamic feature activation - part 3 (client side)
@ 2008-08-28 17:45                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This integrates feature-activation in the client, with these details:

 1. When dccp_parse_options() fails, the reset code is already set, request_sent
    _state_process() currently overrides this with `Packet Error', which is not
    intended - so changed to use the reset code set in dccp_parse_options();

 2. There was a FIXME to change the error code when dccp_ackvec_add() fails.
    I have looked this up and found that:
    * the check whether ackno < ISN is already made earlier,
    * this Response is likely the 1st packet with an Ackno that the client gets,
    * so when dccp_ackvec_add() fails, the reason is likely not a packet error.

 3. When feature negotiation fails, the socket should be marked as not usable,
    so that the application is notified that an error occurs. This is achieved
    by a new label, which uses an error code of `Aborted' and which sets the
    socket state to CLOSED, as well as sk_err.

 4. Avoids parsing the Ack twice in Respond state by not doing option processing
    again in dccp_rcv_respond_partopen_state_process (as option processing has
    already been done on the request_sock in dccp_check_req).

Since this addresses congestion-control initialisation, a corresponding
FIXME has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/input.c |   30 ++++++++++++++++++++++++++----
 1 files changed, 26 insertions(+), 4 deletions(-)

--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -421,8 +421,13 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			goto out_invalid_packet;
 		}
 
+		/*
+		 * If option processing (Step 8) failed, return 1 here so that
+		 * dccp_v4_do_rcv() sends a Reset. The Reset code depends on
+		 * the option type and is set in dccp_parse_options().
+		 */
 		if (dccp_parse_options(sk, NULL, skb))
-			goto out_invalid_packet;
+			return 1;
 
 		/* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
 		if (likely(dp->dccps_options_received.dccpor_timestamp_echo))
@@ -475,6 +480,15 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 		 */
 		dccp_set_state(sk, DCCP_PARTOPEN);
 
+		/*
+		 * If feature negotiation was successful, activate features now;
+		 * an activation failure means that this host could not activate
+		 * one ore more features (e.g. insufficient memory), which would
+		 * leave at least one feature in an undefined state.
+		 */
+		if (dccp_feat_activate_values(sk, &dp->dccps_featneg))
+			goto unable_to_proceed;
+
 		/* Make sure socket is routed, for correct metrics. */
 		icsk->icsk_af_ops->rebuild_header(sk);
 
@@ -509,6 +523,16 @@ out_invalid_packet:
 	/* dccp_v4_do_rcv will send a reset */
 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
 	return 1;
+
+unable_to_proceed:
+	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_ABORTED;
+	/*
+	 * We mark this socket as no longer usable, so that the loop in
+	 * dccp_sendmsg() terminates and the application gets notified.
+	 */
+	dccp_set_state(sk, DCCP_CLOSED);
+	sk->sk_err = ECOMM;
+	return 1;
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -600,7 +624,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 	}
 
-	if (sk->sk_state != DCCP_REQUESTING) {
+	if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
 		if (dccp_check_seqno(sk, skb))
 			goto discard;
 
@@ -665,8 +689,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 
 	case DCCP_REQUESTING:
-		/* FIXME: do congestion control initialization */
-
 		queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
 		if (queued >= 0)
 			return queued;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 29/37] dccp: Clean up old feature-negotiation infrastructure
@ 2008-08-28 17:45                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

The code removed by this patch is no longer referenced or used, the added
lines update documentation and copyrights.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  505 +------------------------------------------------------
 net/dccp/feat.h |   12 +-
 2 files changed, 12 insertions(+), 505 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1,8 +1,13 @@
 /*
  *  net/dccp/feat.c
  *
- *  An implementation of the DCCP protocol
- *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *
+ *  Copyright (c) 2008 The University of Aberdeen, Scotland, UK
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ *  Rewrote from scratch, some bits from earlier code by
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
  *
  *  ASSUMPTIONS
  *  -----------
@@ -17,14 +22,10 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-
 #include <linux/module.h>
-
 #include "ccid.h"
 #include "feat.h"
 
-#define DCCP_FEAT_SP_NOAGREE (-123)
-
 /*
  * Feature activation handlers.
  *
@@ -816,51 +817,6 @@ int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
 	return 0;
 }
 
-static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* figure out if we are changing our CCID or the peer's */
-	const int rx = type == DCCPO_CHANGE_R;
-	const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
-	struct ccid *new_ccid;
-
-	/* Check if nothing is being changed. */
-	if (ccid_nr == new_ccid_nr)
-		return 0;
-
-	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
-	if (new_ccid == NULL)
-		return -ENOMEM;
-
-	if (rx) {
-		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-		dp->dccps_hc_rx_ccid = new_ccid;
-		dmsk->dccpms_rx_ccid = new_ccid_nr;
-	} else {
-		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-		dp->dccps_hc_tx_ccid = new_ccid;
-		dmsk->dccpms_tx_ccid = new_ccid_nr;
-	}
-
-	return 0;
-}
-
-static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
-{
-	dccp_feat_debug(type, feat, val);
-
-	switch (feat) {
-	case DCCPF_CCID:
-		return dccp_feat_update_ccid(sk, type, val);
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n",
-			      dccp_feat_typename(type), feat);
-		break;
-	}
-	return 0;
-}
-
 /* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
 static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
 {
@@ -930,453 +886,6 @@ static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
 	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
 }
 
-#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
-static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
-			       u8 *rpref, u8 rlen)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	u8 *spref, slen, *res = NULL;
-	int i, j, rc, agree = 1;
-
-	BUG_ON(rpref == NULL);
-
-	/* check if we are the black sheep */
-	if (dp->dccps_role == DCCP_ROLE_CLIENT) {
-		spref = rpref;
-		slen  = rlen;
-		rpref = opt->dccpop_val;
-		rlen  = opt->dccpop_len;
-	} else {
-		spref = opt->dccpop_val;
-		slen  = opt->dccpop_len;
-	}
-	/*
-	 * Now we have server preference list in spref and client preference in
-	 * rpref
-	 */
-	BUG_ON(spref == NULL);
-	BUG_ON(rpref == NULL);
-
-	/* FIXME sanity check vals */
-
-	/* Are values in any order?  XXX Lame "algorithm" here */
-	for (i = 0; i < slen; i++) {
-		for (j = 0; j < rlen; j++) {
-			if (spref[i] == rpref[j]) {
-				res = &spref[i];
-				break;
-			}
-		}
-		if (res)
-			break;
-	}
-
-	/* we didn't agree on anything */
-	if (res == NULL) {
-		/* confirm previous value */
-		switch (opt->dccpop_feat) {
-		case DCCPF_CCID:
-			/* XXX did i get this right? =P */
-			if (opt->dccpop_type == DCCPO_CHANGE_L)
-				res = &dccp_msk(sk)->dccpms_tx_ccid;
-			else
-				res = &dccp_msk(sk)->dccpms_rx_ccid;
-			break;
-
-		default:
-			DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat);
-			/* XXX implement res */
-			return -EFAULT;
-		}
-
-		dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
-		agree = 0; /* this is used for mandatory options... */
-	}
-
-	/* need to put result and our preference list */
-	rlen = 1 + opt->dccpop_len;
-	rpref = kmalloc(rlen, GFP_ATOMIC);
-	if (rpref == NULL)
-		return -ENOMEM;
-
-	*rpref = *res;
-	memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
-
-	/* put it in the "confirm queue" */
-	if (opt->dccpop_sc == NULL) {
-		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
-		if (opt->dccpop_sc == NULL) {
-			kfree(rpref);
-			return -ENOMEM;
-		}
-	} else {
-		/* recycle the confirm slot */
-		BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
-		kfree(opt->dccpop_sc->dccpoc_val);
-		dccp_pr_debug("recycling confirm slot\n");
-	}
-	memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
-
-	opt->dccpop_sc->dccpoc_val = rpref;
-	opt->dccpop_sc->dccpoc_len = rlen;
-
-	/* update the option on our side [we are about to send the confirm] */
-	rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
-	if (rc) {
-		kfree(opt->dccpop_sc->dccpoc_val);
-		kfree(opt->dccpop_sc);
-		opt->dccpop_sc = NULL;
-		return rc;
-	}
-
-	dccp_pr_debug("Will confirm %d\n", *rpref);
-
-	/* say we want to change to X but we just got a confirm X, suppress our
-	 * change
-	 */
-	if (!opt->dccpop_conf) {
-		if (*opt->dccpop_val == *res)
-			opt->dccpop_conf = 1;
-		dccp_pr_debug("won't ask for change of same feature\n");
-	}
-
-	return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
-}
-
-static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt;
-	int rc = 1;
-	u8 t;
-
-	/*
-	 * We received a CHANGE.  We gotta match it against our own preference
-	 * list.  If we got a CHANGE_R it means it's a change for us, so we need
-	 * to compare our CHANGE_L list.
-	 */
-	if (type == DCCPO_CHANGE_L)
-		t = DCCPO_CHANGE_R;
-	else
-		t = DCCPO_CHANGE_L;
-
-	/* find our preference list for this feature */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (opt->dccpop_type != t || opt->dccpop_feat != feature)
-			continue;
-
-		/* find the winner from the two preference lists */
-		rc = dccp_feat_reconcile(sk, opt, val, len);
-		break;
-	}
-
-	/* We didn't deal with the change.  This can happen if we have no
-	 * preference list for the feature.  In fact, it just shouldn't
-	 * happen---if we understand a feature, we should have a preference list
-	 * with at least the default value.
-	 */
-	BUG_ON(rc == 1);
-
-	return rc;
-}
-
-static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	u8 *copy;
-	int rc;
-
-	/* NN features must be Change L (sec. 6.3.2) */
-	if (type != DCCPO_CHANGE_L) {
-		dccp_pr_debug("received %s for NN feature %d\n",
-				dccp_feat_typename(type), feature);
-		return -EFAULT;
-	}
-
-	/* XXX sanity check opt val */
-
-	/* copy option so we can confirm it */
-	opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-	if (opt == NULL)
-		return -ENOMEM;
-
-	copy = kmemdup(val, len, GFP_ATOMIC);
-	if (copy == NULL) {
-		kfree(opt);
-		return -ENOMEM;
-	}
-
-	opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = copy;
-	opt->dccpop_len	 = len;
-
-	/* change feature */
-	rc = dccp_feat_update(sk, type, feature, *val);
-	if (rc) {
-		kfree(opt->dccpop_val);
-		kfree(opt);
-		return rc;
-	}
-
-	dccp_feat_debug(type, feature, *copy);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-
-	return 0;
-}
-
-static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
-				    u8 type, u8 feature)
-{
-	/* XXX check if other confirms for that are queued and recycle slot */
-	struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-
-	if (opt == NULL) {
-		/* XXX what do we do?  Ignoring should be fine.  It's a change
-		 * after all =P
-		 */
-		return;
-	}
-
-	switch (type) {
-	case DCCPO_CHANGE_L:
-		opt->dccpop_type = DCCPO_CONFIRM_R;
-		break;
-	case DCCPO_CHANGE_R:
-		opt->dccpop_type = DCCPO_CONFIRM_L;
-		break;
-	default:
-		DCCP_WARN("invalid type %d\n", type);
-		kfree(opt);
-		return;
-	}
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = NULL;
-	opt->dccpop_len	 = 0;
-
-	/* change feature */
-	dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-}
-
-static void dccp_feat_flush_confirm(struct sock *sk)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* Check if there is anything to confirm in the first place */
-	int yes = !list_empty(&dmsk->dccpms_conf);
-
-	if (!yes) {
-		struct dccp_opt_pend *opt;
-
-		list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-			if (opt->dccpop_conf) {
-				yes = 1;
-				break;
-			}
-		}
-	}
-
-	if (!yes)
-		return;
-
-	/* OK there is something to confirm... */
-	/* XXX check if packet is in flight?  Send delayed ack?? */
-	if (sk->sk_state == DCCP_OPEN)
-		dccp_send_ack(sk);
-}
-
-int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	int rc;
-
-	/* Ignore Change requests other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* figure out if it's SP or NN feature */
-	switch (feature) {
-	/* deal with SP features */
-	case DCCPF_CCID:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_sp(sk, type, feature, val, len); */
-		break;
-
-	/* deal with NN features */
-	case DCCPF_ACK_RATIO:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_nn(sk, type, feature, val, len); */
-		break;
-
-	/* XXX implement other features */
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n",
-			      dccp_feat_typename(type), feature);
-		rc = -EFAULT;
-		break;
-	}
-
-	/* check if there were problems changing features */
-	if (rc) {
-		/* If we don't agree on SP, we sent a confirm for old value.
-		 * However we propagate rc to caller in case option was
-		 * mandatory
-		 */
-		if (rc != DCCP_FEAT_SP_NOAGREE)
-			dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
-	}
-
-	/* generate the confirm [if required] */
-	dccp_feat_flush_confirm(sk);
-
-	return rc;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-
-int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-			   u8 *val, u8 len)
-{
-	u8 t;
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	int found = 0;
-	int all_confirmed = 1;
-
-	/* Ignore Confirm options other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* locate our change request */
-	switch (type) {
-	case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
-	case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
-	default:	      DCCP_WARN("invalid type %d\n", type);
-			      return 1;
-
-	}
-	/* XXX sanity check feature value */
-
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (!opt->dccpop_conf && opt->dccpop_type == t &&
-		    opt->dccpop_feat == feature) {
-			found = 1;
-			dccp_pr_debug("feature %d found\n", opt->dccpop_feat);
-
-			/* XXX do sanity check */
-
-			opt->dccpop_conf = 1;
-
-			/* We got a confirmation---change the option */
-			dccp_feat_update(sk, opt->dccpop_type,
-					 opt->dccpop_feat, *val);
-
-			/* XXX check the return value of dccp_feat_update */
-			break;
-		}
-
-		if (!opt->dccpop_conf)
-			all_confirmed = 0;
-	}
-
-	if (!found)
-		dccp_pr_debug("%s(%d, ...) never requested\n",
-			      dccp_feat_typename(type), feature);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
-#endif	/* (later) */
-
-void dccp_feat_clean(struct dccp_minisock *dmsk)
-{
-	struct dccp_opt_pend *opt, *next;
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
-				 dccpop_node) {
-		BUG_ON(opt->dccpop_val == NULL);
-		kfree(opt->dccpop_val);
-
-		if (opt->dccpop_sc != NULL) {
-			BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-		}
-
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		BUG_ON(opt == NULL);
-		if (opt->dccpop_val != NULL)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clean);
-
-/* this is to be called only when a listening sock creates its child.  It is
- * assumed by the function---the confirm is not duplicated, but rather it is
- * "passed on".
- */
-int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
-{
-	struct dccp_minisock *olddmsk = dccp_msk(oldsk);
-	struct dccp_minisock *newdmsk = dccp_msk(newsk);
-	struct dccp_opt_pend *opt;
-	int rc = 0;
-
-	INIT_LIST_HEAD(&newdmsk->dccpms_pending);
-	INIT_LIST_HEAD(&newdmsk->dccpms_conf);
-
-	list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
-		struct dccp_opt_pend *newopt;
-		/* copy the value of the option */
-		u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC);
-
-		if (val == NULL)
-			goto out_clean;
-
-		newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC);
-		if (newopt == NULL) {
-			kfree(val);
-			goto out_clean;
-		}
-
-		/* insert the option */
-		newopt->dccpop_val = val;
-		list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
-
-		/* XXX what happens with backlogs and multiple connections at
-		 * once...
-		 */
-		/* the master socket no longer needs to worry about confirms */
-		opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
-
-		/* reset state for a new socket */
-		opt->dccpop_conf = 0;
-	}
-
-	/* XXX not doing anything about the conf queue */
-
-out:
-	return rc;
-
-out_clean:
-	dccp_feat_clean(newdmsk);
-	rc = -ENOMEM;
-	goto out;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clone);
-
 /**
  * dccp_feat_change_recv  -  Process incoming ChangeL/R options
  * @fn: feature-negotiation list to update
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -3,14 +3,14 @@
 /*
  *  net/dccp/feat.h
  *
- *  An implementation of the DCCP protocol
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
  *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
  *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License version 2 as
- *	published by the Free Software Foundation.
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
  */
-
 #include <linux/types.h>
 #include "dccp.h"
 
@@ -115,8 +115,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern void dccp_feat_clean(struct dccp_minisock *dmsk);
-extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 29/37] dccp: Clean up old feature-negotiation infrastructure
@ 2008-08-28 17:45                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

The code removed by this patch is no longer referenced or used, the added
lines update documentation and copyrights.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  505 +------------------------------------------------------
 net/dccp/feat.h |   12 +-
 2 files changed, 12 insertions(+), 505 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1,8 +1,13 @@
 /*
  *  net/dccp/feat.c
  *
- *  An implementation of the DCCP protocol
- *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *
+ *  Copyright (c) 2008 The University of Aberdeen, Scotland, UK
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ *  Rewrote from scratch, some bits from earlier code by
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
  *
  *  ASSUMPTIONS
  *  -----------
@@ -17,14 +22,10 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-
 #include <linux/module.h>
-
 #include "ccid.h"
 #include "feat.h"
 
-#define DCCP_FEAT_SP_NOAGREE (-123)
-
 /*
  * Feature activation handlers.
  *
@@ -816,51 +817,6 @@ int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
 	return 0;
 }
 
-static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* figure out if we are changing our CCID or the peer's */
-	const int rx = type = DCCPO_CHANGE_R;
-	const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
-	struct ccid *new_ccid;
-
-	/* Check if nothing is being changed. */
-	if (ccid_nr = new_ccid_nr)
-		return 0;
-
-	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
-	if (new_ccid = NULL)
-		return -ENOMEM;
-
-	if (rx) {
-		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-		dp->dccps_hc_rx_ccid = new_ccid;
-		dmsk->dccpms_rx_ccid = new_ccid_nr;
-	} else {
-		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-		dp->dccps_hc_tx_ccid = new_ccid;
-		dmsk->dccpms_tx_ccid = new_ccid_nr;
-	}
-
-	return 0;
-}
-
-static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
-{
-	dccp_feat_debug(type, feat, val);
-
-	switch (feat) {
-	case DCCPF_CCID:
-		return dccp_feat_update_ccid(sk, type, val);
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n",
-			      dccp_feat_typename(type), feat);
-		break;
-	}
-	return 0;
-}
-
 /* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
 static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
 {
@@ -930,453 +886,6 @@ static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
 	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
 }
 
-#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
-static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
-			       u8 *rpref, u8 rlen)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	u8 *spref, slen, *res = NULL;
-	int i, j, rc, agree = 1;
-
-	BUG_ON(rpref = NULL);
-
-	/* check if we are the black sheep */
-	if (dp->dccps_role = DCCP_ROLE_CLIENT) {
-		spref = rpref;
-		slen  = rlen;
-		rpref = opt->dccpop_val;
-		rlen  = opt->dccpop_len;
-	} else {
-		spref = opt->dccpop_val;
-		slen  = opt->dccpop_len;
-	}
-	/*
-	 * Now we have server preference list in spref and client preference in
-	 * rpref
-	 */
-	BUG_ON(spref = NULL);
-	BUG_ON(rpref = NULL);
-
-	/* FIXME sanity check vals */
-
-	/* Are values in any order?  XXX Lame "algorithm" here */
-	for (i = 0; i < slen; i++) {
-		for (j = 0; j < rlen; j++) {
-			if (spref[i] = rpref[j]) {
-				res = &spref[i];
-				break;
-			}
-		}
-		if (res)
-			break;
-	}
-
-	/* we didn't agree on anything */
-	if (res = NULL) {
-		/* confirm previous value */
-		switch (opt->dccpop_feat) {
-		case DCCPF_CCID:
-			/* XXX did i get this right? =P */
-			if (opt->dccpop_type = DCCPO_CHANGE_L)
-				res = &dccp_msk(sk)->dccpms_tx_ccid;
-			else
-				res = &dccp_msk(sk)->dccpms_rx_ccid;
-			break;
-
-		default:
-			DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat);
-			/* XXX implement res */
-			return -EFAULT;
-		}
-
-		dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
-		agree = 0; /* this is used for mandatory options... */
-	}
-
-	/* need to put result and our preference list */
-	rlen = 1 + opt->dccpop_len;
-	rpref = kmalloc(rlen, GFP_ATOMIC);
-	if (rpref = NULL)
-		return -ENOMEM;
-
-	*rpref = *res;
-	memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
-
-	/* put it in the "confirm queue" */
-	if (opt->dccpop_sc = NULL) {
-		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
-		if (opt->dccpop_sc = NULL) {
-			kfree(rpref);
-			return -ENOMEM;
-		}
-	} else {
-		/* recycle the confirm slot */
-		BUG_ON(opt->dccpop_sc->dccpoc_val = NULL);
-		kfree(opt->dccpop_sc->dccpoc_val);
-		dccp_pr_debug("recycling confirm slot\n");
-	}
-	memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
-
-	opt->dccpop_sc->dccpoc_val = rpref;
-	opt->dccpop_sc->dccpoc_len = rlen;
-
-	/* update the option on our side [we are about to send the confirm] */
-	rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
-	if (rc) {
-		kfree(opt->dccpop_sc->dccpoc_val);
-		kfree(opt->dccpop_sc);
-		opt->dccpop_sc = NULL;
-		return rc;
-	}
-
-	dccp_pr_debug("Will confirm %d\n", *rpref);
-
-	/* say we want to change to X but we just got a confirm X, suppress our
-	 * change
-	 */
-	if (!opt->dccpop_conf) {
-		if (*opt->dccpop_val = *res)
-			opt->dccpop_conf = 1;
-		dccp_pr_debug("won't ask for change of same feature\n");
-	}
-
-	return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
-}
-
-static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt;
-	int rc = 1;
-	u8 t;
-
-	/*
-	 * We received a CHANGE.  We gotta match it against our own preference
-	 * list.  If we got a CHANGE_R it means it's a change for us, so we need
-	 * to compare our CHANGE_L list.
-	 */
-	if (type = DCCPO_CHANGE_L)
-		t = DCCPO_CHANGE_R;
-	else
-		t = DCCPO_CHANGE_L;
-
-	/* find our preference list for this feature */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (opt->dccpop_type != t || opt->dccpop_feat != feature)
-			continue;
-
-		/* find the winner from the two preference lists */
-		rc = dccp_feat_reconcile(sk, opt, val, len);
-		break;
-	}
-
-	/* We didn't deal with the change.  This can happen if we have no
-	 * preference list for the feature.  In fact, it just shouldn't
-	 * happen---if we understand a feature, we should have a preference list
-	 * with at least the default value.
-	 */
-	BUG_ON(rc = 1);
-
-	return rc;
-}
-
-static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	u8 *copy;
-	int rc;
-
-	/* NN features must be Change L (sec. 6.3.2) */
-	if (type != DCCPO_CHANGE_L) {
-		dccp_pr_debug("received %s for NN feature %d\n",
-				dccp_feat_typename(type), feature);
-		return -EFAULT;
-	}
-
-	/* XXX sanity check opt val */
-
-	/* copy option so we can confirm it */
-	opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-	if (opt = NULL)
-		return -ENOMEM;
-
-	copy = kmemdup(val, len, GFP_ATOMIC);
-	if (copy = NULL) {
-		kfree(opt);
-		return -ENOMEM;
-	}
-
-	opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = copy;
-	opt->dccpop_len	 = len;
-
-	/* change feature */
-	rc = dccp_feat_update(sk, type, feature, *val);
-	if (rc) {
-		kfree(opt->dccpop_val);
-		kfree(opt);
-		return rc;
-	}
-
-	dccp_feat_debug(type, feature, *copy);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-
-	return 0;
-}
-
-static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
-				    u8 type, u8 feature)
-{
-	/* XXX check if other confirms for that are queued and recycle slot */
-	struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-
-	if (opt = NULL) {
-		/* XXX what do we do?  Ignoring should be fine.  It's a change
-		 * after all =P
-		 */
-		return;
-	}
-
-	switch (type) {
-	case DCCPO_CHANGE_L:
-		opt->dccpop_type = DCCPO_CONFIRM_R;
-		break;
-	case DCCPO_CHANGE_R:
-		opt->dccpop_type = DCCPO_CONFIRM_L;
-		break;
-	default:
-		DCCP_WARN("invalid type %d\n", type);
-		kfree(opt);
-		return;
-	}
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = NULL;
-	opt->dccpop_len	 = 0;
-
-	/* change feature */
-	dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-}
-
-static void dccp_feat_flush_confirm(struct sock *sk)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* Check if there is anything to confirm in the first place */
-	int yes = !list_empty(&dmsk->dccpms_conf);
-
-	if (!yes) {
-		struct dccp_opt_pend *opt;
-
-		list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-			if (opt->dccpop_conf) {
-				yes = 1;
-				break;
-			}
-		}
-	}
-
-	if (!yes)
-		return;
-
-	/* OK there is something to confirm... */
-	/* XXX check if packet is in flight?  Send delayed ack?? */
-	if (sk->sk_state = DCCP_OPEN)
-		dccp_send_ack(sk);
-}
-
-int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	int rc;
-
-	/* Ignore Change requests other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* figure out if it's SP or NN feature */
-	switch (feature) {
-	/* deal with SP features */
-	case DCCPF_CCID:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_sp(sk, type, feature, val, len); */
-		break;
-
-	/* deal with NN features */
-	case DCCPF_ACK_RATIO:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_nn(sk, type, feature, val, len); */
-		break;
-
-	/* XXX implement other features */
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n",
-			      dccp_feat_typename(type), feature);
-		rc = -EFAULT;
-		break;
-	}
-
-	/* check if there were problems changing features */
-	if (rc) {
-		/* If we don't agree on SP, we sent a confirm for old value.
-		 * However we propagate rc to caller in case option was
-		 * mandatory
-		 */
-		if (rc != DCCP_FEAT_SP_NOAGREE)
-			dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
-	}
-
-	/* generate the confirm [if required] */
-	dccp_feat_flush_confirm(sk);
-
-	return rc;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-
-int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-			   u8 *val, u8 len)
-{
-	u8 t;
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	int found = 0;
-	int all_confirmed = 1;
-
-	/* Ignore Confirm options other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* locate our change request */
-	switch (type) {
-	case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
-	case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
-	default:	      DCCP_WARN("invalid type %d\n", type);
-			      return 1;
-
-	}
-	/* XXX sanity check feature value */
-
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (!opt->dccpop_conf && opt->dccpop_type = t &&
-		    opt->dccpop_feat = feature) {
-			found = 1;
-			dccp_pr_debug("feature %d found\n", opt->dccpop_feat);
-
-			/* XXX do sanity check */
-
-			opt->dccpop_conf = 1;
-
-			/* We got a confirmation---change the option */
-			dccp_feat_update(sk, opt->dccpop_type,
-					 opt->dccpop_feat, *val);
-
-			/* XXX check the return value of dccp_feat_update */
-			break;
-		}
-
-		if (!opt->dccpop_conf)
-			all_confirmed = 0;
-	}
-
-	if (!found)
-		dccp_pr_debug("%s(%d, ...) never requested\n",
-			      dccp_feat_typename(type), feature);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
-#endif	/* (later) */
-
-void dccp_feat_clean(struct dccp_minisock *dmsk)
-{
-	struct dccp_opt_pend *opt, *next;
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
-				 dccpop_node) {
-		BUG_ON(opt->dccpop_val = NULL);
-		kfree(opt->dccpop_val);
-
-		if (opt->dccpop_sc != NULL) {
-			BUG_ON(opt->dccpop_sc->dccpoc_val = NULL);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-		}
-
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		BUG_ON(opt = NULL);
-		if (opt->dccpop_val != NULL)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clean);
-
-/* this is to be called only when a listening sock creates its child.  It is
- * assumed by the function---the confirm is not duplicated, but rather it is
- * "passed on".
- */
-int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
-{
-	struct dccp_minisock *olddmsk = dccp_msk(oldsk);
-	struct dccp_minisock *newdmsk = dccp_msk(newsk);
-	struct dccp_opt_pend *opt;
-	int rc = 0;
-
-	INIT_LIST_HEAD(&newdmsk->dccpms_pending);
-	INIT_LIST_HEAD(&newdmsk->dccpms_conf);
-
-	list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
-		struct dccp_opt_pend *newopt;
-		/* copy the value of the option */
-		u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC);
-
-		if (val = NULL)
-			goto out_clean;
-
-		newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC);
-		if (newopt = NULL) {
-			kfree(val);
-			goto out_clean;
-		}
-
-		/* insert the option */
-		newopt->dccpop_val = val;
-		list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
-
-		/* XXX what happens with backlogs and multiple connections at
-		 * once...
-		 */
-		/* the master socket no longer needs to worry about confirms */
-		opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
-
-		/* reset state for a new socket */
-		opt->dccpop_conf = 0;
-	}
-
-	/* XXX not doing anything about the conf queue */
-
-out:
-	return rc;
-
-out_clean:
-	dccp_feat_clean(newdmsk);
-	rc = -ENOMEM;
-	goto out;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clone);
-
 /**
  * dccp_feat_change_recv  -  Process incoming ChangeL/R options
  * @fn: feature-negotiation list to update
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -3,14 +3,14 @@
 /*
  *  net/dccp/feat.h
  *
- *  An implementation of the DCCP protocol
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
  *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
  *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License version 2 as
- *	published by the Free Software Foundation.
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
  */
-
 #include <linux/types.h>
 #include "dccp.h"
 
@@ -115,8 +115,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern void dccp_feat_clean(struct dccp_minisock *dmsk);
-extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 30/37] dccp: Remove obsolete parts of the old CCID interface
@ 2008-08-28 17:45                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

The TX/RX CCIDs of the minisock are now redundant: similar to the Ack Vector
case, their value equals initially that of the sysctl, but at the end of
feature negotiation may be something different.

The old interface removed by this patch thus has been replaced by the newer
interface to dynamically query the currently loaded CCIDs earlier in this
patch set.

Also removed the constructors for the TX CCID and the RX CCID, since the
switch rx/non-rx is done by the handler in minisocks.c (and the handler is
the only place in the code where CCIDs are loaded).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    5 +++--
 include/linux/dccp.h              |    3 ---
 net/dccp/ccid.c                   |   14 --------------
 net/dccp/ccid.h                   |    5 -----
 net/dccp/feat.c                   |   12 ------------
 net/dccp/minisocks.c              |    2 --
 6 files changed, 3 insertions(+), 38 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -140,10 +140,11 @@ send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
 tx_ccid = 2
-	Default CCID for the sender-receiver half-connection.
+	Default CCID for the sender-receiver half-connection. Depending on the
+	choice of CCID, the Send Ack Vector feature is enabled automatically.
 
 rx_ccid = 2
-	Default CCID for the receiver-sender half-connection.
+	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
 	The initial sequence window (sec. 7.5.2).
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -370,7 +370,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
@@ -378,8 +377,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_rx_ccid;
-	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -253,20 +253,6 @@ out_module_put:
 
 EXPORT_SYMBOL_GPL(ccid_new);
 
-struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
-{
-	return ccid_new(id, sk, 1, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
-
-struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk,  gfp_t gfp)
-{
-	return ccid_new(id, sk, 0, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
-
 static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 {
 	struct ccid_operations *ccid_ops;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -111,11 +111,6 @@ extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-
 static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
 {
 	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1131,18 +1131,6 @@ int dccp_feat_init(struct sock *sk)
 	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
 	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
-	/* CCID L */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
-				&dmsk->dccpms_tx_ccid, 1);
-	if (rc)
-		goto out;
-
-	/* CCID R */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
-				&dmsk->dccpms_rx_ccid, 1);
-	if (rc)
-		goto out;
-
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
 				dp->dccps_l_ack_ratio);
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,8 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
-	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 30/37] dccp: Remove obsolete parts of the old CCID interface
@ 2008-08-28 17:45                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

The TX/RX CCIDs of the minisock are now redundant: similar to the Ack Vector
case, their value equals initially that of the sysctl, but at the end of
feature negotiation may be something different.

The old interface removed by this patch thus has been replaced by the newer
interface to dynamically query the currently loaded CCIDs earlier in this
patch set.

Also removed the constructors for the TX CCID and the RX CCID, since the
switch rx/non-rx is done by the handler in minisocks.c (and the handler is
the only place in the code where CCIDs are loaded).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    5 +++--
 include/linux/dccp.h              |    3 ---
 net/dccp/ccid.c                   |   14 --------------
 net/dccp/ccid.h                   |    5 -----
 net/dccp/feat.c                   |   12 ------------
 net/dccp/minisocks.c              |    2 --
 6 files changed, 3 insertions(+), 38 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -140,10 +140,11 @@ send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
 tx_ccid = 2
-	Default CCID for the sender-receiver half-connection.
+	Default CCID for the sender-receiver half-connection. Depending on the
+	choice of CCID, the Send Ack Vector feature is enabled automatically.
 
 rx_ccid = 2
-	Default CCID for the receiver-sender half-connection.
+	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
 	The initial sequence window (sec. 7.5.2).
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -370,7 +370,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
@@ -378,8 +377,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_rx_ccid;
-	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -253,20 +253,6 @@ out_module_put:
 
 EXPORT_SYMBOL_GPL(ccid_new);
 
-struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
-{
-	return ccid_new(id, sk, 1, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
-
-struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk,  gfp_t gfp)
-{
-	return ccid_new(id, sk, 0, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
-
 static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 {
 	struct ccid_operations *ccid_ops;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -111,11 +111,6 @@ extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-
 static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
 {
 	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1131,18 +1131,6 @@ int dccp_feat_init(struct sock *sk)
 	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
 	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
-	/* CCID L */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
-				&dmsk->dccpms_tx_ccid, 1);
-	if (rc)
-		goto out;
-
-	/* CCID R */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
-				&dmsk->dccpms_rx_ccid, 1);
-	if (rc)
-		goto out;
-
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
 				dp->dccps_l_ack_ratio);
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,8 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
-	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 31/37] dccp: Remove manual influence on NDP Count feature
@ 2008-08-28 17:45                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

Updating the NDP count feature is handled automatically now:
 * for CCID-2 it is disabled, since the code does not use NDP counts;
 * for CCID-3 it is enabled, as NDP counts are used to determine loss lengths.

Allowing the user to change NDP values leads to unpredictable and failing
behaviour, since it is then possible to disable NDP counts even when they
are needed (e.g. in CCID-3).

This means that only those user settings are sensible that agree with the
values for Send NDP Count implied by the choice of CCID. But those settings
are already activated by the feature negotiation (CCID dependency tracking),
hence this form of support is redundant.

At startup the initialisation of the NDP count feature is with the default
value of 0, which is done implicitly by the zeroing-out of the socket when
it is allocated. If the choice of CCID or feature negotiation enables NDP
count, this will then be updated via the NDP activation handler.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    4 ++--
 net/dccp/dccp.h                   |    1 -
 net/dccp/feat.c                   |    2 +-
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    4 +---
 net/dccp/sysctl.c                 |    7 -------
 7 files changed, 4 insertions(+), 18 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ndp = 1
-	Whether or not to send NDP count options (sec. 7.7.2).
-
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -371,14 +371,12 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
-  * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
 	__u8			dccpms_send_ack_vector;
-	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
@@ -490,6 +488,7 @@ struct dccp_ackvec;
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
+ * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
@@ -529,6 +528,7 @@ struct dccp_sock {
 	__u16				dccps_r_ack_ratio;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
+	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -99,7 +99,6 @@ extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_feat_send_ack_vector;
-extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -86,7 +86,7 @@ static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
 static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
 {
 	if (!rx)
-		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+		dccp_sk(sk)->dccps_send_ndp_count = (enable > 0);
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -46,7 +46,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
-	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -27,7 +27,6 @@ int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
-int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -531,8 +530,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-	if (dmsk->dccpms_send_ndp_count &&
-	    dccp_insert_option_ndp(sk, skb))
+	if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
 		return -1;
 
 	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -48,13 +48,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ndp",
-		.data		= &sysctl_dccp_feat_send_ndp_count,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ndp_count),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 31/37] dccp: Remove manual influence on NDP Count feature
@ 2008-08-28 17:45                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

Updating the NDP count feature is handled automatically now:
 * for CCID-2 it is disabled, since the code does not use NDP counts;
 * for CCID-3 it is enabled, as NDP counts are used to determine loss lengths.

Allowing the user to change NDP values leads to unpredictable and failing
behaviour, since it is then possible to disable NDP counts even when they
are needed (e.g. in CCID-3).

This means that only those user settings are sensible that agree with the
values for Send NDP Count implied by the choice of CCID. But those settings
are already activated by the feature negotiation (CCID dependency tracking),
hence this form of support is redundant.

At startup the initialisation of the NDP count feature is with the default
value of 0, which is done implicitly by the zeroing-out of the socket when
it is allocated. If the choice of CCID or feature negotiation enables NDP
count, this will then be updated via the NDP activation handler.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    4 ++--
 net/dccp/dccp.h                   |    1 -
 net/dccp/feat.c                   |    2 +-
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    4 +---
 net/dccp/sysctl.c                 |    7 -------
 7 files changed, 4 insertions(+), 18 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ndp = 1
-	Whether or not to send NDP count options (sec. 7.7.2).
-
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -371,14 +371,12 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
-  * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
 	__u8			dccpms_send_ack_vector;
-	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
@@ -490,6 +488,7 @@ struct dccp_ackvec;
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
+ * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
@@ -529,6 +528,7 @@ struct dccp_sock {
 	__u16				dccps_r_ack_ratio;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
+	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -99,7 +99,6 @@ extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_feat_send_ack_vector;
-extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -86,7 +86,7 @@ static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
 static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
 {
 	if (!rx)
-		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+		dccp_sk(sk)->dccps_send_ndp_count = (enable > 0);
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -46,7 +46,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
-	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -27,7 +27,6 @@ int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
-int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -531,8 +530,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-	if (dmsk->dccpms_send_ndp_count &&
-	    dccp_insert_option_ndp(sk, skb))
+	if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
 		return -1;
 
 	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -48,13 +48,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ndp",
-		.data		= &sysctl_dccp_feat_send_ndp_count,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ndp_count),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 32/37] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl
@ 2008-08-28 17:45                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This removes the use of the sysctl and the minisock variable for the Send Ack
Vector feature, which is now handled fully dynamically via feature negotiation;
i.e. when CCID2 is enabled, Ack Vectors are automatically enabled (as per
RFC 4341, 4.).

Using a sysctl in parallel to this implementation would open the door to
crashes, since much of the code relies on tests of the boolean minisock /
sysctl variable. Thus, this patch replaces all tests of type

	if (dccp_msk(sk)->dccpms_send_ack_vector)
		/* ... */
with
	if (dp->dccps_hc_rx_ackvec != NULL)
		/* ... */

The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
negotiation concluded that Ack Vectors are to be used on the half-connection.
Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
so that the test is a valid one.

The activation handler for Ack Vectors is called as soon as the feature
negotiation has concluded at the
 * server when the Ack marking the transition RESPOND => OPEN arrives;
 * client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.

Adding the sequence number of the Response packet to the Ack Vector has been
removed, since
 (a) connection establishment implies that the Response has been received;
 (b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
     this entry will always be ignored;
 (c) it can not be used for anything useful - to detect loss for instance, only
     packets received after the loss can serve as pseudo-dupacks.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    3 ---
 net/dccp/dccp.h                   |    3 +--
 net/dccp/diag.c                   |    2 +-
 net/dccp/input.c                  |   12 +++---------
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    7 ++-----
 net/dccp/proto.c                  |    3 +--
 net/dccp/sysctl.c                 |    7 -------
 9 files changed, 8 insertions(+), 33 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ackvec = 1
-	Whether or not to send Ack Vector options (sec. 11.5).
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection. Depending on the
 	choice of CCID, the Send Ack Vector feature is enabled automatically.
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -360,7 +360,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
 #define DCCPF_INITIAL_ACK_RATIO			2
 #define DCCPF_INITIAL_CCID			DCCPC_CCID2
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -370,13 +369,11 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_send_ack_vector;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
@@ -434,7 +433,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	const struct dccp_sock *dp = dccp_sk(sk);
 	return dp->dccps_timestamp_echo != 0 ||
 #ifdef CONFIG_IP_DCCP_ACKVEC
-	       (dccp_msk(sk)->dccpms_send_ack_vector &&
+	       (dp->dccps_hc_rx_ackvec != NULL &&
 		dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 #endif
 	       inet_csk_ack_scheduled(sk);
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -29,7 +29,7 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info)
 	info->tcpi_backoff	= icsk->icsk_backoff;
 	info->tcpi_pmtu		= icsk->icsk_pmtu_cookie;
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		info->tcpi_options |= TCPI_OPT_SACK;
 
 	ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -163,7 +163,7 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
 					    DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
@@ -375,7 +375,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
 	if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 		dccp_event_ack_recv(sk, skb);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector &&
+	if (dp->dccps_hc_rx_ackvec != NULL &&
 	    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 			    DCCP_SKB_CB(skb)->dccpd_seq,
 			    DCCP_ACKVEC_STATE_RECEIVED))
@@ -434,12 +434,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp -
 			    dp->dccps_options_received.dccpor_timestamp_echo));
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
-		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
-				    DCCP_SKB_CB(skb)->dccpd_seq,
-				    DCCP_ACKVEC_STATE_RECEIVED))
-			goto out_invalid_packet; /* FIXME: change error code */
-
 		/* Stop the REQUEST timer */
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
 		WARN_ON(sk->sk_send_head == NULL);
@@ -637,7 +631,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 			dccp_event_ack_recv(sk, skb);
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
+		if (dp->dccps_hc_rx_ackvec != NULL &&
 		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 				    DCCP_SKB_CB(skb)->dccpd_seq,
 				    DCCP_ACKVEC_STATE_RECEIVED))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,7 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -145,8 +144,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
 				break;
-
-			if (dccp_msk(sk)->dccpms_send_ack_vector &&
+			if (dp->dccps_hc_rx_ackvec != NULL &&
 			    dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
 				goto out_invalid_option;
 			break;
@@ -526,7 +524,6 @@ static void dccp_insert_option_padding(struct sk_buff *skb)
 int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
@@ -547,7 +544,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 			if (dccp_insert_option_timestamp(sk, skb))
 				return -1;
 
-		} else if (dmsk->dccpms_send_ack_vector	&&
+		} else if (dp->dccps_hc_rx_ackvec != NULL &&
 			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
 			   dccp_insert_option_ackvec(sk, skb)) {
 				return -1;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -207,7 +207,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
 void dccp_destroy_sock(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	/*
 	 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -225,7 +224,7 @@ void dccp_destroy_sock(struct sock *sk)
 	kfree(dp->dccps_service_list);
 	dp->dccps_service_list = NULL;
 
-	if (dmsk->dccpms_send_ack_vector) {
+	if (dp->dccps_hc_rx_ackvec != NULL) {
 		dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
 		dp->dccps_hc_rx_ackvec = NULL;
 	}
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ackvec",
-		.data		= &sysctl_dccp_feat_send_ack_vector,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 32/37] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl
@ 2008-08-28 17:45                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This removes the use of the sysctl and the minisock variable for the Send Ack
Vector feature, which is now handled fully dynamically via feature negotiation;
i.e. when CCID2 is enabled, Ack Vectors are automatically enabled (as per
RFC 4341, 4.).

Using a sysctl in parallel to this implementation would open the door to
crashes, since much of the code relies on tests of the boolean minisock /
sysctl variable. Thus, this patch replaces all tests of type

	if (dccp_msk(sk)->dccpms_send_ack_vector)
		/* ... */
with
	if (dp->dccps_hc_rx_ackvec != NULL)
		/* ... */

The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
negotiation concluded that Ack Vectors are to be used on the half-connection.
Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
so that the test is a valid one.

The activation handler for Ack Vectors is called as soon as the feature
negotiation has concluded at the
 * server when the Ack marking the transition RESPOND => OPEN arrives;
 * client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.

Adding the sequence number of the Response packet to the Ack Vector has been
removed, since
 (a) connection establishment implies that the Response has been received;
 (b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
     this entry will always be ignored;
 (c) it can not be used for anything useful - to detect loss for instance, only
     packets received after the loss can serve as pseudo-dupacks.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    3 ---
 net/dccp/dccp.h                   |    3 +--
 net/dccp/diag.c                   |    2 +-
 net/dccp/input.c                  |   12 +++---------
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    7 ++-----
 net/dccp/proto.c                  |    3 +--
 net/dccp/sysctl.c                 |    7 -------
 9 files changed, 8 insertions(+), 33 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ackvec = 1
-	Whether or not to send Ack Vector options (sec. 11.5).
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection. Depending on the
 	choice of CCID, the Send Ack Vector feature is enabled automatically.
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -360,7 +360,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
 #define DCCPF_INITIAL_ACK_RATIO			2
 #define DCCPF_INITIAL_CCID			DCCPC_CCID2
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -370,13 +369,11 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_send_ack_vector;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
@@ -434,7 +433,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	const struct dccp_sock *dp = dccp_sk(sk);
 	return dp->dccps_timestamp_echo != 0 ||
 #ifdef CONFIG_IP_DCCP_ACKVEC
-	       (dccp_msk(sk)->dccpms_send_ack_vector &&
+	       (dp->dccps_hc_rx_ackvec != NULL &&
 		dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 #endif
 	       inet_csk_ack_scheduled(sk);
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -29,7 +29,7 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info)
 	info->tcpi_backoff	= icsk->icsk_backoff;
 	info->tcpi_pmtu		= icsk->icsk_pmtu_cookie;
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		info->tcpi_options |= TCPI_OPT_SACK;
 
 	ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -163,7 +163,7 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
 					    DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
@@ -375,7 +375,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
 	if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 		dccp_event_ack_recv(sk, skb);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector &&
+	if (dp->dccps_hc_rx_ackvec != NULL &&
 	    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 			    DCCP_SKB_CB(skb)->dccpd_seq,
 			    DCCP_ACKVEC_STATE_RECEIVED))
@@ -434,12 +434,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp -
 			    dp->dccps_options_received.dccpor_timestamp_echo));
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
-		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
-				    DCCP_SKB_CB(skb)->dccpd_seq,
-				    DCCP_ACKVEC_STATE_RECEIVED))
-			goto out_invalid_packet; /* FIXME: change error code */
-
 		/* Stop the REQUEST timer */
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
 		WARN_ON(sk->sk_send_head = NULL);
@@ -637,7 +631,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 			dccp_event_ack_recv(sk, skb);
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
+		if (dp->dccps_hc_rx_ackvec != NULL &&
 		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 				    DCCP_SKB_CB(skb)->dccpd_seq,
 				    DCCP_ACKVEC_STATE_RECEIVED))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,7 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -145,8 +144,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
 				break;
-
-			if (dccp_msk(sk)->dccpms_send_ack_vector &&
+			if (dp->dccps_hc_rx_ackvec != NULL &&
 			    dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
 				goto out_invalid_option;
 			break;
@@ -526,7 +524,6 @@ static void dccp_insert_option_padding(struct sk_buff *skb)
 int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
@@ -547,7 +544,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 			if (dccp_insert_option_timestamp(sk, skb))
 				return -1;
 
-		} else if (dmsk->dccpms_send_ack_vector	&&
+		} else if (dp->dccps_hc_rx_ackvec != NULL &&
 			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
 			   dccp_insert_option_ackvec(sk, skb)) {
 				return -1;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -207,7 +207,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
 void dccp_destroy_sock(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	/*
 	 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -225,7 +224,7 @@ void dccp_destroy_sock(struct sock *sk)
 	kfree(dp->dccps_service_list);
 	dp->dccps_service_list = NULL;
 
-	if (dmsk->dccpms_send_ack_vector) {
+	if (dp->dccps_hc_rx_ackvec != NULL) {
 		dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
 		dp->dccps_hc_rx_ackvec = NULL;
 	}
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ackvec",
-		.data		= &sysctl_dccp_feat_send_ack_vector,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 33/37] dccp: Initialisation framework for feature negotiation
@ 2008-08-28 17:45                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This initialises feature negotiation from two tables, which are initialised
from sysctls.

As a novel feature, specifics of the implementation (e.g. currently short
seqnos and ECN are not supported) are advertised for robustness.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |   19 --------------
 net/dccp/feat.c      |   66 ++++++++++++++++++++++++++++++++++++++++++-------
 net/dccp/feat.h      |    2 +-
 3 files changed, 57 insertions(+), 30 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -369,28 +369,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_pending - List of features being negotiated
-  * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	struct list_head	dccpms_pending;
-	struct list_head	dccpms_conf;
-};
-
-struct dccp_opt_conf {
-	__u8			*dccpoc_val;
-	__u8			dccpoc_len;
-};
-
-struct dccp_opt_pend {
-	struct list_head	dccpop_node;
-	__u8			dccpop_type;
-	__u8			dccpop_feat;
-	__u8		        *dccpop_val;
-	__u8			dccpop_len;
-	int			dccpop_conf;
-	struct dccp_opt_conf    *dccpop_sc;
 };
 
 extern void dccp_minisock_init(struct dccp_minisock *dmsk);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1122,24 +1122,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 	return 0;	/* ignore FN options in all other states */
 }
 
+/**
+ * dccp_feat_init  -  Seed feature negotiation with host-specific defaults
+ * This initialises global defaults, depending on the value of the sysctls.
+ * These can later be overridden by registering changes via setsockopt calls.
+ * The last link in the chain is finalise_settings, to make sure that between
+ * here and the start of actual feature negotiation no inconsistencies enter.
+ *
+ * All features not appearing below use either defaults or are otherwise
+ * later adjusted through dccp_feat_finalise_settings().
+ */
 int dccp_feat_init(struct sock *sk)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
+	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+	u8 on = 1, off = 0;
 	int rc;
+	struct {
+		u8 *val;
+		u8 len;
+	} tx, rx;
+
+	/* Non-negotiable (NN) features */
+	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
+				    sysctl_dccp_feat_sequence_window);
+	if (rc)
+		return rc;
+
+	/* Server-priority (SP) features */
+
+	/* Advertise that short seqnos are not supported (7.6.1) */
+	rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
+	if (rc)
+		return rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
+	/* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
+	rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
+	if (rc)
+		return rc;
+
+	/*
+	 * We advertise the available list of CCIDs and reorder according to
+	 * preferences, to avoid failure resulting from negotiating different
+	 * singleton values (which always leads to failure).
+	 * These settings can still (later) be overridden via sockopts.
+	 */
+	if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
+	    ccid_get_builtin_ccids(&rx.val, &rx.len))
+		return -ENOBUFS;
 
-	/* Ack ratio */
-	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dp->dccps_l_ack_ratio);
-out:
+	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
+	if (rc)
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
+
+free_ccid_lists:
+	kfree(tx.val);
+	kfree(rx.val);
 	return rc;
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_init);
-
 int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -110,13 +110,13 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
+extern int  dccp_feat_init(struct sock *sk);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct sock *sk);
 
 /*
  * Encoding variable-length options and their maximum length.
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 33/37] dccp: Initialisation framework for feature negotiation
@ 2008-08-28 17:45                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This initialises feature negotiation from two tables, which are initialised
from sysctls.

As a novel feature, specifics of the implementation (e.g. currently short
seqnos and ECN are not supported) are advertised for robustness.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |   19 --------------
 net/dccp/feat.c      |   66 ++++++++++++++++++++++++++++++++++++++++++-------
 net/dccp/feat.h      |    2 +-
 3 files changed, 57 insertions(+), 30 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -369,28 +369,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_pending - List of features being negotiated
-  * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	struct list_head	dccpms_pending;
-	struct list_head	dccpms_conf;
-};
-
-struct dccp_opt_conf {
-	__u8			*dccpoc_val;
-	__u8			dccpoc_len;
-};
-
-struct dccp_opt_pend {
-	struct list_head	dccpop_node;
-	__u8			dccpop_type;
-	__u8			dccpop_feat;
-	__u8		        *dccpop_val;
-	__u8			dccpop_len;
-	int			dccpop_conf;
-	struct dccp_opt_conf    *dccpop_sc;
 };
 
 extern void dccp_minisock_init(struct dccp_minisock *dmsk);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1122,24 +1122,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 	return 0;	/* ignore FN options in all other states */
 }
 
+/**
+ * dccp_feat_init  -  Seed feature negotiation with host-specific defaults
+ * This initialises global defaults, depending on the value of the sysctls.
+ * These can later be overridden by registering changes via setsockopt calls.
+ * The last link in the chain is finalise_settings, to make sure that between
+ * here and the start of actual feature negotiation no inconsistencies enter.
+ *
+ * All features not appearing below use either defaults or are otherwise
+ * later adjusted through dccp_feat_finalise_settings().
+ */
 int dccp_feat_init(struct sock *sk)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
+	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+	u8 on = 1, off = 0;
 	int rc;
+	struct {
+		u8 *val;
+		u8 len;
+	} tx, rx;
+
+	/* Non-negotiable (NN) features */
+	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
+				    sysctl_dccp_feat_sequence_window);
+	if (rc)
+		return rc;
+
+	/* Server-priority (SP) features */
+
+	/* Advertise that short seqnos are not supported (7.6.1) */
+	rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
+	if (rc)
+		return rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
+	/* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
+	rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
+	if (rc)
+		return rc;
+
+	/*
+	 * We advertise the available list of CCIDs and reorder according to
+	 * preferences, to avoid failure resulting from negotiating different
+	 * singleton values (which always leads to failure).
+	 * These settings can still (later) be overridden via sockopts.
+	 */
+	if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
+	    ccid_get_builtin_ccids(&rx.val, &rx.len))
+		return -ENOBUFS;
 
-	/* Ack ratio */
-	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dp->dccps_l_ack_ratio);
-out:
+	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
+	if (rc)
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
+
+free_ccid_lists:
+	kfree(tx.val);
+	kfree(rx.val);
 	return rc;
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_init);
-
 int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -110,13 +110,13 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
+extern int  dccp_feat_init(struct sock *sk);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct sock *sk);
 
 /*
  * Encoding variable-length options and their maximum length.
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 34/37] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-08-28 17:45                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This adds auto-loading of CCIDs (when module loading is enabled)
for the purpose of feature negotiation.

The problem with loading the CCIDs at the end of feature negotiation is
that this would happen in software interrupt context. Besides, if the host
advertises CCIDs during negotiation, it should have them ready to use, in
case an agreeing peer wants to use it for the connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.c |   39 +++++++++++++++++++++++++++++----------
 net/dccp/ccid.h |    1 +
 net/dccp/feat.c |    5 +++++
 3 files changed, 35 insertions(+), 10 deletions(-)

--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops)
 
 EXPORT_SYMBOL_GPL(ccid_unregister);
 
+/**
+ * ccid_request_module  -  Pre-load CCID module for later use
+ * This should be called only from process context (e.g. during connection
+ * setup) and is necessary for later calls to ccid_new (typically in software
+ * interrupt), so that it has the modules available when they are needed.
+ */
+static int ccid_request_module(u8 id)
+{
+	if (!in_atomic()) {
+		ccids_read_lock();
+		if (ccids[id] == NULL) {
+			ccids_read_unlock();
+			return request_module("net-dccp-ccid-%d", id);
+		}
+		ccids_read_unlock();
+	}
+	return 0;
+}
+
+int ccid_request_modules(u8 const *ccid_array, u8 array_len)
+{
+#ifdef CONFIG_KMOD
+	while (array_len--)
+		if (ccid_request_module(ccid_array[array_len]))
+			return -1;
+#endif
+	return 0;
+}
+
 struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 {
 	struct ccid_operations *ccid_ops;
 	struct ccid *ccid = NULL;
 
 	ccids_read_lock();
-#ifdef CONFIG_KMOD
-	if (ccids[id] == NULL) {
-		/* We only try to load if in process context */
-		ccids_read_unlock();
-		if (gfp & GFP_ATOMIC)
-			goto out;
-		request_module("net-dccp-ccid-%d", id);
-		ccids_read_lock();
-	}
-#endif
 	ccid_ops = ccids[id];
 	if (ccid_ops == NULL)
 		goto out_unlock;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -108,6 +108,7 @@ extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
 extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 					  char __user *, int __user *);
 
+extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1170,6 +1170,11 @@ int dccp_feat_init(struct sock *sk)
 	    ccid_get_builtin_ccids(&rx.val, &rx.len))
 		return -ENOBUFS;
 
+	/* Pre-load all CCID modules that are going to be advertised */
+	rc = -EUNATCH;
+	if (ccid_request_modules(tx.val, tx.len))
+		goto free_ccid_lists;
+
 	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
 	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 34/37] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-08-28 17:45                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This adds auto-loading of CCIDs (when module loading is enabled)
for the purpose of feature negotiation.

The problem with loading the CCIDs at the end of feature negotiation is
that this would happen in software interrupt context. Besides, if the host
advertises CCIDs during negotiation, it should have them ready to use, in
case an agreeing peer wants to use it for the connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.c |   39 +++++++++++++++++++++++++++++----------
 net/dccp/ccid.h |    1 +
 net/dccp/feat.c |    5 +++++
 3 files changed, 35 insertions(+), 10 deletions(-)

--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops)
 
 EXPORT_SYMBOL_GPL(ccid_unregister);
 
+/**
+ * ccid_request_module  -  Pre-load CCID module for later use
+ * This should be called only from process context (e.g. during connection
+ * setup) and is necessary for later calls to ccid_new (typically in software
+ * interrupt), so that it has the modules available when they are needed.
+ */
+static int ccid_request_module(u8 id)
+{
+	if (!in_atomic()) {
+		ccids_read_lock();
+		if (ccids[id] = NULL) {
+			ccids_read_unlock();
+			return request_module("net-dccp-ccid-%d", id);
+		}
+		ccids_read_unlock();
+	}
+	return 0;
+}
+
+int ccid_request_modules(u8 const *ccid_array, u8 array_len)
+{
+#ifdef CONFIG_KMOD
+	while (array_len--)
+		if (ccid_request_module(ccid_array[array_len]))
+			return -1;
+#endif
+	return 0;
+}
+
 struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 {
 	struct ccid_operations *ccid_ops;
 	struct ccid *ccid = NULL;
 
 	ccids_read_lock();
-#ifdef CONFIG_KMOD
-	if (ccids[id] = NULL) {
-		/* We only try to load if in process context */
-		ccids_read_unlock();
-		if (gfp & GFP_ATOMIC)
-			goto out;
-		request_module("net-dccp-ccid-%d", id);
-		ccids_read_lock();
-	}
-#endif
 	ccid_ops = ccids[id];
 	if (ccid_ops = NULL)
 		goto out_unlock;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -108,6 +108,7 @@ extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
 extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 					  char __user *, int __user *);
 
+extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1170,6 +1170,11 @@ int dccp_feat_init(struct sock *sk)
 	    ccid_get_builtin_ccids(&rx.val, &rx.len))
 		return -ENOBUFS;
 
+	/* Pre-load all CCID modules that are going to be advertised */
+	rc = -EUNATCH;
+	if (ccid_request_modules(tx.val, tx.len))
+		goto free_ccid_lists;
+
 	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
 	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 35/37] dccp: Implement both feature-local and feature-remote Sequence Window feature
@ 2008-08-28 17:45                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This adds full support for local/remote Sequence Window feature, from which the
  * sequence-number-validity (W) and
  * acknowledgment-number-validity (W') windows
derive as specified in RFC 4340, 7.5.3.

Specifically, the following changes are introduced:
  * integrated new socket fields into dccp_sk;
  * updated the update_gsr/gss routines with regard to these fields;
  * updated handler code: the Sequence Window feature is located at the TX side,
    so the local feature is meant if the handler-rx flag is false;
  * the initialisation of `rcv_wnd' in reqsk is removed, since
    - rcv_wnd is not used by the code anywhere;
    - sequence number checks are not done in the LISTEN state (cf. 7.5.3);
    - dccp_check_req checks the Ack number validity more rigorously;
  * the `struct dccp_minisock' became empty and is now removed.

Until the handshake completes with activating negotiated values, the local/remote
Sequence-Window values are undefined and thus can not reliably be estimated.
This issue is addressed in a separate patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ++-
 include/linux/dccp.h              |   24 ++++--------------------
 net/dccp/dccp.h                   |   16 +++++++---------
 net/dccp/feat.c                   |   13 +++++++++++--
 net/dccp/minisocks.c              |   11 -----------
 net/dccp/proto.c                  |    2 --
 6 files changed, 24 insertions(+), 45 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -141,7 +141,8 @@ rx_ccid = 2
 	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
-	The initial sequence window (sec. 7.5.2).
+	The initial sequence window (sec. 7.5.2) of the sender. This influences
+	the local ackno validity and the remote seqno validity windows (7.5.1).
 
 tx_qlen = 5
 	The size of the transmit buffer in packets. A value of 0 corresponds
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -364,19 +364,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
 /**
-  * struct dccp_minisock - Minimal DCCP connection representation
-  *
-  * Will be used to pass the state from dccp_request_sock to dccp_sock.
-  *
-  * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  */
-struct dccp_minisock {
-	__u64			dccpms_sequence_window;
-};
-
-extern void dccp_minisock_init(struct dccp_minisock *dmsk);
-
-/**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
@@ -464,13 +451,14 @@ struct dccp_ackvec;
  * @dccps_timestamp_time - time of receiving latest @dccps_timestamp_echo
  * @dccps_l_ack_ratio - feature-local Ack Ratio
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
+ * @dccps_l_seq_win - local Sequence Window (influences ack number validity)
+ * @dccps_r_seq_win - remote Sequence Window (influences seq number validity)
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
  * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
- * @dccps_minisock - associated minisock (accessed via dccp_msk)
  * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
@@ -504,12 +492,13 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
+	__u64				dccps_l_seq_win:48;
+	__u64				dccps_r_seq_win:48;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
 	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
-	struct dccp_minisock		dccps_minisock;
 	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
@@ -527,11 +516,6 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
 	return (struct dccp_sock *)sk;
 }
 
-static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
-{
-	return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
-}
-
 static inline const char *dccp_role(const struct sock *sk)
 {
 	switch (dccp_sk(sk)->dccps_role) {
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -409,23 +409,21 @@ static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
 static inline void dccp_update_gsr(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	dp->dccps_gsr = seq;
-	dccp_set_seqno(&dp->dccps_swl,
-		       dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
-	dccp_set_seqno(&dp->dccps_swh,
-		       dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
+	/* Sequence validity window depends on remote Sequence Window (7.5.1) */
+	dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
+	dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
 }
 
 static inline void dccp_update_gss(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	dp->dccps_awh = dp->dccps_gss = seq;
-	dccp_set_seqno(&dp->dccps_awl,
-		       (dp->dccps_gss -
-			dccp_msk(sk)->dccpms_sequence_window + 1));
+	dp->dccps_gss = seq;
+	/* Ack validity window depends on local Sequence Window value (7.5.1) */
+	dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
+	dp->dccps_awh = dp->dccps_gss;
 }
 
 static inline int dccp_ack_pending(const struct sock *sk)
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -52,8 +52,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
 
 static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
 {
-	if (!rx)
-		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		dp->dccps_r_seq_win = seq_win;
+		/* propagate changes to update SWL/SWH */
+		dccp_update_gsr(sk, dp->dccps_gsr);
+	} else {
+		dp->dccps_l_seq_win = seq_win;
+		/* propagate changes to update AWL */
+		dccp_update_gss(sk, dp->dccps_gss);
+	}
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -42,11 +42,6 @@ struct inet_timewait_death_row dccp_death_row = {
 
 EXPORT_SYMBOL_GPL(dccp_death_row);
 
-void dccp_minisock_init(struct dccp_minisock *dmsk)
-{
-	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-}
-
 void dccp_time_wait(struct sock *sk, int state, int timeo)
 {
 	struct inet_timewait_sock *tw = NULL;
@@ -110,7 +105,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
-		struct dccp_minisock *newdmsk = dccp_msk(newsk);
 
 		newdp->dccps_role	    = DCCP_ROLE_SERVER;
 		newdp->dccps_hc_rx_ackvec   = NULL;
@@ -128,10 +122,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		 *    Initialize S.GAR := S.ISS
 		 *    Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
 		 */
-
-		/* See dccp_v4_conn_request */
-		newdmsk->dccpms_sequence_window = req->rcv_wnd;
-
 		newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
 		dccp_update_gss(newsk, dreq->dreq_iss);
 
@@ -289,7 +279,6 @@ int dccp_reqsk_init(struct request_sock *req,
 
 	inet_rsk(req)->rmt_port	  = dccp_hdr(skb)->dccph_sport;
 	inet_rsk(req)->acked	  = 0;
-	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
 
 	/* inherit feature negotiation options from listening socket */
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -180,8 +180,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	dccp_minisock_init(&dp->dccps_minisock);
-
 	icsk->icsk_rto		= DCCP_TIMEOUT_INIT;
 	icsk->icsk_syn_retries	= sysctl_dccp_request_retries;
 	sk->sk_state		= DCCP_CLOSED;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 35/37] dccp: Implement both feature-local and feature-remote Sequence Window feature
@ 2008-08-28 17:45                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This adds full support for local/remote Sequence Window feature, from which the
  * sequence-number-validity (W) and
  * acknowledgment-number-validity (W') windows
derive as specified in RFC 4340, 7.5.3.

Specifically, the following changes are introduced:
  * integrated new socket fields into dccp_sk;
  * updated the update_gsr/gss routines with regard to these fields;
  * updated handler code: the Sequence Window feature is located at the TX side,
    so the local feature is meant if the handler-rx flag is false;
  * the initialisation of `rcv_wnd' in reqsk is removed, since
    - rcv_wnd is not used by the code anywhere;
    - sequence number checks are not done in the LISTEN state (cf. 7.5.3);
    - dccp_check_req checks the Ack number validity more rigorously;
  * the `struct dccp_minisock' became empty and is now removed.

Until the handshake completes with activating negotiated values, the local/remote
Sequence-Window values are undefined and thus can not reliably be estimated.
This issue is addressed in a separate patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ++-
 include/linux/dccp.h              |   24 ++++--------------------
 net/dccp/dccp.h                   |   16 +++++++---------
 net/dccp/feat.c                   |   13 +++++++++++--
 net/dccp/minisocks.c              |   11 -----------
 net/dccp/proto.c                  |    2 --
 6 files changed, 24 insertions(+), 45 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -141,7 +141,8 @@ rx_ccid = 2
 	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
-	The initial sequence window (sec. 7.5.2).
+	The initial sequence window (sec. 7.5.2) of the sender. This influences
+	the local ackno validity and the remote seqno validity windows (7.5.1).
 
 tx_qlen = 5
 	The size of the transmit buffer in packets. A value of 0 corresponds
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -364,19 +364,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
 /**
-  * struct dccp_minisock - Minimal DCCP connection representation
-  *
-  * Will be used to pass the state from dccp_request_sock to dccp_sock.
-  *
-  * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  */
-struct dccp_minisock {
-	__u64			dccpms_sequence_window;
-};
-
-extern void dccp_minisock_init(struct dccp_minisock *dmsk);
-
-/**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
@@ -464,13 +451,14 @@ struct dccp_ackvec;
  * @dccps_timestamp_time - time of receiving latest @dccps_timestamp_echo
  * @dccps_l_ack_ratio - feature-local Ack Ratio
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
+ * @dccps_l_seq_win - local Sequence Window (influences ack number validity)
+ * @dccps_r_seq_win - remote Sequence Window (influences seq number validity)
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
  * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
- * @dccps_minisock - associated minisock (accessed via dccp_msk)
  * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
@@ -504,12 +492,13 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
+	__u64				dccps_l_seq_win:48;
+	__u64				dccps_r_seq_win:48;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
 	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
-	struct dccp_minisock		dccps_minisock;
 	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
@@ -527,11 +516,6 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
 	return (struct dccp_sock *)sk;
 }
 
-static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
-{
-	return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
-}
-
 static inline const char *dccp_role(const struct sock *sk)
 {
 	switch (dccp_sk(sk)->dccps_role) {
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -409,23 +409,21 @@ static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
 static inline void dccp_update_gsr(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	dp->dccps_gsr = seq;
-	dccp_set_seqno(&dp->dccps_swl,
-		       dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
-	dccp_set_seqno(&dp->dccps_swh,
-		       dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
+	/* Sequence validity window depends on remote Sequence Window (7.5.1) */
+	dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
+	dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
 }
 
 static inline void dccp_update_gss(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	dp->dccps_awh = dp->dccps_gss = seq;
-	dccp_set_seqno(&dp->dccps_awl,
-		       (dp->dccps_gss -
-			dccp_msk(sk)->dccpms_sequence_window + 1));
+	dp->dccps_gss = seq;
+	/* Ack validity window depends on local Sequence Window value (7.5.1) */
+	dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
+	dp->dccps_awh = dp->dccps_gss;
 }
 
 static inline int dccp_ack_pending(const struct sock *sk)
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -52,8 +52,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
 
 static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
 {
-	if (!rx)
-		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		dp->dccps_r_seq_win = seq_win;
+		/* propagate changes to update SWL/SWH */
+		dccp_update_gsr(sk, dp->dccps_gsr);
+	} else {
+		dp->dccps_l_seq_win = seq_win;
+		/* propagate changes to update AWL */
+		dccp_update_gss(sk, dp->dccps_gss);
+	}
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -42,11 +42,6 @@ struct inet_timewait_death_row dccp_death_row = {
 
 EXPORT_SYMBOL_GPL(dccp_death_row);
 
-void dccp_minisock_init(struct dccp_minisock *dmsk)
-{
-	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-}
-
 void dccp_time_wait(struct sock *sk, int state, int timeo)
 {
 	struct inet_timewait_sock *tw = NULL;
@@ -110,7 +105,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
-		struct dccp_minisock *newdmsk = dccp_msk(newsk);
 
 		newdp->dccps_role	    = DCCP_ROLE_SERVER;
 		newdp->dccps_hc_rx_ackvec   = NULL;
@@ -128,10 +122,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		 *    Initialize S.GAR := S.ISS
 		 *    Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
 		 */
-
-		/* See dccp_v4_conn_request */
-		newdmsk->dccpms_sequence_window = req->rcv_wnd;
-
 		newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
 		dccp_update_gss(newsk, dreq->dreq_iss);
 
@@ -289,7 +279,6 @@ int dccp_reqsk_init(struct request_sock *req,
 
 	inet_rsk(req)->rmt_port	  = dccp_hdr(skb)->dccph_sport;
 	inet_rsk(req)->acked	  = 0;
-	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
 
 	/* inherit feature negotiation options from listening socket */
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -180,8 +180,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	dccp_minisock_init(&dp->dccps_minisock);
-
 	icsk->icsk_rto		= DCCP_TIMEOUT_INIT;
 	icsk->icsk_syn_retries	= sysctl_dccp_request_retries;
 	sk->sk_state		= DCCP_CLOSED;
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 36/37] dccp: Initialisation and type-checking of feature sysctls
@ 2008-08-28 17:45                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This patch takes care of initialising and type-checking sysctls related to
feature negotiation. Type checking is important since some of the sysctls
now directly act on the feature-negotiation process.

The sysctls are initialised with the known default values for each feature.
For the type-checking the value constraints from RFC 4340 are used:

 * Sequence Window uses the specified Wmin=32, the maximum is ulong (4 bytes),
   tested and confirmed that it works up to 4294967295 - for Gbps speed;
 * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
 * CCIDs are between 0 .. 255;
 * request_retries, retries1, retries2 also between 0..255 for good measure;
 * tx_qlen is checked to be non-negative;
 * sync_ratelimit remains as before.

Further changes:
----------------
Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    8 --------
 net/dccp/dccp.h      |    3 ---
 net/dccp/feat.c      |   11 ++++++++---
 net/dccp/feat.h      |    8 ++++++++
 net/dccp/options.c   |    4 ----
 net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
 6 files changed, 46 insertions(+), 31 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 	return __dccp_hdr_len(dccp_hdr(skb));
 }
 
-
-/* initial values for each feature */
-#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-#define DCCPF_INITIAL_ACK_RATIO			2
-#define DCCPF_INITIAL_CCID			DCCPC_CCID2
-/* FIXME: for now we're default to 1 but it should really be 0 */
-#define DCCPF_INITIAL_SEND_NDP_COUNT		1
-
 /**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 extern int  sysctl_dccp_request_retries;
 extern int  sysctl_dccp_retries1;
 extern int  sysctl_dccp_retries2;
-extern int  sysctl_dccp_feat_sequence_window;
-extern int  sysctl_dccp_feat_rx_ccid;
-extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -26,6 +26,11 @@
 #include "ccid.h"
 #include "feat.h"
 
+/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
+unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
+int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
+		sysctl_dccp_tx_ccid	    __read_mostly = 2;
+
 /*
  * Feature activation handlers.
  *
@@ -1153,7 +1158,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Non-negotiable (NN) features */
 	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
-				    sysctl_dccp_feat_sequence_window);
+				    sysctl_dccp_sequence_window);
 	if (rc)
 		return rc;
 
@@ -1184,8 +1189,8 @@ int dccp_feat_init(struct sock *sk)
 	if (ccid_request_modules(tx.val, tx.len))
 		goto free_ccid_lists;
 
-	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
-	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;
 
 	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -97,6 +97,13 @@ struct ccid_dependency {
 	u8	val;
 };
 
+/*
+ * Sysctls to seed defaults for feature negotiation
+ */
+extern unsigned long sysctl_dccp_sequence_window;
+extern int	     sysctl_dccp_rx_ccid;
+extern int	     sysctl_dccp_tx_ccid;
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -111,6 +118,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
 extern int  dccp_feat_init(struct sock *sk);
+extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -23,10 +23,6 @@
 #include "dccp.h"
 #include "feat.h"
 
-int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
-int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
 	u64 value = 0;
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -18,55 +18,72 @@
 #error This file should not be compiled without CONFIG_SYSCTL defined
 #endif
 
+/* Boundary values */
+static int		zero     = 0,
+			u8_max   = 0xFF;
+static unsigned long	seqw_min = 32;
+
 static struct ctl_table dccp_default_table[] = {
 	{
 		.procname	= "seq_window",
-		.data		= &sysctl_dccp_feat_sequence_window,
-		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
+		.data		= &sysctl_dccp_sequence_window,
+		.maxlen		= sizeof(sysctl_dccp_sequence_window),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_doulongvec_minmax,
+		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
 	},
 	{
 		.procname	= "rx_ccid",
-		.data		= &sysctl_dccp_feat_rx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
+		.data		= &sysctl_dccp_rx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "tx_ccid",
-		.data		= &sysctl_dccp_feat_tx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
+		.data		= &sysctl_dccp_tx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries1",
 		.data		= &sysctl_dccp_retries1,
 		.maxlen		= sizeof(sysctl_dccp_retries1),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries2",
 		.data		= &sysctl_dccp_retries2,
 		.maxlen		= sizeof(sysctl_dccp_retries2),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "tx_qlen",
 		.data		= &sysctl_dccp_tx_qlen,
 		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
 	},
 	{
 		.procname	= "sync_ratelimit",
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 36/37] dccp: Initialisation and type-checking of feature sysctls
@ 2008-08-28 17:45                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

This patch takes care of initialising and type-checking sysctls related to
feature negotiation. Type checking is important since some of the sysctls
now directly act on the feature-negotiation process.

The sysctls are initialised with the known default values for each feature.
For the type-checking the value constraints from RFC 4340 are used:

 * Sequence Window uses the specified Wmin2, the maximum is ulong (4 bytes),
   tested and confirmed that it works up to 4294967295 - for Gbps speed;
 * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
 * CCIDs are between 0 .. 255;
 * request_retries, retries1, retries2 also between 0..255 for good measure;
 * tx_qlen is checked to be non-negative;
 * sync_ratelimit remains as before.

Further changes:
----------------
Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    8 --------
 net/dccp/dccp.h      |    3 ---
 net/dccp/feat.c      |   11 ++++++++---
 net/dccp/feat.h      |    8 ++++++++
 net/dccp/options.c   |    4 ----
 net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
 6 files changed, 46 insertions(+), 31 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 	return __dccp_hdr_len(dccp_hdr(skb));
 }
 
-
-/* initial values for each feature */
-#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-#define DCCPF_INITIAL_ACK_RATIO			2
-#define DCCPF_INITIAL_CCID			DCCPC_CCID2
-/* FIXME: for now we're default to 1 but it should really be 0 */
-#define DCCPF_INITIAL_SEND_NDP_COUNT		1
-
 /**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 extern int  sysctl_dccp_request_retries;
 extern int  sysctl_dccp_retries1;
 extern int  sysctl_dccp_retries2;
-extern int  sysctl_dccp_feat_sequence_window;
-extern int  sysctl_dccp_feat_rx_ccid;
-extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -26,6 +26,11 @@
 #include "ccid.h"
 #include "feat.h"
 
+/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
+unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
+int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
+		sysctl_dccp_tx_ccid	    __read_mostly = 2;
+
 /*
  * Feature activation handlers.
  *
@@ -1153,7 +1158,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Non-negotiable (NN) features */
 	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
-				    sysctl_dccp_feat_sequence_window);
+				    sysctl_dccp_sequence_window);
 	if (rc)
 		return rc;
 
@@ -1184,8 +1189,8 @@ int dccp_feat_init(struct sock *sk)
 	if (ccid_request_modules(tx.val, tx.len))
 		goto free_ccid_lists;
 
-	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
-	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;
 
 	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -97,6 +97,13 @@ struct ccid_dependency {
 	u8	val;
 };
 
+/*
+ * Sysctls to seed defaults for feature negotiation
+ */
+extern unsigned long sysctl_dccp_sequence_window;
+extern int	     sysctl_dccp_rx_ccid;
+extern int	     sysctl_dccp_tx_ccid;
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -111,6 +118,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
 extern int  dccp_feat_init(struct sock *sk);
+extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -23,10 +23,6 @@
 #include "dccp.h"
 #include "feat.h"
 
-int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
-int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
 	u64 value = 0;
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -18,55 +18,72 @@
 #error This file should not be compiled without CONFIG_SYSCTL defined
 #endif
 
+/* Boundary values */
+static int		zero     = 0,
+			u8_max   = 0xFF;
+static unsigned long	seqw_min = 32;
+
 static struct ctl_table dccp_default_table[] = {
 	{
 		.procname	= "seq_window",
-		.data		= &sysctl_dccp_feat_sequence_window,
-		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
+		.data		= &sysctl_dccp_sequence_window,
+		.maxlen		= sizeof(sysctl_dccp_sequence_window),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_doulongvec_minmax,
+		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
 	},
 	{
 		.procname	= "rx_ccid",
-		.data		= &sysctl_dccp_feat_rx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
+		.data		= &sysctl_dccp_rx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "tx_ccid",
-		.data		= &sysctl_dccp_feat_tx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
+		.data		= &sysctl_dccp_tx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries1",
 		.data		= &sysctl_dccp_retries1,
 		.maxlen		= sizeof(sysctl_dccp_retries1),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries2",
 		.data		= &sysctl_dccp_retries2,
 		.maxlen		= sizeof(sysctl_dccp_retries2),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "tx_qlen",
 		.data		= &sysctl_dccp_tx_qlen,
 		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
 	},
 	{
 		.procname	= "sync_ratelimit",
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 37/37] dccp: Debugging functions for feature negotiation
@ 2008-08-28 17:45                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

Since all feature-negotiation processing now takes place in feat.c, functions
for producing verbose debugging output are concentrated there.

New functions to print out values, entry records, and options are provided,
and also a macro is defined to not always have the function name in the
output line.

Thanks a lot to Wei Yongjun and Giuseppe Galeota for help with errors in an
earlier revision of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h    |    2 +
 net/dccp/feat.c    |  153 ++++++++++++++++++++++++++++++++++++----------------
 net/dccp/feat.h    |   13 -----
 net/dccp/options.c |    4 --
 4 files changed, 109 insertions(+), 63 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -42,9 +42,11 @@
 extern int dccp_debug;
 #define dccp_pr_debug(format, a...)	  DCCP_PR_DEBUG(dccp_debug, format, ##a)
 #define dccp_pr_debug_cat(format, a...)   DCCP_PRINTK(dccp_debug, format, ##a)
+#define dccp_debug(fmt, a...)		  dccp_pr_debug_cat(KERN_DEBUG fmt, ##a)
 #else
 #define dccp_pr_debug(format, a...)
 #define dccp_pr_debug_cat(format, a...)
+#define dccp_debug(format, a...)
 #endif
 
 extern struct inet_hashinfo dccp_hashinfo;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -204,6 +204,100 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? : dccp_feat_table[idx].default_value;
 }
 
+/*
+ *	Debugging and verbose-printing section
+ */
+static const char *dccp_feat_fname(const u8 feat)
+{
+	static const char *feature_names[] = {
+		[DCCPF_RESERVED]	= "Reserved",
+		[DCCPF_CCID]		= "CCID",
+		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
+		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
+		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
+		[DCCPF_ACK_RATIO]	= "Ack Ratio",
+		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
+		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
+		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
+		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
+	};
+	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
+		return feature_names[DCCPF_RESERVED];
+
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
+	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
+		return "CCID-specific";
+
+	return feature_names[feat];
+}
+
+static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
+					 "UNSTABLE", "STABLE" };
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+static const char *dccp_feat_oname(const u8 opt)
+{
+	switch (opt) {
+	case DCCPO_CHANGE_L:  return "Change_L";
+	case DCCPO_CONFIRM_L: return "Confirm_L";
+	case DCCPO_CHANGE_R:  return "Change_R";
+	case DCCPO_CONFIRM_R: return "Confirm_R";
+	}
+	return NULL;
+}
+
+static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
+{
+	u8 i, type = dccp_feat_type(feat_num);
+
+	if (val == NULL || (type == FEAT_SP && val->sp.vec == NULL))
+		dccp_pr_debug_cat("(NULL)");
+	else if (type == FEAT_SP)
+		for (i = 0; i < val->sp.len; i++)
+			dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
+	else if (type == FEAT_NN)
+		dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
+	else
+		dccp_pr_debug_cat("unknown type %u", type);
+}
+
+static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
+{
+	u8 type = dccp_feat_type(feat_num);
+	dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
+
+	if (type == FEAT_NN)
+		fval.nn = dccp_decode_value_var(list, len);
+	dccp_feat_printval(feat_num, &fval);
+}
+
+static void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
+{
+	dccp_debug("   * %s %s = ", entry->is_local ? "local" : "remote",
+				    dccp_feat_fname(entry->feat_num));
+	dccp_feat_printval(entry->feat_num, &entry->val);
+	dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
+			  entry->needs_confirm ? "(Confirm pending)" : "");
+}
+
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)	do {	      \
+	dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
+	dccp_feat_printvals(feat, val, len);				      \
+	dccp_pr_debug_cat(") %s\n", mandatory ? "!" : "");	} while (0)
+
+#define dccp_feat_print_fnlist(fn_list)  {		\
+	const struct dccp_feat_entry *___entry;		\
+							\
+	dccp_pr_debug("List Dump:\n");			\
+	list_for_each_entry(___entry, fn_list, node)	\
+		dccp_feat_print_entry(___entry);	\
+}
+#else	/* ! CONFIG_IP_DCCP_DEBUG */
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
+#define dccp_feat_print_fnlist(fn_list)
+#endif
+
 static int __dccp_feat_activate(struct sock *sk, const int idx,
 				const bool is_local, dccp_feat_val const *fval)
 {
@@ -236,6 +330,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
 	/* Location is RX if this is a local-RX or remote-TX feature */
 	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
 
+	dccp_debug("   -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
+		   dccp_feat_fname(dccp_feat_table[idx].feat_num),
+		   fval ? "" : "default ",  (unsigned long long)val);
+
 	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
 }
 
@@ -550,6 +648,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
 				return -1;
 			}
 		}
+		dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
 
 		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
 			return -1;
@@ -803,6 +902,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	while (i--)
 		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
 			return -1;
+	dccp_feat_print_fnlist(fn);
 	return 0;
 }
 
@@ -921,6 +1021,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	if (len == 0 || type == FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
 		goto unknown_feature_or_value;
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	/*
 	 *	Negotiation of NN features: Change R is invalid, so there is no
 	 *	simultaneous negotiation; hence we do not consult the list.
@@ -1028,6 +1130,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	const bool local = (opt == DCCPO_CONFIRM_R);
 	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	if (entry == NULL) {	/* nothing queued: ignore or handle error */
 		if (is_mandatory && type == FEAT_UNKNOWN)
 			return DCCP_RESET_CODE_MANDATORY_ERROR;
@@ -1222,9 +1326,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 			goto activation_failed;
 		}
 		if (cur->state != FEAT_STABLE) {
-			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+			DCCP_CRIT("Negotiation of %s %s failed in state %s",
 				  cur->is_local ? "local" : "remote",
-				  cur->feat_num, cur->state);
+				  dccp_feat_fname(cur->feat_num),
+				  dccp_feat_sname[cur->state]);
 			goto activation_failed;
 		}
 		fvals[idx][cur->is_local] = &cur->val;
@@ -1265,47 +1370,3 @@ activation_failed:
 	dp->dccps_hc_rx_ackvec = NULL;
 	return -1;
 }
-
-#ifdef CONFIG_IP_DCCP_DEBUG
-const char *dccp_feat_typename(const u8 type)
-{
-	switch(type) {
-	case DCCPO_CHANGE_L:  return("ChangeL");
-	case DCCPO_CONFIRM_L: return("ConfirmL");
-	case DCCPO_CHANGE_R:  return("ChangeR");
-	case DCCPO_CONFIRM_R: return("ConfirmR");
-	/* the following case must not appear in feature negotation  */
-	default:	      dccp_pr_debug("unknown type %d [BUG!]\n", type);
-	}
-	return NULL;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_typename);
-
-const char *dccp_feat_name(const u8 feat)
-{
-	static const char *feature_names[] = {
-		[DCCPF_RESERVED]	= "Reserved",
-		[DCCPF_CCID]		= "CCID",
-		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
-		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
-		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
-		[DCCPF_ACK_RATIO]	= "Ack Ratio",
-		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
-		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
-		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
-		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
-	};
-	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
-		return feature_names[DCCPF_RESERVED];
-
-	if (feat ==  DCCPF_SEND_LEV_RATE)
-		return "Send Loss Event Rate";
-	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
-		return "CCID-specific";
-
-	return feature_names[feat];
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_name);
-#endif /* CONFIG_IP_DCCP_DEBUG */
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -104,19 +104,6 @@ extern unsigned long sysctl_dccp_sequence_window;
 extern int	     sysctl_dccp_rx_ccid;
 extern int	     sysctl_dccp_tx_ccid;
 
-#ifdef CONFIG_IP_DCCP_DEBUG
-extern const char *dccp_feat_typename(const u8 type);
-extern const char *dccp_feat_name(const u8 feat);
-
-static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
-{
-	dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type),
-					   dccp_feat_name(feat), feat, val);
-}
-#else
-#define dccp_feat_debug(type, feat, val)
-#endif /* CONFIG_IP_DCCP_DEBUG */
-
 extern int  dccp_feat_init(struct sock *sk);
 extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -498,10 +498,6 @@ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
 		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
-
-	dccp_pr_debug("%s(%s (%d), ...), length %d\n",
-		      dccp_feat_typename(type),
-		      dccp_feat_name(feat), feat, len);
 	return 0;
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 37/37] dccp: Debugging functions for feature negotiation
@ 2008-08-28 17:45                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-28 17:45 UTC (permalink / raw)
  To: dccp

Since all feature-negotiation processing now takes place in feat.c, functions
for producing verbose debugging output are concentrated there.

New functions to print out values, entry records, and options are provided,
and also a macro is defined to not always have the function name in the
output line.

Thanks a lot to Wei Yongjun and Giuseppe Galeota for help with errors in an
earlier revision of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h    |    2 +
 net/dccp/feat.c    |  153 ++++++++++++++++++++++++++++++++++++----------------
 net/dccp/feat.h    |   13 -----
 net/dccp/options.c |    4 --
 4 files changed, 109 insertions(+), 63 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -42,9 +42,11 @@
 extern int dccp_debug;
 #define dccp_pr_debug(format, a...)	  DCCP_PR_DEBUG(dccp_debug, format, ##a)
 #define dccp_pr_debug_cat(format, a...)   DCCP_PRINTK(dccp_debug, format, ##a)
+#define dccp_debug(fmt, a...)		  dccp_pr_debug_cat(KERN_DEBUG fmt, ##a)
 #else
 #define dccp_pr_debug(format, a...)
 #define dccp_pr_debug_cat(format, a...)
+#define dccp_debug(format, a...)
 #endif
 
 extern struct inet_hashinfo dccp_hashinfo;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -204,6 +204,100 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? : dccp_feat_table[idx].default_value;
 }
 
+/*
+ *	Debugging and verbose-printing section
+ */
+static const char *dccp_feat_fname(const u8 feat)
+{
+	static const char *feature_names[] = {
+		[DCCPF_RESERVED]	= "Reserved",
+		[DCCPF_CCID]		= "CCID",
+		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
+		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
+		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
+		[DCCPF_ACK_RATIO]	= "Ack Ratio",
+		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
+		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
+		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
+		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
+	};
+	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
+		return feature_names[DCCPF_RESERVED];
+
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
+	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
+		return "CCID-specific";
+
+	return feature_names[feat];
+}
+
+static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
+					 "UNSTABLE", "STABLE" };
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+static const char *dccp_feat_oname(const u8 opt)
+{
+	switch (opt) {
+	case DCCPO_CHANGE_L:  return "Change_L";
+	case DCCPO_CONFIRM_L: return "Confirm_L";
+	case DCCPO_CHANGE_R:  return "Change_R";
+	case DCCPO_CONFIRM_R: return "Confirm_R";
+	}
+	return NULL;
+}
+
+static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
+{
+	u8 i, type = dccp_feat_type(feat_num);
+
+	if (val = NULL || (type = FEAT_SP && val->sp.vec = NULL))
+		dccp_pr_debug_cat("(NULL)");
+	else if (type = FEAT_SP)
+		for (i = 0; i < val->sp.len; i++)
+			dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
+	else if (type = FEAT_NN)
+		dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
+	else
+		dccp_pr_debug_cat("unknown type %u", type);
+}
+
+static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
+{
+	u8 type = dccp_feat_type(feat_num);
+	dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
+
+	if (type = FEAT_NN)
+		fval.nn = dccp_decode_value_var(list, len);
+	dccp_feat_printval(feat_num, &fval);
+}
+
+static void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
+{
+	dccp_debug("   * %s %s = ", entry->is_local ? "local" : "remote",
+				    dccp_feat_fname(entry->feat_num));
+	dccp_feat_printval(entry->feat_num, &entry->val);
+	dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
+			  entry->needs_confirm ? "(Confirm pending)" : "");
+}
+
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)	do {	      \
+	dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
+	dccp_feat_printvals(feat, val, len);				      \
+	dccp_pr_debug_cat(") %s\n", mandatory ? "!" : "");	} while (0)
+
+#define dccp_feat_print_fnlist(fn_list)  {		\
+	const struct dccp_feat_entry *___entry;		\
+							\
+	dccp_pr_debug("List Dump:\n");			\
+	list_for_each_entry(___entry, fn_list, node)	\
+		dccp_feat_print_entry(___entry);	\
+}
+#else	/* ! CONFIG_IP_DCCP_DEBUG */
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
+#define dccp_feat_print_fnlist(fn_list)
+#endif
+
 static int __dccp_feat_activate(struct sock *sk, const int idx,
 				const bool is_local, dccp_feat_val const *fval)
 {
@@ -236,6 +330,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
 	/* Location is RX if this is a local-RX or remote-TX feature */
 	rx = (is_local = (dccp_feat_table[idx].rxtx = FEAT_AT_RX));
 
+	dccp_debug("   -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
+		   dccp_feat_fname(dccp_feat_table[idx].feat_num),
+		   fval ? "" : "default ",  (unsigned long long)val);
+
 	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
 }
 
@@ -550,6 +648,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
 				return -1;
 			}
 		}
+		dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
 
 		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
 			return -1;
@@ -803,6 +902,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	while (i--)
 		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
 			return -1;
+	dccp_feat_print_fnlist(fn);
 	return 0;
 }
 
@@ -921,6 +1021,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	if (len = 0 || type = FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
 		goto unknown_feature_or_value;
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	/*
 	 *	Negotiation of NN features: Change R is invalid, so there is no
 	 *	simultaneous negotiation; hence we do not consult the list.
@@ -1028,6 +1130,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	const bool local = (opt = DCCPO_CONFIRM_R);
 	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	if (entry = NULL) {	/* nothing queued: ignore or handle error */
 		if (is_mandatory && type = FEAT_UNKNOWN)
 			return DCCP_RESET_CODE_MANDATORY_ERROR;
@@ -1222,9 +1326,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 			goto activation_failed;
 		}
 		if (cur->state != FEAT_STABLE) {
-			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+			DCCP_CRIT("Negotiation of %s %s failed in state %s",
 				  cur->is_local ? "local" : "remote",
-				  cur->feat_num, cur->state);
+				  dccp_feat_fname(cur->feat_num),
+				  dccp_feat_sname[cur->state]);
 			goto activation_failed;
 		}
 		fvals[idx][cur->is_local] = &cur->val;
@@ -1265,47 +1370,3 @@ activation_failed:
 	dp->dccps_hc_rx_ackvec = NULL;
 	return -1;
 }
-
-#ifdef CONFIG_IP_DCCP_DEBUG
-const char *dccp_feat_typename(const u8 type)
-{
-	switch(type) {
-	case DCCPO_CHANGE_L:  return("ChangeL");
-	case DCCPO_CONFIRM_L: return("ConfirmL");
-	case DCCPO_CHANGE_R:  return("ChangeR");
-	case DCCPO_CONFIRM_R: return("ConfirmR");
-	/* the following case must not appear in feature negotation  */
-	default:	      dccp_pr_debug("unknown type %d [BUG!]\n", type);
-	}
-	return NULL;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_typename);
-
-const char *dccp_feat_name(const u8 feat)
-{
-	static const char *feature_names[] = {
-		[DCCPF_RESERVED]	= "Reserved",
-		[DCCPF_CCID]		= "CCID",
-		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
-		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
-		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
-		[DCCPF_ACK_RATIO]	= "Ack Ratio",
-		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
-		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
-		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
-		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
-	};
-	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
-		return feature_names[DCCPF_RESERVED];
-
-	if (feat =  DCCPF_SEND_LEV_RATE)
-		return "Send Loss Event Rate";
-	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
-		return "CCID-specific";
-
-	return feature_names[feat];
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_name);
-#endif /* CONFIG_IP_DCCP_DEBUG */
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -104,19 +104,6 @@ extern unsigned long sysctl_dccp_sequence_window;
 extern int	     sysctl_dccp_rx_ccid;
 extern int	     sysctl_dccp_tx_ccid;
 
-#ifdef CONFIG_IP_DCCP_DEBUG
-extern const char *dccp_feat_typename(const u8 type);
-extern const char *dccp_feat_name(const u8 feat);
-
-static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
-{
-	dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type),
-					   dccp_feat_name(feat), feat, val);
-}
-#else
-#define dccp_feat_debug(type, feat, val)
-#endif /* CONFIG_IP_DCCP_DEBUG */
-
 extern int  dccp_feat_init(struct sock *sk);
 extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -498,10 +498,6 @@ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
 		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
-
-	dccp_pr_debug("%s(%s (%d), ...), length %d\n",
-		      dccp_feat_typename(type),
-		      dccp_feat_name(feat), feat, len);
 	return 0;
 }
 
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 03/37] dccp: List management for new feature negotiation
  2008-08-28 17:44         ` Gerrit Renker
@ 2008-08-28 19:43           ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 19:43 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:38PM +0200, Gerrit Renker escreveu:
> This adds list fields and list management functions for the new feature
> negotiation implementation. The new code is kept in parallel to the old
> code, until removed at the end of the patch set.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 129 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -147,6 +147,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
>  	}
>  }
>  
> +/*
> + *	List management functions
> + */
> +
> +/**
> + * dccp_feat_entry_new  -  Central list update routine (called by all others)
> + * @fn: list to add to
> + * @feat: feature number
> + * @is_local: whether the local (1) or remote feature with number @feat is meant
> + * The function maintains and relies on the following invariants:
> + *  - each feat_num in the list is known, ie. we know its type and default value
> + *  - each feat_num/is_local combination is unique (old entries are overwritten)
> + *  - SP values are always freshly allocated
> + *  - list is sorted in increasing order of feature number (faster lookup)
> + */
> +static struct dccp_feat_entry *
> +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
> +{
> +	struct dccp_feat_entry *entry;
> +	struct list_head *pos_head = fn;
> +
> +	list_for_each(pos_head, fn) {
> +		entry = list_entry(pos_head, struct dccp_feat_entry, node);

Why not use list_for_each_entry()?

> +		if (feat < entry->feat_num)
> +			break;
> +		if (entry->feat_num == feat && entry->is_local == is_local) {
> +			dccp_feat_val_destructor(entry->feat_num, &entry->val);

<first reaction>
You call dccp_feat_val_destructor on entry->val, that kfrees a field and
then return it? I havent checked, but would it be safer to set the field
kfree'ed in dccp_feat_val_destructor to NULL since
dccp_feat_val_destructor is not a destructor (i.e. its not the last
function in the life of dccp_feat_val)?

Humm, and shouldn't this entry be removed from the list?
</>

I got confused with a _new routine that ends up not being a constructor
and _destructor being called on an object, then not setting what it
frees to NULL and then reusing it somehow

> +			return entry;
> +		}
> +	}
> +	entry = kmalloc(sizeof(struct dccp_feat_entry), gfp_any());
> +	if (entry != NULL) {
> +		entry->feat_num = feat;
> +		entry->is_local = is_local;
> +		list_add_tail(&entry->node, pos_head);
> +	}
> +	return entry;
> +}
> +
> +static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
> +						     u8 feat_num, u8 is_local)
> +{
> +	struct dccp_feat_entry *entry;
> +
> +	list_for_each_entry(entry, fn_list, node)

cool, here you use list_for_each_entry :-)

> +		if (entry->feat_num == feat_num && entry->is_local == is_local)
> +			return entry;
> +		else if (entry->feat_num > feat_num)
> +			break;
> +	return NULL;
> +}

Humm, wouldn't it be better to make the users of dccp_feat_entry_new
call dccp_feat_list_lookup and if it returns NULL call
dccp_feat_entry_new that now would just be what its name implies, i.e. a
constructor, doing just the kmalloc + member init?

> +/**
> + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
> + * @fn_list: feature-negotiation list to update
> + * @feat: one of %dccp_feature_numbers
> + * @local: whether local (1) or remote (0) @feat_num is meant
> + * @needs_mandatory: whether to use Mandatory feature negotiation options
> + * @fval: pointer to NN/SP value to be inserted (will be copied)
> + */
> +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
> +				 u8 mandatory, dccp_feat_val *fval)
> +{
> +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
> +
> +	if (new == NULL)
> +		return -ENOMEM;
> +
> +	new->feat_num	     = feat;
> +	new->is_local	     = local;
> +	new->state	     = FEAT_INITIALISING;
> +	new->needs_confirm   = 0;
> +	new->empty_confirm   = 0;
> +	new->val	     = *fval;
> +	new->needs_mandatory = mandatory;
> +
> +	return 0;
> +}
> +
> +/**
> + * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
> + * @fn_list: feature-negotiation list to add to
> + * @feat: one of %dccp_feature_numbers
> + * @local: whether local (1) or remote (0) @feat_num is being confirmed
> + * @fval: pointer to NN/SP value to be inserted or NULL
> + * Returns 0 on success, a Reset code for further processing otherwise.
> + */
> +static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
> +				  dccp_feat_val *fval)
> +{
> +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
> +
> +	if (new == NULL)
> +		return DCCP_RESET_CODE_TOO_BUSY;
> +
> +	new->feat_num	     = feat;
> +	new->is_local	     = local;
> +	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
> +	new->needs_confirm   = 1;
> +	new->empty_confirm   = (fval == NULL);
> +	new->val.nn	     = 0;		/* zeroes the whole structure */
> +	if (!new->empty_confirm)
> +		new->val     = *fval;
> +	new->needs_mandatory = 0;
> +
> +	return 0;
> +}
> +
> +static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
> +{
> +	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
> +}
> +
> +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
> +{
> +	list_del(&entry->node);
> +	dccp_feat_entry_destructor(entry);
> +}

So dccp_feat_entry will always be embedded on other structs? i.e.
dccp_feat_entry_destructor doesn't frees its space, only fields that
points to memory allocated elsewhere

> +void dccp_feat_list_purge(struct list_head *fn_list)
> +{
> +	struct dccp_feat_entry *entry, *next;
> +
> +	list_for_each_entry_safe(entry, next, fn_list, node)
> +		dccp_feat_entry_destructor(entry);
> +	INIT_LIST_HEAD(fn_list);
> +}

Ditto, who frees the struct dccp_feat_entry instances?

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-28 19:43           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 19:43 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:38PM +0200, Gerrit Renker escreveu:
> This adds list fields and list management functions for the new feature
> negotiation implementation. The new code is kept in parallel to the old
> code, until removed at the end of the patch set.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 129 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -147,6 +147,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
>  	}
>  }
>  
> +/*
> + *	List management functions
> + */
> +
> +/**
> + * dccp_feat_entry_new  -  Central list update routine (called by all others)
> + * @fn: list to add to
> + * @feat: feature number
> + * @is_local: whether the local (1) or remote feature with number @feat is meant
> + * The function maintains and relies on the following invariants:
> + *  - each feat_num in the list is known, ie. we know its type and default value
> + *  - each feat_num/is_local combination is unique (old entries are overwritten)
> + *  - SP values are always freshly allocated
> + *  - list is sorted in increasing order of feature number (faster lookup)
> + */
> +static struct dccp_feat_entry *
> +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
> +{
> +	struct dccp_feat_entry *entry;
> +	struct list_head *pos_head = fn;
> +
> +	list_for_each(pos_head, fn) {
> +		entry = list_entry(pos_head, struct dccp_feat_entry, node);

Why not use list_for_each_entry()?

> +		if (feat < entry->feat_num)
> +			break;
> +		if (entry->feat_num = feat && entry->is_local = is_local) {
> +			dccp_feat_val_destructor(entry->feat_num, &entry->val);

<first reaction>
You call dccp_feat_val_destructor on entry->val, that kfrees a field and
then return it? I havent checked, but would it be safer to set the field
kfree'ed in dccp_feat_val_destructor to NULL since
dccp_feat_val_destructor is not a destructor (i.e. its not the last
function in the life of dccp_feat_val)?

Humm, and shouldn't this entry be removed from the list?
</>

I got confused with a _new routine that ends up not being a constructor
and _destructor being called on an object, then not setting what it
frees to NULL and then reusing it somehow

> +			return entry;
> +		}
> +	}
> +	entry = kmalloc(sizeof(struct dccp_feat_entry), gfp_any());
> +	if (entry != NULL) {
> +		entry->feat_num = feat;
> +		entry->is_local = is_local;
> +		list_add_tail(&entry->node, pos_head);
> +	}
> +	return entry;
> +}
> +
> +static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
> +						     u8 feat_num, u8 is_local)
> +{
> +	struct dccp_feat_entry *entry;
> +
> +	list_for_each_entry(entry, fn_list, node)

cool, here you use list_for_each_entry :-)

> +		if (entry->feat_num = feat_num && entry->is_local = is_local)
> +			return entry;
> +		else if (entry->feat_num > feat_num)
> +			break;
> +	return NULL;
> +}

Humm, wouldn't it be better to make the users of dccp_feat_entry_new
call dccp_feat_list_lookup and if it returns NULL call
dccp_feat_entry_new that now would just be what its name implies, i.e. a
constructor, doing just the kmalloc + member init?

> +/**
> + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
> + * @fn_list: feature-negotiation list to update
> + * @feat: one of %dccp_feature_numbers
> + * @local: whether local (1) or remote (0) @feat_num is meant
> + * @needs_mandatory: whether to use Mandatory feature negotiation options
> + * @fval: pointer to NN/SP value to be inserted (will be copied)
> + */
> +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
> +				 u8 mandatory, dccp_feat_val *fval)
> +{
> +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
> +
> +	if (new = NULL)
> +		return -ENOMEM;
> +
> +	new->feat_num	     = feat;
> +	new->is_local	     = local;
> +	new->state	     = FEAT_INITIALISING;
> +	new->needs_confirm   = 0;
> +	new->empty_confirm   = 0;
> +	new->val	     = *fval;
> +	new->needs_mandatory = mandatory;
> +
> +	return 0;
> +}
> +
> +/**
> + * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
> + * @fn_list: feature-negotiation list to add to
> + * @feat: one of %dccp_feature_numbers
> + * @local: whether local (1) or remote (0) @feat_num is being confirmed
> + * @fval: pointer to NN/SP value to be inserted or NULL
> + * Returns 0 on success, a Reset code for further processing otherwise.
> + */
> +static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
> +				  dccp_feat_val *fval)
> +{
> +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
> +
> +	if (new = NULL)
> +		return DCCP_RESET_CODE_TOO_BUSY;
> +
> +	new->feat_num	     = feat;
> +	new->is_local	     = local;
> +	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
> +	new->needs_confirm   = 1;
> +	new->empty_confirm   = (fval = NULL);
> +	new->val.nn	     = 0;		/* zeroes the whole structure */
> +	if (!new->empty_confirm)
> +		new->val     = *fval;
> +	new->needs_mandatory = 0;
> +
> +	return 0;
> +}
> +
> +static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
> +{
> +	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
> +}
> +
> +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
> +{
> +	list_del(&entry->node);
> +	dccp_feat_entry_destructor(entry);
> +}

So dccp_feat_entry will always be embedded on other structs? i.e.
dccp_feat_entry_destructor doesn't frees its space, only fields that
points to memory allocated elsewhere

> +void dccp_feat_list_purge(struct list_head *fn_list)
> +{
> +	struct dccp_feat_entry *entry, *next;
> +
> +	list_for_each_entry_safe(entry, next, fn_list, node)
> +		dccp_feat_entry_destructor(entry);
> +	INIT_LIST_HEAD(fn_list);
> +}

Ditto, who frees the struct dccp_feat_entry instances?

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 04/37] dccp: Per-socket initialisation of feature negotiation
  2008-08-28 17:44           ` Gerrit Renker
@ 2008-08-28 19:53             ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 19:53 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:39PM +0200, Gerrit Renker escreveu:
> This provides feature-negotiation initialisation for both DCCP sockets and
> DCCP request_sockets, to support feature negotiation during connection setup.
> 
> It also resolves a FIXME regarding the congestion control initialisation.
> 
> Thanks to Wei Yongjun for help with the IPv6 side of this patch.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    4 ++++
>  net/dccp/dccp.h      |    3 ++-
>  net/dccp/feat.c      |   19 +++++++++++++++++++
>  net/dccp/feat.h      |    1 +
>  net/dccp/input.c     |    2 --
>  net/dccp/ipv4.c      |    3 ++-
>  net/dccp/ipv6.c      |    3 ++-
>  net/dccp/minisocks.c |    7 ++++++-
>  net/dccp/proto.c     |    1 +
>  9 files changed, 37 insertions(+), 6 deletions(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
>   * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
>   * @dreq_isr: initial sequence number received on the Request
>   * @dreq_service: service code present on the Request (there is just one)
> + * @dreq_featneg: feature negotiation options for this connection
>   * The following two fields are analogous to the ones in dccp_sock:
>   * @dreq_timestamp_echo: last received timestamp to echo (13.1)
>   * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
> @@ -421,6 +422,7 @@ struct dccp_request_sock {
>  	__u64			 dreq_iss;
>  	__u64			 dreq_isr;
>  	__be32			 dreq_service;
> +	struct list_head	 dreq_featneg;

Wouldn't be better to use hlist here? So that we use 8 bytes less per
struct dccp_request_sock, after all we don't use struct sock while in
embryonic stage exactly to reduce the footprint at this point in the
socket lifetime :-)

>  	__u32			 dreq_timestamp_echo;
>  	__u32			 dreq_timestamp_time;
>  };
> @@ -498,6 +500,7 @@ struct dccp_ackvec;
>   * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
>   * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
>   * @dccps_minisock - associated minisock (accessed via dccp_msk)
> + * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
>   * @dccps_hc_rx_ackvec - rx half connection ack vector
>   * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
>   * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
> @@ -535,6 +538,7 @@ struct dccp_sock {
>  	__u64				dccps_ndp_count:48;
>  	unsigned long			dccps_rate_last;
>  	struct dccp_minisock		dccps_minisock;
> +	struct list_head		dccps_featneg;

And here as well

>  	struct dccp_ackvec		*dccps_hc_rx_ackvec;
>  	struct ccid			*dccps_hc_rx_ccid;
>  	struct ccid			*dccps_hc_tx_ccid;
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
>  extern void dccp_set_state(struct sock *sk, const int state);
>  extern void dccp_done(struct sock *sk);
>  
> -extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
> +extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
> +			    struct sk_buff const *skb);
>  
>  extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
>  
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -276,6 +276,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
>  }
>  EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
>  
> +/* generate @to as full clone of @from - @to must not contain any nodes */
> +int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
> +{
> +	struct dccp_feat_entry *entry, *new;
> +
> +	INIT_LIST_HEAD(to);
> +	list_for_each_entry(entry, from, node) {
> +		new = dccp_feat_clone_entry(entry);

dccp_feat_clone_entry uses kmemdup for a new dccp_feat_entry _and_
possibly for sp.vec, and goes on adding it to the 'to' list, but if
one fails you go to cloning_failed: and dccp_feat_list_purge will
call just dccp_feat_entry_destructor that doesn't frees the
dccp_feat_entry instances, just the sp.vec. 

Looks like major leakage, or am I missing something?

> +		if (new == NULL)
> +			goto cloning_failed;
> +		list_add_tail(&new->node, to);
> +	}
> +	return 0;
> +
> +cloning_failed:
> +	dccp_feat_list_purge(to);
> +	return -ENOMEM;
> +}
> +

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 04/37] dccp: Per-socket initialisation of feature
@ 2008-08-28 19:53             ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 19:53 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:39PM +0200, Gerrit Renker escreveu:
> This provides feature-negotiation initialisation for both DCCP sockets and
> DCCP request_sockets, to support feature negotiation during connection setup.
> 
> It also resolves a FIXME regarding the congestion control initialisation.
> 
> Thanks to Wei Yongjun for help with the IPv6 side of this patch.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    4 ++++
>  net/dccp/dccp.h      |    3 ++-
>  net/dccp/feat.c      |   19 +++++++++++++++++++
>  net/dccp/feat.h      |    1 +
>  net/dccp/input.c     |    2 --
>  net/dccp/ipv4.c      |    3 ++-
>  net/dccp/ipv6.c      |    3 ++-
>  net/dccp/minisocks.c |    7 ++++++-
>  net/dccp/proto.c     |    1 +
>  9 files changed, 37 insertions(+), 6 deletions(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
>   * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
>   * @dreq_isr: initial sequence number received on the Request
>   * @dreq_service: service code present on the Request (there is just one)
> + * @dreq_featneg: feature negotiation options for this connection
>   * The following two fields are analogous to the ones in dccp_sock:
>   * @dreq_timestamp_echo: last received timestamp to echo (13.1)
>   * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
> @@ -421,6 +422,7 @@ struct dccp_request_sock {
>  	__u64			 dreq_iss;
>  	__u64			 dreq_isr;
>  	__be32			 dreq_service;
> +	struct list_head	 dreq_featneg;

Wouldn't be better to use hlist here? So that we use 8 bytes less per
struct dccp_request_sock, after all we don't use struct sock while in
embryonic stage exactly to reduce the footprint at this point in the
socket lifetime :-)

>  	__u32			 dreq_timestamp_echo;
>  	__u32			 dreq_timestamp_time;
>  };
> @@ -498,6 +500,7 @@ struct dccp_ackvec;
>   * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
>   * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
>   * @dccps_minisock - associated minisock (accessed via dccp_msk)
> + * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
>   * @dccps_hc_rx_ackvec - rx half connection ack vector
>   * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
>   * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
> @@ -535,6 +538,7 @@ struct dccp_sock {
>  	__u64				dccps_ndp_count:48;
>  	unsigned long			dccps_rate_last;
>  	struct dccp_minisock		dccps_minisock;
> +	struct list_head		dccps_featneg;

And here as well

>  	struct dccp_ackvec		*dccps_hc_rx_ackvec;
>  	struct ccid			*dccps_hc_rx_ccid;
>  	struct ccid			*dccps_hc_tx_ccid;
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
>  extern void dccp_set_state(struct sock *sk, const int state);
>  extern void dccp_done(struct sock *sk);
>  
> -extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
> +extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
> +			    struct sk_buff const *skb);
>  
>  extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
>  
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -276,6 +276,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
>  }
>  EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
>  
> +/* generate @to as full clone of @from - @to must not contain any nodes */
> +int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
> +{
> +	struct dccp_feat_entry *entry, *new;
> +
> +	INIT_LIST_HEAD(to);
> +	list_for_each_entry(entry, from, node) {
> +		new = dccp_feat_clone_entry(entry);

dccp_feat_clone_entry uses kmemdup for a new dccp_feat_entry _and_
possibly for sp.vec, and goes on adding it to the 'to' list, but if
one fails you go to cloning_failed: and dccp_feat_list_purge will
call just dccp_feat_entry_destructor that doesn't frees the
dccp_feat_entry instances, just the sp.vec. 

Looks like major leakage, or am I missing something?

> +		if (new = NULL)
> +			goto cloning_failed;
> +		list_add_tail(&new->node, to);
> +	}
> +	return 0;
> +
> +cloning_failed:
> +	dccp_feat_list_purge(to);
> +	return -ENOMEM;
> +}
> +

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase
  2008-08-28 17:44               ` Gerrit Renker
@ 2008-08-28 20:50                 ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 20:50 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:41PM +0200, Gerrit Renker escreveu:
> This patch starts the new implementation of feature negotiation:
>  1. Although it is theoretically possible to perform feature negotiation at any
>     time (and RFC 4340 supports this), in practice this is prohibitively complex,
>     as it requires to put traffic on hold for each new negotiation.
>  2. As a byproduct of restricting feature negotiation to connection setup, the
>     feature-negotiation retransmit timer is no longer required. This part is now
>     mapped onto the protocol-level retransmission.
>     Details indicating why timers are no longer needed can be found on
>     http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
> 	                                      implementation_notes.html
> 
> This patch disables anytime negotiation, subsequent patches work out full
> feature negotiation support for connection setup.

While I agree that its better to initially support only negotiation at
connection startup, I wonder if the response to feature negotiation
after connection startup should be plainly ignore the request or if we
should reset the connection, telling the other side that what it wants
to do is not implemented currently.

- Arnaldo
 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> ---
>  net/dccp/feat.c    |   19 ++++++++-----------
>  net/dccp/options.c |   18 ------------------
>  net/dccp/timer.c   |   12 ------------
>  3 files changed, 8 insertions(+), 41 deletions(-)
> 
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -6,6 +6,8 @@
>   *
>   *  ASSUMPTIONS
>   *  -----------
> + *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
> + *    changes of parameters of an established connection are not supported.
>   *  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.
> @@ -649,6 +651,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
>  {
>  	int rc;
>  
> +	/* Ignore Change requests other than during connection setup */
> +	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
> +		return 0;
>  	dccp_feat_debug(type, feature, *val);
>  
>  	/* figure out if it's SP or NN feature */
> @@ -698,6 +703,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
>  	int found = 0;
>  	int all_confirmed = 1;
>  
> +	/* Ignore Confirm options other than during connection setup */
> +	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
> +		return 0;
>  	dccp_feat_debug(type, feature, *val);
>  
>  	/* locate our change request */
> @@ -732,17 +740,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
>  			all_confirmed = 0;
>  	}
>  
> -	/* fix re-transmit timer */
> -	/* XXX gotta make sure that no option negotiation occurs during
> -	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
> -	 * on.  if all options are confirmed it might kill timer which should
> -	 * remain alive until close is received.
> -	 */
> -	if (all_confirmed) {
> -		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
> -		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
> -	}
> -
>  	if (!found)
>  		dccp_pr_debug("%s(%d, ...) never requested\n",
>  			      dccp_feat_typename(type), feature);
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
>  
>  static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
>  {
> -	struct dccp_sock *dp = dccp_sk(sk);
>  	struct dccp_minisock *dmsk = dccp_msk(sk);
>  	struct dccp_opt_pend *opt, *next;
>  	int change = 0;
> @@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
>  		}
>  	}
>  
> -	/* Retransmit timer.
> -	 * If this is the master listening sock, we don't set a timer on it.  It
> -	 * should be fine because if the dude doesn't receive our RESPONSE
> -	 * [which will contain the CHANGE] he will send another REQUEST which
> -	 * will "retrnasmit" the change.
> -	 */
> -	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
> -		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
> -
> -		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
> -		 * only when sending new stuff i guess.  Currently the timer
> -		 * never backs off because on re-transmission it just resets it!
> -		 */
> -		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
> -					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
> -	}
> -
>  	return 0;
>  }
>  
> --- a/net/dccp/timer.c
> +++ b/net/dccp/timer.c
> @@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk)
>  {
>  	struct inet_connection_sock *icsk = inet_csk(sk);
>  
> -	/* retransmit timer is used for feature negotiation throughout
> -	 * connection.  In this case, no packet is re-transmitted, but rather an
> -	 * ack is generated and pending changes are placed into its options.
> -	 */
> -	if (sk->sk_send_head == NULL) {
> -		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
> -		if (sk->sk_state == DCCP_OPEN)
> -			dccp_send_ack(sk);
> -		goto backoff;
> -	}
> -
>  	/*
>  	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
>  	 * sent, no need to retransmit, this sock is dead.
> @@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk)
>  		return;
>  	}
>  
> -backoff:
>  	icsk->icsk_backoff++;
>  
>  	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 06/37] dccp: Limit feature negotiation to connection
@ 2008-08-28 20:50                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 20:50 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:41PM +0200, Gerrit Renker escreveu:
> This patch starts the new implementation of feature negotiation:
>  1. Although it is theoretically possible to perform feature negotiation at any
>     time (and RFC 4340 supports this), in practice this is prohibitively complex,
>     as it requires to put traffic on hold for each new negotiation.
>  2. As a byproduct of restricting feature negotiation to connection setup, the
>     feature-negotiation retransmit timer is no longer required. This part is now
>     mapped onto the protocol-level retransmission.
>     Details indicating why timers are no longer needed can be found on
>     http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
> 	                                      implementation_notes.html
> 
> This patch disables anytime negotiation, subsequent patches work out full
> feature negotiation support for connection setup.

While I agree that its better to initially support only negotiation at
connection startup, I wonder if the response to feature negotiation
after connection startup should be plainly ignore the request or if we
should reset the connection, telling the other side that what it wants
to do is not implemented currently.

- Arnaldo
 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> ---
>  net/dccp/feat.c    |   19 ++++++++-----------
>  net/dccp/options.c |   18 ------------------
>  net/dccp/timer.c   |   12 ------------
>  3 files changed, 8 insertions(+), 41 deletions(-)
> 
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -6,6 +6,8 @@
>   *
>   *  ASSUMPTIONS
>   *  -----------
> + *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
> + *    changes of parameters of an established connection are not supported.
>   *  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.
> @@ -649,6 +651,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
>  {
>  	int rc;
>  
> +	/* Ignore Change requests other than during connection setup */
> +	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
> +		return 0;
>  	dccp_feat_debug(type, feature, *val);
>  
>  	/* figure out if it's SP or NN feature */
> @@ -698,6 +703,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
>  	int found = 0;
>  	int all_confirmed = 1;
>  
> +	/* Ignore Confirm options other than during connection setup */
> +	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
> +		return 0;
>  	dccp_feat_debug(type, feature, *val);
>  
>  	/* locate our change request */
> @@ -732,17 +740,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
>  			all_confirmed = 0;
>  	}
>  
> -	/* fix re-transmit timer */
> -	/* XXX gotta make sure that no option negotiation occurs during
> -	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
> -	 * on.  if all options are confirmed it might kill timer which should
> -	 * remain alive until close is received.
> -	 */
> -	if (all_confirmed) {
> -		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
> -		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
> -	}
> -
>  	if (!found)
>  		dccp_pr_debug("%s(%d, ...) never requested\n",
>  			      dccp_feat_typename(type), feature);
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
>  
>  static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
>  {
> -	struct dccp_sock *dp = dccp_sk(sk);
>  	struct dccp_minisock *dmsk = dccp_msk(sk);
>  	struct dccp_opt_pend *opt, *next;
>  	int change = 0;
> @@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
>  		}
>  	}
>  
> -	/* Retransmit timer.
> -	 * If this is the master listening sock, we don't set a timer on it.  It
> -	 * should be fine because if the dude doesn't receive our RESPONSE
> -	 * [which will contain the CHANGE] he will send another REQUEST which
> -	 * will "retrnasmit" the change.
> -	 */
> -	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
> -		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
> -
> -		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
> -		 * only when sending new stuff i guess.  Currently the timer
> -		 * never backs off because on re-transmission it just resets it!
> -		 */
> -		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
> -					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
> -	}
> -
>  	return 0;
>  }
>  
> --- a/net/dccp/timer.c
> +++ b/net/dccp/timer.c
> @@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk)
>  {
>  	struct inet_connection_sock *icsk = inet_csk(sk);
>  
> -	/* retransmit timer is used for feature negotiation throughout
> -	 * connection.  In this case, no packet is re-transmitted, but rather an
> -	 * ack is generated and pending changes are placed into its options.
> -	 */
> -	if (sk->sk_send_head = NULL) {
> -		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
> -		if (sk->sk_state = DCCP_OPEN)
> -			dccp_send_ack(sk);
> -		goto backoff;
> -	}
> -
>  	/*
>  	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
>  	 * sent, no need to retransmit, this sock is dead.
> @@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk)
>  		return;
>  	}
>  
> -backoff:
>  	icsk->icsk_backoff++;
>  
>  	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature values
  2008-08-28 17:44                 ` Gerrit Renker
@ 2008-08-28 20:54                   ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 20:54 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:42PM +0200, Gerrit Renker escreveu:
> Two registration routines, for SP and NN features, are provided by this patch,
> replacing a previous routine which was used for both feature types.
> 
> These are internal-only routines and therefore start with `__feat_register'.
> 
> It further exports the known limits of Sequence Window and Ack Ratio as symbolic
> constants.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ccids/ccid2.c |    6 +-
>  net/dccp/feat.c        |  123 +++++++++++++++++++++++++++++++++++++++---------
>  net/dccp/feat.h        |   25 +++++++++-
>  net/dccp/proto.c       |    2 +-
>  4 files changed, 128 insertions(+), 28 deletions(-)
> 
> --- a/net/dccp/ccids/ccid2.c
> +++ b/net/dccp/ccids/ccid2.c
> @@ -25,7 +25,7 @@
>  /*
>   * This implementation should follow RFC 4341
>   */
> -
> +#include "../feat.h"
>  #include "../ccid.h"
>  #include "../dccp.h"
>  #include "ccid2.h"
> @@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
>  		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
>  		val = max_ratio;
>  	}
> -	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
> -		val = 0xFFFF;
> +	if (val > DCCPF_ACK_RATIO_MAX)
> +		val = DCCPF_ACK_RATIO_MAX;
>  
>  	if (val == dp->dccps_l_ack_ratio)
>  		return;
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -297,6 +297,95 @@ cloning_failed:
>  	return -ENOMEM;
>  }
>  
> +static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
> +{
> +	switch (feat_num) {
> +	case DCCPF_ACK_RATIO:
> +		return val <= DCCPF_ACK_RATIO_MAX;
> +	case DCCPF_SEQUENCE_WINDOW:
> +		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
> +	}
> +	return 0;	/* feature unknown - so we can't tell */
> +}
> +
> +/* check that SP values are within the ranges defined in RFC 4340 */
> +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
> +{
> +	switch (feat_num) {
> +	case DCCPF_CCID:
> +		return val == DCCPC_CCID2 || val == DCCPC_CCID3;

Shouldn't we look at the registered CCIDs and do validation based on the
modules loaded? Doing it this hardcoded way will prevent testing CCID4,
for instance, or require that the kernel be patched, which can not be
possible with enterprise distros, etc. And defeats the purpose of having
multiple pluggable congestion control algorithms :-)

> +	/* Type-check Boolean feature values: */
> +	case DCCPF_SHORT_SEQNOS:
> +	case DCCPF_ECN_INCAPABLE:
> +	case DCCPF_SEND_ACK_VECTOR:
> +	case DCCPF_SEND_NDP_COUNT:
> +	case DCCPF_DATA_CHECKSUM:
> +	case DCCPF_SEND_LEV_RATE:
> +		return val < 2;
> +	case DCCPF_MIN_CSUM_COVER:
> +		return val < 16;
> +	}
> +	return 0;			/* feature unknown */
> +}
> +
> +static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
> +{
> +	if (sp_list == NULL || sp_len < 1)
> +		return 0;
> +	while (sp_len--)
> +		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
> +			return 0;
> +	return 1;
> +}
> +
> +/**
> + * __feat_register_nn  -  Register new NN value on socket
> + * @fn: feature-negotiation list to register with
> + * @feat: an NN feature from %dccp_feature_numbers
> + * @mandatory: use Mandatory option if 1
> + * @nn_val: value to register (restricted to 4 bytes)
> + * Note that NN features are local by definition (RFC 4340, 6.3.2).
> + */
> +static int __feat_register_nn(struct list_head *fn, u8 feat,
> +			      u8 mandatory, u64 nn_val)
> +{
> +	dccp_feat_val fval = { .nn = nn_val };
> +
> +	if (dccp_feat_type(feat) != FEAT_NN ||
> +	    !dccp_feat_is_valid_nn_val(feat, nn_val))
> +		return -EINVAL;
> +
> +	/* Don't bother with default values, they will be activated anyway. */
> +	if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
> +		return 0;
> +
> +	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
> +}
> +
> +/**
> + * __feat_register_sp  -  Register new SP value/list on socket
> + * @fn: feature-negotiation list to register with
> + * @feat: an SP feature from %dccp_feature_numbers
> + * @is_local: whether the local (1) or the remote (0) @feat is meant
> + * @mandatory: use Mandatory option if 1
> + * @sp_val: SP value followed by optional preference list
> + * @sp_len: length of @sp_val in bytes
> + */
> +static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
> +			      u8 mandatory, u8 const *sp_val, u8 sp_len)
> +{
> +	dccp_feat_val fval;
> +
> +	if (dccp_feat_type(feat) != FEAT_SP ||
> +	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
> +		return -EINVAL;
> +
> +	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
> +		return -ENOMEM;
> +
> +	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
> +}
> +
>  int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
>  		     u8 *val, u8 len, gfp_t gfp)
>  {
> @@ -833,42 +922,30 @@ out_clean:
>  
>  EXPORT_SYMBOL_GPL(dccp_feat_clone);
>  
> -static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
> -			    u8 *val, u8 len)
> -{
> -	int rc = -ENOMEM;
> -	u8 *copy = kmemdup(val, len, GFP_KERNEL);
> -
> -	if (copy != NULL) {
> -		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
> -		if (rc)
> -			kfree(copy);
> -	}
> -	return rc;
> -}
> -
> -int dccp_feat_init(struct dccp_minisock *dmsk)
> +int dccp_feat_init(struct sock *sk)
>  {
> +	struct dccp_sock *dp = dccp_sk(sk);
> +	struct dccp_minisock *dmsk = dccp_msk(sk);
>  	int rc;
>  
> -	INIT_LIST_HEAD(&dmsk->dccpms_pending);
> -	INIT_LIST_HEAD(&dmsk->dccpms_conf);
> +	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
> +	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
>  
>  	/* CCID L */
> -	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
> -			      &dmsk->dccpms_tx_ccid, 1);
> +	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
> +				&dmsk->dccpms_tx_ccid, 1);
>  	if (rc)
>  		goto out;
>  
>  	/* CCID R */
> -	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
> -			      &dmsk->dccpms_rx_ccid, 1);
> +	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
> +				&dmsk->dccpms_rx_ccid, 1);
>  	if (rc)
>  		goto out;
>  
>  	/* Ack ratio */
> -	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
> -			      &dmsk->dccpms_ack_ratio, 1);
> +	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
> +				dmsk->dccpms_ack_ratio);
>  out:
>  	return rc;
>  }
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -14,6 +14,15 @@
>  #include <linux/types.h>
>  #include "dccp.h"
>  
> +/*
> + * Known limits of feature values.
> + */
> +/* Ack Ratio takes 2-byte integer values (11.3) */
> +#define DCCPF_ACK_RATIO_MAX	0xFFFF
> +/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
> +#define DCCPF_SEQ_WMIN		32
> +#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
> +
>  enum dccp_feat_type {
>  	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
>  	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
> @@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
>  	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
>  }
>  
> +/**
> + * struct ccid_dependency  -  Track changes resulting from choosing a CCID
> + * @dependent_feat: one of %dccp_feature_numbers
> + * @is_local: local (1) or remote (0) @dependent_feat
> + * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
> + * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
> + */
> +struct ccid_dependency {
> +	u8	dependent_feat;
> +	bool	is_local:1,
> +		is_mandatory:1;
> +	u8	val;
> +};
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  extern const char *dccp_feat_typename(const u8 type);
>  extern const char *dccp_feat_name(const u8 feat);
> @@ -96,6 +119,6 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
>  extern void dccp_feat_clean(struct dccp_minisock *dmsk);
>  extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
>  extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
> -extern int  dccp_feat_init(struct dccp_minisock *dmsk);
> +extern int  dccp_feat_init(struct sock *sk);
>  
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
>  	 * setsockopt(CCIDs-I-want/accept). -acme
>  	 */
>  	if (likely(ctl_sock_initialized)) {
> -		int rc = dccp_feat_init(dmsk);
> +		int rc = dccp_feat_init(sk);
>  
>  		if (rc)
>  			return rc;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature
@ 2008-08-28 20:54                   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 20:54 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:42PM +0200, Gerrit Renker escreveu:
> Two registration routines, for SP and NN features, are provided by this patch,
> replacing a previous routine which was used for both feature types.
> 
> These are internal-only routines and therefore start with `__feat_register'.
> 
> It further exports the known limits of Sequence Window and Ack Ratio as symbolic
> constants.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ccids/ccid2.c |    6 +-
>  net/dccp/feat.c        |  123 +++++++++++++++++++++++++++++++++++++++---------
>  net/dccp/feat.h        |   25 +++++++++-
>  net/dccp/proto.c       |    2 +-
>  4 files changed, 128 insertions(+), 28 deletions(-)
> 
> --- a/net/dccp/ccids/ccid2.c
> +++ b/net/dccp/ccids/ccid2.c
> @@ -25,7 +25,7 @@
>  /*
>   * This implementation should follow RFC 4341
>   */
> -
> +#include "../feat.h"
>  #include "../ccid.h"
>  #include "../dccp.h"
>  #include "ccid2.h"
> @@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
>  		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
>  		val = max_ratio;
>  	}
> -	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
> -		val = 0xFFFF;
> +	if (val > DCCPF_ACK_RATIO_MAX)
> +		val = DCCPF_ACK_RATIO_MAX;
>  
>  	if (val = dp->dccps_l_ack_ratio)
>  		return;
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -297,6 +297,95 @@ cloning_failed:
>  	return -ENOMEM;
>  }
>  
> +static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
> +{
> +	switch (feat_num) {
> +	case DCCPF_ACK_RATIO:
> +		return val <= DCCPF_ACK_RATIO_MAX;
> +	case DCCPF_SEQUENCE_WINDOW:
> +		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
> +	}
> +	return 0;	/* feature unknown - so we can't tell */
> +}
> +
> +/* check that SP values are within the ranges defined in RFC 4340 */
> +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
> +{
> +	switch (feat_num) {
> +	case DCCPF_CCID:
> +		return val = DCCPC_CCID2 || val = DCCPC_CCID3;

Shouldn't we look at the registered CCIDs and do validation based on the
modules loaded? Doing it this hardcoded way will prevent testing CCID4,
for instance, or require that the kernel be patched, which can not be
possible with enterprise distros, etc. And defeats the purpose of having
multiple pluggable congestion control algorithms :-)

> +	/* Type-check Boolean feature values: */
> +	case DCCPF_SHORT_SEQNOS:
> +	case DCCPF_ECN_INCAPABLE:
> +	case DCCPF_SEND_ACK_VECTOR:
> +	case DCCPF_SEND_NDP_COUNT:
> +	case DCCPF_DATA_CHECKSUM:
> +	case DCCPF_SEND_LEV_RATE:
> +		return val < 2;
> +	case DCCPF_MIN_CSUM_COVER:
> +		return val < 16;
> +	}
> +	return 0;			/* feature unknown */
> +}
> +
> +static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
> +{
> +	if (sp_list = NULL || sp_len < 1)
> +		return 0;
> +	while (sp_len--)
> +		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
> +			return 0;
> +	return 1;
> +}
> +
> +/**
> + * __feat_register_nn  -  Register new NN value on socket
> + * @fn: feature-negotiation list to register with
> + * @feat: an NN feature from %dccp_feature_numbers
> + * @mandatory: use Mandatory option if 1
> + * @nn_val: value to register (restricted to 4 bytes)
> + * Note that NN features are local by definition (RFC 4340, 6.3.2).
> + */
> +static int __feat_register_nn(struct list_head *fn, u8 feat,
> +			      u8 mandatory, u64 nn_val)
> +{
> +	dccp_feat_val fval = { .nn = nn_val };
> +
> +	if (dccp_feat_type(feat) != FEAT_NN ||
> +	    !dccp_feat_is_valid_nn_val(feat, nn_val))
> +		return -EINVAL;
> +
> +	/* Don't bother with default values, they will be activated anyway. */
> +	if (nn_val - (u64)dccp_feat_default_value(feat) = 0)
> +		return 0;
> +
> +	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
> +}
> +
> +/**
> + * __feat_register_sp  -  Register new SP value/list on socket
> + * @fn: feature-negotiation list to register with
> + * @feat: an SP feature from %dccp_feature_numbers
> + * @is_local: whether the local (1) or the remote (0) @feat is meant
> + * @mandatory: use Mandatory option if 1
> + * @sp_val: SP value followed by optional preference list
> + * @sp_len: length of @sp_val in bytes
> + */
> +static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
> +			      u8 mandatory, u8 const *sp_val, u8 sp_len)
> +{
> +	dccp_feat_val fval;
> +
> +	if (dccp_feat_type(feat) != FEAT_SP ||
> +	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
> +		return -EINVAL;
> +
> +	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
> +		return -ENOMEM;
> +
> +	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
> +}
> +
>  int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
>  		     u8 *val, u8 len, gfp_t gfp)
>  {
> @@ -833,42 +922,30 @@ out_clean:
>  
>  EXPORT_SYMBOL_GPL(dccp_feat_clone);
>  
> -static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
> -			    u8 *val, u8 len)
> -{
> -	int rc = -ENOMEM;
> -	u8 *copy = kmemdup(val, len, GFP_KERNEL);
> -
> -	if (copy != NULL) {
> -		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
> -		if (rc)
> -			kfree(copy);
> -	}
> -	return rc;
> -}
> -
> -int dccp_feat_init(struct dccp_minisock *dmsk)
> +int dccp_feat_init(struct sock *sk)
>  {
> +	struct dccp_sock *dp = dccp_sk(sk);
> +	struct dccp_minisock *dmsk = dccp_msk(sk);
>  	int rc;
>  
> -	INIT_LIST_HEAD(&dmsk->dccpms_pending);
> -	INIT_LIST_HEAD(&dmsk->dccpms_conf);
> +	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
> +	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
>  
>  	/* CCID L */
> -	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
> -			      &dmsk->dccpms_tx_ccid, 1);
> +	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
> +				&dmsk->dccpms_tx_ccid, 1);
>  	if (rc)
>  		goto out;
>  
>  	/* CCID R */
> -	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
> -			      &dmsk->dccpms_rx_ccid, 1);
> +	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
> +				&dmsk->dccpms_rx_ccid, 1);
>  	if (rc)
>  		goto out;
>  
>  	/* Ack ratio */
> -	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
> -			      &dmsk->dccpms_ack_ratio, 1);
> +	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
> +				dmsk->dccpms_ack_ratio);
>  out:
>  	return rc;
>  }
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -14,6 +14,15 @@
>  #include <linux/types.h>
>  #include "dccp.h"
>  
> +/*
> + * Known limits of feature values.
> + */
> +/* Ack Ratio takes 2-byte integer values (11.3) */
> +#define DCCPF_ACK_RATIO_MAX	0xFFFF
> +/* Wmin2 and Wmax=2^46-1 from 7.5.2 */
> +#define DCCPF_SEQ_WMIN		32
> +#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
> +
>  enum dccp_feat_type {
>  	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
>  	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
> @@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
>  	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
>  }
>  
> +/**
> + * struct ccid_dependency  -  Track changes resulting from choosing a CCID
> + * @dependent_feat: one of %dccp_feature_numbers
> + * @is_local: local (1) or remote (0) @dependent_feat
> + * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
> + * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
> + */
> +struct ccid_dependency {
> +	u8	dependent_feat;
> +	bool	is_local:1,
> +		is_mandatory:1;
> +	u8	val;
> +};
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  extern const char *dccp_feat_typename(const u8 type);
>  extern const char *dccp_feat_name(const u8 feat);
> @@ -96,6 +119,6 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
>  extern void dccp_feat_clean(struct dccp_minisock *dmsk);
>  extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
>  extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
> -extern int  dccp_feat_init(struct dccp_minisock *dmsk);
> +extern int  dccp_feat_init(struct sock *sk);
>  
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
>  	 * setsockopt(CCIDs-I-want/accept). -acme
>  	 */
>  	if (likely(ctl_sock_initialized)) {
> -		int rc = dccp_feat_init(dmsk);
> +		int rc = dccp_feat_init(sk);
>  
>  		if (rc)
>  			return rc;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 08/37] dccp: Query supported CCIDs
  2008-08-28 17:44                   ` Gerrit Renker
@ 2008-08-28 21:00                     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:00 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:43PM +0200, Gerrit Renker escreveu:
> This provides a data structure to record which CCIDs are locally supported
> and three accessor functions:
>  - a test function for internal use which is used to validate CCID requests
>    made by the user;
>  - a copy function so that the list can be used for feature-negotiation;
>  - documented getsockopt() support so that the user can query capabilities.
> 
> The data structure is a table which is filled in at compile-time with the
> list of available CCIDs (which in turn depends on the Kconfig choices).
> 
> Using the copy function for cloning the list of supported CCIDs is useful for
> feature negotiation, since the negotiation is now with the full list of available
> CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
> will not fail if the peer requests to use CCID3 instead of CCID2.

But this limits us to the CCIDs at kernel build time, what if I want to
test CCID4? I guess we could have something like a bitmap and check if
the bit for that CCID is set, and it would be set at ccid_register time.

Perhaps using include/linux/bitmap.h :-)

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 08/37] dccp: Query supported CCIDs
@ 2008-08-28 21:00                     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:00 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:43PM +0200, Gerrit Renker escreveu:
> This provides a data structure to record which CCIDs are locally supported
> and three accessor functions:
>  - a test function for internal use which is used to validate CCID requests
>    made by the user;
>  - a copy function so that the list can be used for feature-negotiation;
>  - documented getsockopt() support so that the user can query capabilities.
> 
> The data structure is a table which is filled in at compile-time with the
> list of available CCIDs (which in turn depends on the Kconfig choices).
> 
> Using the copy function for cloning the list of supported CCIDs is useful for
> feature negotiation, since the negotiation is now with the full list of available
> CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
> will not fail if the peer requests to use CCID3 instead of CCID2.

But this limits us to the CCIDs at kernel build time, what if I want to
test CCID4? I guess we could have something like a bitmap and check if
the bit for that CCID is set, and it would be set at ccid_register time.

Perhaps using include/linux/bitmap.h :-)

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID
  2008-08-28 17:44                     ` Gerrit Renker
@ 2008-08-28 21:07                       ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:07 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:44PM +0200, Gerrit Renker escreveu:
> This provides a missing link in the code chain, as several features implicitly
> depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
> feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
> 
> For Send Ack Vector, the situation is as follows:
>  * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
>    endpoints which use CCID2 to disable Ack Vector features such a connection;
> 
>  * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
>    with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);
> 
>  * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
>    negotiable. However, this implies that the code negotiating the use of Ack
>    Vectors also supports it (i.e. is able to supply and to either parse or
>    ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
>    Vector support), the use of Ack Vectors is here disabled, with a comment
>    in the source code.
> 
> An analogous consideration arises for the Send Loss Event Rate feature,
> since the CCID-3 implementation does not support the loss interval options
> of RFC 4342. To make such use explicit, corresponding feature-negotiation
> options are inserted which signal the use of the loss event rate option,
> as it is used by the CCID3 code.
> 
> Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.
> 
> The patch implements this as a function which is called after the user has
> made all other registrations for changing default values of features.
> 
> The table is variable-length, the reserved (and hence for feature-negotiation
> invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
> is used to mark the end of the table.

Doesn't this belongs into struct ccid_operations? Why has the core feature
negotiation have knowledge of any specific CCID? When people want to
merge CCID 4, 5, etc will we need to change net/dccp/feat.c?

I think that this needs thus to go to struct ccid_operations, and then the feature
negotiation code can just use use the ccid number to access:

struct ccid_operations *ccids[CCID_MAX]

ccids[ccid_number]->deps
 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/dccp.h   |    1 +
>  net/dccp/feat.c   |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  net/dccp/output.c |    4 +
>  net/dccp/proto.c  |    3 +
>  4 files changed, 168 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
>  	       inet_csk_ack_scheduled(sk);
>  }
>  
> +extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
>  extern void dccp_feat_list_purge(struct list_head *fn_list);
>  
>  extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -438,6 +438,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
>  
>  EXPORT_SYMBOL_GPL(dccp_feat_change);
>  
> +/*
> + *	Tracking features whose value depend on the choice of CCID
> + *
> + * This is designed with an extension in mind so that a list walk could be done
> + * before activating any features. However, the existing framework was found to
> + * work satisfactorily up until now, the automatic verification is left open.
> + * When adding new CCIDs, add a corresponding dependency table here.
> + */
> +static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
> +{
> +	static const struct ccid_dependency ccid2_dependencies[2][2] = {
> +		/*
> +		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
> +		 * feature and Send Ack Vector is an RX feature, `is_local'
> +		 * needs to be reversed.
> +		 */
> +		{	/* Dependencies of the receiver-side (remote) CCID2 */
> +			{
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= true,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 }
> +		},
> +		{	/* Dependencies of the sender-side (local) CCID2 */
> +			{
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= false,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 }
> +		}
> +	};
> +	static const struct ccid_dependency ccid3_dependencies[2][5] = {
> +		{	/*
> +			 * Dependencies of the receiver-side CCID3
> +			 */
> +			{	/* locally disable Ack Vectors */
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= true,
> +				.is_mandatory	= false,
> +				.val		= 0
> +			},
> +			{	/* see below why Send Loss Event Rate is on */
> +				.dependent_feat	= DCCPF_SEND_LEV_RATE,
> +				.is_local	= true,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
> +				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
> +				.is_local	= false,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 },
> +		},
> +		{	/*
> +			 * CCID3 at the TX side: we request that the HC-receiver
> +			 * will not send Ack Vectors (they will be ignored, so
> +			 * Mandatory is not set); we enable Send Loss Event Rate
> +			 * (Mandatory since the implementation does not support
> +			 * the Loss Intervals option of RFC 4342, 8.6).
> +			 * The last two options are for peer's information only.
> +			*/
> +			{
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= false,
> +				.is_mandatory	= false,
> +				.val		= 0
> +			},
> +			{
> +				.dependent_feat	= DCCPF_SEND_LEV_RATE,
> +				.is_local	= false,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{	/* this CCID does not support Ack Ratio */
> +				.dependent_feat	= DCCPF_ACK_RATIO,
> +				.is_local	= true,
> +				.is_mandatory	= false,
> +				.val		= 0
> +			},
> +			{	/* tell receiver we are sending NDP counts */
> +				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
> +				.is_local	= true,
> +				.is_mandatory	= false,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 }
> +		}
> +	};
> +	switch (ccid) {
> +	case DCCPC_CCID2:
> +		return ccid2_dependencies[is_local];
> +	case DCCPC_CCID3:
> +		return ccid3_dependencies[is_local];
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +/**
> + * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
> + * @fn: feature-negotiation list to update
> + * @id: CCID number to track
> + * @is_local: whether TX CCID (1) or RX CCID (0) is meant
> + * This function needs to be called after registering all other features.
> + */
> +static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
> +{
> +	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
> +	int i, rc = (table == NULL);
> +
> +	for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
> +		if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
> +			rc = __feat_register_sp(fn, table[i].dependent_feat,
> +						    table[i].is_local,
> +						    table[i].is_mandatory,
> +						    &table[i].val, 1);
> +		else
> +			rc = __feat_register_nn(fn, table[i].dependent_feat,
> +						    table[i].is_mandatory,
> +						    table[i].val);
> +	return rc;
> +}
> +
> +/**
> + * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
> + * @dp: client or listening socket (settings will be inherited)
> + * This is called after all registrations (socket initialisation, sysctls, and
> + * sockopt calls), and before sending the first packet containing Change options
> + * (ie. client-Request or server-Response), to ensure internal consistency.
> + */
> +int dccp_feat_finalise_settings(struct dccp_sock *dp)
> +{
> +	struct list_head *fn = &dp->dccps_featneg;
> +	struct dccp_feat_entry *entry;
> +	int i = 2, ccids[2] = { -1, -1 };
> +
> +	/*
> +	 * Propagating CCIDs:
> +	 * 1) not useful to propagate CCID settings if this host advertises more
> +	 *    than one CCID: the choice of CCID  may still change - if this is
> +	 *    the client, or if this is the server and the client sends
> +	 *    singleton CCID values.
> +	 * 2) since is that propagate_ccid changes the list, we defer changing
> +	 *    the sorted list until after the traversal.
> +	 */
> +	list_for_each_entry(entry, fn, node)
> +		if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
> +			ccids[entry->is_local] = entry->val.sp.vec[0];
> +	while (i--)
> +		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
> +			return -1;
> +	return 0;
> +}
> +
>  static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
>  {
>  	struct dccp_sock *dp = dccp_sk(sk);
> --- a/net/dccp/output.c
> +++ b/net/dccp/output.c
> @@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
>  	struct sk_buff *skb;
>  	struct inet_connection_sock *icsk = inet_csk(sk);
>  
> +	/* do not connect if feature negotiation setup fails */
> +	if (dccp_feat_finalise_settings(dccp_sk(sk)))
> +		return -EPROTO;
> +
>  	dccp_connect_init(sk);
>  
>  	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
>  	struct dccp_sock *dp = dccp_sk(sk);
>  
>  	dp->dccps_role = DCCP_ROLE_LISTEN;
> +	/* do not start to listen if feature negotiation setup fails */
> +	if (dccp_feat_finalise_settings(dp))
> +		return -EPROTO;
>  	return inet_csk_listen_start(sk, backlog);
>  }
>  
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice
@ 2008-08-28 21:07                       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:07 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:44PM +0200, Gerrit Renker escreveu:
> This provides a missing link in the code chain, as several features implicitly
> depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
> feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
> 
> For Send Ack Vector, the situation is as follows:
>  * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
>    endpoints which use CCID2 to disable Ack Vector features such a connection;
> 
>  * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
>    with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);
> 
>  * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
>    negotiable. However, this implies that the code negotiating the use of Ack
>    Vectors also supports it (i.e. is able to supply and to either parse or
>    ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
>    Vector support), the use of Ack Vectors is here disabled, with a comment
>    in the source code.
> 
> An analogous consideration arises for the Send Loss Event Rate feature,
> since the CCID-3 implementation does not support the loss interval options
> of RFC 4342. To make such use explicit, corresponding feature-negotiation
> options are inserted which signal the use of the loss event rate option,
> as it is used by the CCID3 code.
> 
> Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.
> 
> The patch implements this as a function which is called after the user has
> made all other registrations for changing default values of features.
> 
> The table is variable-length, the reserved (and hence for feature-negotiation
> invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
> is used to mark the end of the table.

Doesn't this belongs into struct ccid_operations? Why has the core feature
negotiation have knowledge of any specific CCID? When people want to
merge CCID 4, 5, etc will we need to change net/dccp/feat.c?

I think that this needs thus to go to struct ccid_operations, and then the feature
negotiation code can just use use the ccid number to access:

struct ccid_operations *ccids[CCID_MAX]

ccids[ccid_number]->deps
 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/dccp.h   |    1 +
>  net/dccp/feat.c   |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  net/dccp/output.c |    4 +
>  net/dccp/proto.c  |    3 +
>  4 files changed, 168 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
>  	       inet_csk_ack_scheduled(sk);
>  }
>  
> +extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
>  extern void dccp_feat_list_purge(struct list_head *fn_list);
>  
>  extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -438,6 +438,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
>  
>  EXPORT_SYMBOL_GPL(dccp_feat_change);
>  
> +/*
> + *	Tracking features whose value depend on the choice of CCID
> + *
> + * This is designed with an extension in mind so that a list walk could be done
> + * before activating any features. However, the existing framework was found to
> + * work satisfactorily up until now, the automatic verification is left open.
> + * When adding new CCIDs, add a corresponding dependency table here.
> + */
> +static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
> +{
> +	static const struct ccid_dependency ccid2_dependencies[2][2] = {
> +		/*
> +		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
> +		 * feature and Send Ack Vector is an RX feature, `is_local'
> +		 * needs to be reversed.
> +		 */
> +		{	/* Dependencies of the receiver-side (remote) CCID2 */
> +			{
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= true,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 }
> +		},
> +		{	/* Dependencies of the sender-side (local) CCID2 */
> +			{
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= false,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 }
> +		}
> +	};
> +	static const struct ccid_dependency ccid3_dependencies[2][5] = {
> +		{	/*
> +			 * Dependencies of the receiver-side CCID3
> +			 */
> +			{	/* locally disable Ack Vectors */
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= true,
> +				.is_mandatory	= false,
> +				.val		= 0
> +			},
> +			{	/* see below why Send Loss Event Rate is on */
> +				.dependent_feat	= DCCPF_SEND_LEV_RATE,
> +				.is_local	= true,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
> +				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
> +				.is_local	= false,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 },
> +		},
> +		{	/*
> +			 * CCID3 at the TX side: we request that the HC-receiver
> +			 * will not send Ack Vectors (they will be ignored, so
> +			 * Mandatory is not set); we enable Send Loss Event Rate
> +			 * (Mandatory since the implementation does not support
> +			 * the Loss Intervals option of RFC 4342, 8.6).
> +			 * The last two options are for peer's information only.
> +			*/
> +			{
> +				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
> +				.is_local	= false,
> +				.is_mandatory	= false,
> +				.val		= 0
> +			},
> +			{
> +				.dependent_feat	= DCCPF_SEND_LEV_RATE,
> +				.is_local	= false,
> +				.is_mandatory	= true,
> +				.val		= 1
> +			},
> +			{	/* this CCID does not support Ack Ratio */
> +				.dependent_feat	= DCCPF_ACK_RATIO,
> +				.is_local	= true,
> +				.is_mandatory	= false,
> +				.val		= 0
> +			},
> +			{	/* tell receiver we are sending NDP counts */
> +				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
> +				.is_local	= true,
> +				.is_mandatory	= false,
> +				.val		= 1
> +			},
> +			{ 0, 0, 0, 0 }
> +		}
> +	};
> +	switch (ccid) {
> +	case DCCPC_CCID2:
> +		return ccid2_dependencies[is_local];
> +	case DCCPC_CCID3:
> +		return ccid3_dependencies[is_local];
> +	default:
> +		return NULL;
> +	}
> +}
> +
> +/**
> + * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
> + * @fn: feature-negotiation list to update
> + * @id: CCID number to track
> + * @is_local: whether TX CCID (1) or RX CCID (0) is meant
> + * This function needs to be called after registering all other features.
> + */
> +static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
> +{
> +	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
> +	int i, rc = (table = NULL);
> +
> +	for (i = 0; rc = 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
> +		if (dccp_feat_type(table[i].dependent_feat) = FEAT_SP)
> +			rc = __feat_register_sp(fn, table[i].dependent_feat,
> +						    table[i].is_local,
> +						    table[i].is_mandatory,
> +						    &table[i].val, 1);
> +		else
> +			rc = __feat_register_nn(fn, table[i].dependent_feat,
> +						    table[i].is_mandatory,
> +						    table[i].val);
> +	return rc;
> +}
> +
> +/**
> + * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
> + * @dp: client or listening socket (settings will be inherited)
> + * This is called after all registrations (socket initialisation, sysctls, and
> + * sockopt calls), and before sending the first packet containing Change options
> + * (ie. client-Request or server-Response), to ensure internal consistency.
> + */
> +int dccp_feat_finalise_settings(struct dccp_sock *dp)
> +{
> +	struct list_head *fn = &dp->dccps_featneg;
> +	struct dccp_feat_entry *entry;
> +	int i = 2, ccids[2] = { -1, -1 };
> +
> +	/*
> +	 * Propagating CCIDs:
> +	 * 1) not useful to propagate CCID settings if this host advertises more
> +	 *    than one CCID: the choice of CCID  may still change - if this is
> +	 *    the client, or if this is the server and the client sends
> +	 *    singleton CCID values.
> +	 * 2) since is that propagate_ccid changes the list, we defer changing
> +	 *    the sorted list until after the traversal.
> +	 */
> +	list_for_each_entry(entry, fn, node)
> +		if (entry->feat_num = DCCPF_CCID && entry->val.sp.len = 1)
> +			ccids[entry->is_local] = entry->val.sp.vec[0];
> +	while (i--)
> +		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
> +			return -1;
> +	return 0;
> +}
> +
>  static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
>  {
>  	struct dccp_sock *dp = dccp_sk(sk);
> --- a/net/dccp/output.c
> +++ b/net/dccp/output.c
> @@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
>  	struct sk_buff *skb;
>  	struct inet_connection_sock *icsk = inet_csk(sk);
>  
> +	/* do not connect if feature negotiation setup fails */
> +	if (dccp_feat_finalise_settings(dccp_sk(sk)))
> +		return -EPROTO;
> +
>  	dccp_connect_init(sk);
>  
>  	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
>  	struct dccp_sock *dp = dccp_sk(sk);
>  
>  	dp->dccps_role = DCCP_ROLE_LISTEN;
> +	/* do not start to listen if feature negotiation setup fails */
> +	if (dccp_feat_finalise_settings(dp))
> +		return -EPROTO;
>  	return inet_csk_listen_start(sk, backlog);
>  }
>  
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage
  2008-08-28 17:44                           ` Gerrit Renker
@ 2008-08-28 21:25                             ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:25 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:47PM +0200, Gerrit Renker escreveu:
> This provides feature negotiation for server minimum checksum coverage
> which so far has been missing.
> 
> Since sender/receiver coverage values range only from 0...15, their
> type has also been reduced in size from u16 to u4.
> 
> Feature-negotiation options are now generated for both sender and receiver
> coverage, i.e. when the peer has `forgotten' to enable partial coverage
> then feature negotiation will automatically enable (negotiate) the partial
> coverage value for this connection.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    4 +-
>  net/dccp/proto.c     |   52 +++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 41 insertions(+), 15 deletions(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -527,8 +527,8 @@ struct dccp_sock {
>  	__u32				dccps_timestamp_time;
>  	__u16				dccps_l_ack_ratio;
>  	__u16				dccps_r_ack_ratio;
> -	__u16				dccps_pcslen;
> -	__u16				dccps_pcrlen;
> +	__u8				dccps_pcslen:4;
> +	__u8				dccps_pcrlen:4;
>  	__u64				dccps_ndp_count:48;
>  	unsigned long			dccps_rate_last;
>  	struct dccp_minisock		dccps_minisock;
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -470,6 +470,41 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
>  	return 0;
>  }
>  
> +static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
> +{
> +	u8 *list, len;
> +	int i, rc;
> +
> +	if (cscov < 0 || cscov > 15)
> +		return -EINVAL;
> +
> +	if (rx)
> +		dccp_sk(sk)->dccps_pcrlen = cscov;
> +	else
> +		dccp_sk(sk)->dccps_pcslen = cscov;

Wouldn't be better to change socket internal state only after the
kmalloc? Perhaps even only if dccp_feat_register_sp was successful?

> +	/*
> +	 * Populate a list of permissible values, in the range cscov...15. This
> +	 * is necessary since feature negotiation of single values only works if
> +	 * both sides incidentally choose the same value. Since the list starts
> +	 * lowest-value first, negotiation will pick the smallest shared value.
> +	 */
> +	if (cscov == 0)
> +		return 0;
> +	len = 16 - cscov;
> +
> +	list = kmalloc(len, GFP_KERNEL);
> +	if (list == NULL)
> +		return -ENOBUFS;
> +
> +	for (i = 0; i < len; i++)
> +		list[i] = cscov++;
> +
> +	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
> +
> +	kfree(list);
> +	return rc;
> +}
> +
>  static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		char __user *optval, int optlen)
>  {
> @@ -502,20 +537,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		else
>  			dp->dccps_server_timewait = (val != 0);
>  		break;
> -	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
> -		if (val < 0 || val > 15)
> -			err = -EINVAL;
> -		else
> -			dp->dccps_pcslen = val;
> +	case DCCP_SOCKOPT_SEND_CSCOV:
> +		err = dccp_setsockopt_cscov(sk, val, false);
>  		break;
> -	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
> -		if (val < 0 || val > 15)
> -			err = -EINVAL;
> -		else {
> -			dp->dccps_pcrlen = val;
> -			/* FIXME: add feature negotiation,
> -			 * ChangeL(MinimumChecksumCoverage, val) */
> -		}
> +	case DCCP_SOCKOPT_RECV_CSCOV:
> +		err = dccp_setsockopt_cscov(sk, val, true);
>  		break;
>  	default:
>  		err = -ENOPROTOOPT;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 12/37] dccp: Feature negotiation for
@ 2008-08-28 21:25                             ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:25 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:47PM +0200, Gerrit Renker escreveu:
> This provides feature negotiation for server minimum checksum coverage
> which so far has been missing.
> 
> Since sender/receiver coverage values range only from 0...15, their
> type has also been reduced in size from u16 to u4.
> 
> Feature-negotiation options are now generated for both sender and receiver
> coverage, i.e. when the peer has `forgotten' to enable partial coverage
> then feature negotiation will automatically enable (negotiate) the partial
> coverage value for this connection.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    4 +-
>  net/dccp/proto.c     |   52 +++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 41 insertions(+), 15 deletions(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -527,8 +527,8 @@ struct dccp_sock {
>  	__u32				dccps_timestamp_time;
>  	__u16				dccps_l_ack_ratio;
>  	__u16				dccps_r_ack_ratio;
> -	__u16				dccps_pcslen;
> -	__u16				dccps_pcrlen;
> +	__u8				dccps_pcslen:4;
> +	__u8				dccps_pcrlen:4;
>  	__u64				dccps_ndp_count:48;
>  	unsigned long			dccps_rate_last;
>  	struct dccp_minisock		dccps_minisock;
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -470,6 +470,41 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
>  	return 0;
>  }
>  
> +static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
> +{
> +	u8 *list, len;
> +	int i, rc;
> +
> +	if (cscov < 0 || cscov > 15)
> +		return -EINVAL;
> +
> +	if (rx)
> +		dccp_sk(sk)->dccps_pcrlen = cscov;
> +	else
> +		dccp_sk(sk)->dccps_pcslen = cscov;

Wouldn't be better to change socket internal state only after the
kmalloc? Perhaps even only if dccp_feat_register_sp was successful?

> +	/*
> +	 * Populate a list of permissible values, in the range cscov...15. This
> +	 * is necessary since feature negotiation of single values only works if
> +	 * both sides incidentally choose the same value. Since the list starts
> +	 * lowest-value first, negotiation will pick the smallest shared value.
> +	 */
> +	if (cscov = 0)
> +		return 0;
> +	len = 16 - cscov;
> +
> +	list = kmalloc(len, GFP_KERNEL);
> +	if (list = NULL)
> +		return -ENOBUFS;
> +
> +	for (i = 0; i < len; i++)
> +		list[i] = cscov++;
> +
> +	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
> +
> +	kfree(list);
> +	return rc;
> +}
> +
>  static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		char __user *optval, int optlen)
>  {
> @@ -502,20 +537,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		else
>  			dp->dccps_server_timewait = (val != 0);
>  		break;
> -	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
> -		if (val < 0 || val > 15)
> -			err = -EINVAL;
> -		else
> -			dp->dccps_pcslen = val;
> +	case DCCP_SOCKOPT_SEND_CSCOV:
> +		err = dccp_setsockopt_cscov(sk, val, false);
>  		break;
> -	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
> -		if (val < 0 || val > 15)
> -			err = -EINVAL;
> -		else {
> -			dp->dccps_pcrlen = val;
> -			/* FIXME: add feature negotiation,
> -			 * ChangeL(MinimumChecksumCoverage, val) */
> -		}
> +	case DCCP_SOCKOPT_RECV_CSCOV:
> +		err = dccp_setsockopt_cscov(sk, val, true);
>  		break;
>  	default:
>  		err = -ENOPROTOOPT;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 13/37] dccp: Deprecate Ack Ratio sysctl
  2008-08-28 17:44                             ` Gerrit Renker
@ 2008-08-28 21:26                               ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:26 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:48PM +0200, Gerrit Renker escreveu:
> This patch deprecates the Ack Ratio sysctl, since
>  * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
>  * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
>  * even if it would work in CCID-2, there is no point for a user to change it:
>    - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
>    - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
>      (since waiting for Acks which will never arrive in this window),
>    - cwnd is not a user-configurable value.
> 
> The only reasonable place for Ack Ratio is to print it for debugging. It is
> planned to do this later on, as part of e.g. dccp_probe.
> 
> With this patch Ack Ratio is now under full control of feature negotiation:
>  * Ack Ratio is resolved as a dependency of the selected CCID;
>  * if the chosen CCID supports it (i.e. CCID == CCID-2), Ack Ratio is set to
>    the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
>    Ratio 2 for both endpoints";
>  * what happens then is part of another patch set, since it concerns the
>    dynamic update of Ack Ratio while the connection is in full flight.
> 
> Thanks to Tomasz Grobelny for discussion leading up to this patch.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Looks ok,

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> ---
>  Documentation/networking/dccp.txt |    3 ---
>  include/linux/dccp.h              |    2 --
>  net/dccp/dccp.h                   |    1 -
>  net/dccp/minisocks.c              |    1 -
>  net/dccp/options.c                |    1 -
>  net/dccp/sysctl.c                 |    7 -------
>  6 files changed, 0 insertions(+), 15 deletions(-)
> 
> --- a/Documentation/networking/dccp.txt
> +++ b/Documentation/networking/dccp.txt
> @@ -125,9 +125,6 @@ send_ndp = 1
>  send_ackvec = 1
>  	Whether or not to send Ack Vector options (sec. 11.5).
>  
> -ack_ratio = 2
> -	The default Ack Ratio (sec. 11.3) to use.
> -
>  tx_ccid = 2
>  	Default CCID for the sender-receiver half-connection.
>  
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -368,7 +368,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>    * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
>    * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
>    * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
> -  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
>    * @dccpms_pending - List of features being negotiated
>    * @dccpms_conf -
>    */
> @@ -378,7 +377,6 @@ struct dccp_minisock {
>  	__u8			dccpms_tx_ccid;
>  	__u8			dccpms_send_ack_vector;
>  	__u8			dccpms_send_ndp_count;
> -	__u8			dccpms_ack_ratio;
>  	struct list_head	dccpms_pending;
>  	struct list_head	dccpms_conf;
>  };
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
>  extern int  sysctl_dccp_feat_sequence_window;
>  extern int  sysctl_dccp_feat_rx_ccid;
>  extern int  sysctl_dccp_feat_tx_ccid;
> -extern int  sysctl_dccp_feat_ack_ratio;
>  extern int  sysctl_dccp_feat_send_ack_vector;
>  extern int  sysctl_dccp_feat_send_ndp_count;
>  extern int  sysctl_dccp_tx_qlen;
> --- a/net/dccp/minisocks.c
> +++ b/net/dccp/minisocks.c
> @@ -47,7 +47,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
>  	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
>  	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
>  	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
> -	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
>  	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
>  	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
>  }
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -26,7 +26,6 @@
>  int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
>  int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
>  int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
> -int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
>  int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
>  int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
>  
> --- a/net/dccp/sysctl.c
> +++ b/net/dccp/sysctl.c
> @@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
>  		.proc_handler	= proc_dointvec,
>  	},
>  	{
> -		.procname	= "ack_ratio",
> -		.data		= &sysctl_dccp_feat_ack_ratio,
> -		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
> -		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> -	},
> -	{
>  		.procname	= "send_ackvec",
>  		.data		= &sysctl_dccp_feat_send_ack_vector,
>  		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 13/37] dccp: Deprecate Ack Ratio sysctl
@ 2008-08-28 21:26                               ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:26 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:48PM +0200, Gerrit Renker escreveu:
> This patch deprecates the Ack Ratio sysctl, since
>  * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
>  * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
>  * even if it would work in CCID-2, there is no point for a user to change it:
>    - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
>    - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
>      (since waiting for Acks which will never arrive in this window),
>    - cwnd is not a user-configurable value.
> 
> The only reasonable place for Ack Ratio is to print it for debugging. It is
> planned to do this later on, as part of e.g. dccp_probe.
> 
> With this patch Ack Ratio is now under full control of feature negotiation:
>  * Ack Ratio is resolved as a dependency of the selected CCID;
>  * if the chosen CCID supports it (i.e. CCID = CCID-2), Ack Ratio is set to
>    the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
>    Ratio 2 for both endpoints";
>  * what happens then is part of another patch set, since it concerns the
>    dynamic update of Ack Ratio while the connection is in full flight.
> 
> Thanks to Tomasz Grobelny for discussion leading up to this patch.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Looks ok,

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> ---
>  Documentation/networking/dccp.txt |    3 ---
>  include/linux/dccp.h              |    2 --
>  net/dccp/dccp.h                   |    1 -
>  net/dccp/minisocks.c              |    1 -
>  net/dccp/options.c                |    1 -
>  net/dccp/sysctl.c                 |    7 -------
>  6 files changed, 0 insertions(+), 15 deletions(-)
> 
> --- a/Documentation/networking/dccp.txt
> +++ b/Documentation/networking/dccp.txt
> @@ -125,9 +125,6 @@ send_ndp = 1
>  send_ackvec = 1
>  	Whether or not to send Ack Vector options (sec. 11.5).
>  
> -ack_ratio = 2
> -	The default Ack Ratio (sec. 11.3) to use.
> -
>  tx_ccid = 2
>  	Default CCID for the sender-receiver half-connection.
>  
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -368,7 +368,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>    * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
>    * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
>    * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
> -  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
>    * @dccpms_pending - List of features being negotiated
>    * @dccpms_conf -
>    */
> @@ -378,7 +377,6 @@ struct dccp_minisock {
>  	__u8			dccpms_tx_ccid;
>  	__u8			dccpms_send_ack_vector;
>  	__u8			dccpms_send_ndp_count;
> -	__u8			dccpms_ack_ratio;
>  	struct list_head	dccpms_pending;
>  	struct list_head	dccpms_conf;
>  };
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
>  extern int  sysctl_dccp_feat_sequence_window;
>  extern int  sysctl_dccp_feat_rx_ccid;
>  extern int  sysctl_dccp_feat_tx_ccid;
> -extern int  sysctl_dccp_feat_ack_ratio;
>  extern int  sysctl_dccp_feat_send_ack_vector;
>  extern int  sysctl_dccp_feat_send_ndp_count;
>  extern int  sysctl_dccp_tx_qlen;
> --- a/net/dccp/minisocks.c
> +++ b/net/dccp/minisocks.c
> @@ -47,7 +47,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
>  	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
>  	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
>  	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
> -	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
>  	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
>  	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
>  }
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -26,7 +26,6 @@
>  int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
>  int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
>  int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
> -int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
>  int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
>  int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
>  
> --- a/net/dccp/sysctl.c
> +++ b/net/dccp/sysctl.c
> @@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
>  		.proc_handler	= proc_dointvec,
>  	},
>  	{
> -		.procname	= "ack_ratio",
> -		.data		= &sysctl_dccp_feat_ack_ratio,
> -		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
> -		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> -	},
> -	{
>  		.procname	= "send_ackvec",
>  		.data		= &sysctl_dccp_feat_send_ack_vector,
>  		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
  2008-08-28 17:44                               ` Gerrit Renker
@ 2008-08-28 21:35                                 ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:35 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:49PM +0200, Gerrit Renker escreveu:
> This splits the setsockopt calls into two groups, depending on whether an
> integer argument (val) is required and whether routines being called do
> their own locking.
> 
> Some options (such as setting the CCID) use u8 rather than int, so that for
> these the test with regard to integer-sizeof can not be used.
> 
> The second switch-case statement now only has those statements which need
> locking and which make use of `val'.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>



> ---
>  net/dccp/proto.c |   31 ++++++++++++++++---------------
>  1 files changed, 16 insertions(+), 15 deletions(-)
> 
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -511,26 +511,27 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  	struct dccp_sock *dp = dccp_sk(sk);
>  	int val, err = 0;
>  
> -	if (optlen < sizeof(int))
> -		return -EINVAL;
> -
> -	if (get_user(val, (int __user *)optval))
> -		return -EFAULT;
> -
> -	if (optname == DCCP_SOCKOPT_SERVICE)
> -		return dccp_setsockopt_service(sk, val, optval, optlen);
> -
> -	lock_sock(sk);
>  	switch (optname) {
>  	case DCCP_SOCKOPT_PACKET_SIZE:
>  		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
> -		err = 0;
> -		break;
> +		return 0;
>  	case DCCP_SOCKOPT_CHANGE_L:
>  	case DCCP_SOCKOPT_CHANGE_R:
>  		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
> -		err = 0;
> -		break;
> +		return 0;
> +	default:
> +		if (optlen < sizeof(int))
> +			return -EINVAL;
> +
> +		if (get_user(val, (int __user *)optval))
> +			return -EFAULT;
> +
> +		if (optname == DCCP_SOCKOPT_SERVICE)
> +			return dccp_setsockopt_service(sk, val, optval, optlen);

What is in the default could well continue outside the switch
statatement, since all the other cases return directly.

Other than that:

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> +	}
> +
> +	lock_sock(sk);
> +	switch (optname) {
>  	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
>  		if (dp->dccps_role != DCCP_ROLE_SERVER)
>  			err = -EOPNOTSUPP;
> @@ -547,8 +548,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		err = -ENOPROTOOPT;
>  		break;
>  	}
> -
>  	release_sock(sk);
> +
>  	return err;
>  }
>  
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
@ 2008-08-28 21:35                                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:35 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:49PM +0200, Gerrit Renker escreveu:
> This splits the setsockopt calls into two groups, depending on whether an
> integer argument (val) is required and whether routines being called do
> their own locking.
> 
> Some options (such as setting the CCID) use u8 rather than int, so that for
> these the test with regard to integer-sizeof can not be used.
> 
> The second switch-case statement now only has those statements which need
> locking and which make use of `val'.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>



> ---
>  net/dccp/proto.c |   31 ++++++++++++++++---------------
>  1 files changed, 16 insertions(+), 15 deletions(-)
> 
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -511,26 +511,27 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  	struct dccp_sock *dp = dccp_sk(sk);
>  	int val, err = 0;
>  
> -	if (optlen < sizeof(int))
> -		return -EINVAL;
> -
> -	if (get_user(val, (int __user *)optval))
> -		return -EFAULT;
> -
> -	if (optname = DCCP_SOCKOPT_SERVICE)
> -		return dccp_setsockopt_service(sk, val, optval, optlen);
> -
> -	lock_sock(sk);
>  	switch (optname) {
>  	case DCCP_SOCKOPT_PACKET_SIZE:
>  		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
> -		err = 0;
> -		break;
> +		return 0;
>  	case DCCP_SOCKOPT_CHANGE_L:
>  	case DCCP_SOCKOPT_CHANGE_R:
>  		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
> -		err = 0;
> -		break;
> +		return 0;
> +	default:
> +		if (optlen < sizeof(int))
> +			return -EINVAL;
> +
> +		if (get_user(val, (int __user *)optval))
> +			return -EFAULT;
> +
> +		if (optname = DCCP_SOCKOPT_SERVICE)
> +			return dccp_setsockopt_service(sk, val, optval, optlen);

What is in the default could well continue outside the switch
statatement, since all the other cases return directly.

Other than that:

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> +	}
> +
> +	lock_sock(sk);
> +	switch (optname) {
>  	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
>  		if (dp->dccps_role != DCCP_ROLE_SERVER)
>  			err = -EOPNOTSUPP;
> @@ -547,8 +548,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		err = -ENOPROTOOPT;
>  		break;
>  	}
> -
>  	release_sock(sk);
> +
>  	return err;
>  }
>  
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
  2008-08-28 17:44                                 ` Gerrit Renker
@ 2008-08-28 21:45                                   ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:45 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:50PM +0200, Gerrit Renker escreveu:
> With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
> overrides the defaults set by the global sysctl variables for TX/RX CCIDs.
> 
> To make full use of this facility, the remaining patches of this patch set are
> needed, which track dependencies and activate negotiated feature values.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  Documentation/networking/dccp.txt |   14 ++++++++++++++
>  include/linux/dccp.h              |    5 +++++
>  net/dccp/proto.c                  |   32 ++++++++++++++++++++++++++++++++
>  3 files changed, 51 insertions(+), 0 deletions(-)
> 
> --- a/Documentation/networking/dccp.txt
> +++ b/Documentation/networking/dccp.txt
> @@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
>  supported by the endpoint (see include/linux/dccp.h for symbolic constants).
>  The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
>  
> +DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
> +time, combining the operation of the next two socket options. This option is
> +preferrable over the latter two, since often applications will use the same
> +type of CCID for both directions; and mixed use of CCIDs is not currently well
> +understood. This socket option takes as argument at least one uint8_t value, or
> +an array of uint8_t values, which must match available CCIDS (see above). CCIDs
> +must be registered on the socket before calling connect() or listen().
> +
> +DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
> +the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
> +Please note that the getsockopt argument type here is `int', not uint8_t.
> +
> +DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
> +
>  DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
>  timewait state when closing the connection (RFC 4340, 8.3). The usual case is
>  that the closing server sends a CloseReq, whereupon the client holds timewait
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -203,11 +203,16 @@ enum dccp_feature_numbers {
>  #define DCCP_SOCKOPT_SEND_CSCOV		10
>  #define DCCP_SOCKOPT_RECV_CSCOV		11
>  #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
> +#define DCCP_SOCKOPT_CCID		13
> +#define DCCP_SOCKOPT_TX_CCID		14
> +#define DCCP_SOCKOPT_RX_CCID		15
>  #define DCCP_SOCKOPT_CCID_RX_INFO	128
>  #define DCCP_SOCKOPT_CCID_TX_INFO	192
>  
>  /* maximum number of services provided on the same listening port */
>  #define DCCP_SERVICE_LIST_MAX_LEN      32
> +/* maximum number of CCID preferences that can be registered at one time */
> +#define DCCP_CCID_LIST_MAX_LEN	       16

Since this is an arbitrary lenght up to 253, it could as well be 253,
no? Or is there any other limit that I'm forgetting? :-) It may well be
that case, would have to read the RFC about how the encoding is done for
feat len, which I did some weeks ago, but...
  
>  #ifdef __KERNEL__
>  
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -505,6 +505,34 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
>  	return rc;
>  }
>  
> +static int dccp_setsockopt_ccid(struct sock *sk, int type,
> +				char __user *optval, int optlen)
> +{
> +	u8 *val;
> +	int rc = 0;
> +
> +	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
> +		return -EINVAL;
> +
> +	val = kmalloc(optlen, GFP_KERNEL);
> +	if (val == NULL)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(val, optval, optlen))
> +		rc = -EFAULT;
> +
> +	lock_sock(sk);
> +	if (!rc && (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID))
> +		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
> +

This _really_ is confusing! Why not:

	rc = -EFAULT;
	if (copy_from_user(val, optval, optlen))
		goto out;

	lock_sock(sk);
	rc = 0;
	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);

	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
	release_sock(sk);
out:
> +	kfree(val);
> +	return rc;
> +}

:-)

And even then that '0' or '1' requires one to look at what this binary
number means, we could have something like
dccp_feat_register_sp_{local,remote} perhaps, IIRC that is the is_local
parameter, no?

> +
>  static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		char __user *optval, int optlen)
>  {
> @@ -519,6 +547,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  	case DCCP_SOCKOPT_CHANGE_R:
>  		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
>  		return 0;
> +	case DCCP_SOCKOPT_CCID:
> +	case DCCP_SOCKOPT_RX_CCID:
> +	case DCCP_SOCKOPT_TX_CCID:
> +		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
>  	default:
>  		if (optlen < sizeof(int))
>  			return -EINVAL;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
@ 2008-08-28 21:45                                   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:45 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:50PM +0200, Gerrit Renker escreveu:
> With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
> overrides the defaults set by the global sysctl variables for TX/RX CCIDs.
> 
> To make full use of this facility, the remaining patches of this patch set are
> needed, which track dependencies and activate negotiated feature values.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  Documentation/networking/dccp.txt |   14 ++++++++++++++
>  include/linux/dccp.h              |    5 +++++
>  net/dccp/proto.c                  |   32 ++++++++++++++++++++++++++++++++
>  3 files changed, 51 insertions(+), 0 deletions(-)
> 
> --- a/Documentation/networking/dccp.txt
> +++ b/Documentation/networking/dccp.txt
> @@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
>  supported by the endpoint (see include/linux/dccp.h for symbolic constants).
>  The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
>  
> +DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
> +time, combining the operation of the next two socket options. This option is
> +preferrable over the latter two, since often applications will use the same
> +type of CCID for both directions; and mixed use of CCIDs is not currently well
> +understood. This socket option takes as argument at least one uint8_t value, or
> +an array of uint8_t values, which must match available CCIDS (see above). CCIDs
> +must be registered on the socket before calling connect() or listen().
> +
> +DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
> +the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
> +Please note that the getsockopt argument type here is `int', not uint8_t.
> +
> +DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
> +
>  DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
>  timewait state when closing the connection (RFC 4340, 8.3). The usual case is
>  that the closing server sends a CloseReq, whereupon the client holds timewait
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -203,11 +203,16 @@ enum dccp_feature_numbers {
>  #define DCCP_SOCKOPT_SEND_CSCOV		10
>  #define DCCP_SOCKOPT_RECV_CSCOV		11
>  #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
> +#define DCCP_SOCKOPT_CCID		13
> +#define DCCP_SOCKOPT_TX_CCID		14
> +#define DCCP_SOCKOPT_RX_CCID		15
>  #define DCCP_SOCKOPT_CCID_RX_INFO	128
>  #define DCCP_SOCKOPT_CCID_TX_INFO	192
>  
>  /* maximum number of services provided on the same listening port */
>  #define DCCP_SERVICE_LIST_MAX_LEN      32
> +/* maximum number of CCID preferences that can be registered at one time */
> +#define DCCP_CCID_LIST_MAX_LEN	       16

Since this is an arbitrary lenght up to 253, it could as well be 253,
no? Or is there any other limit that I'm forgetting? :-) It may well be
that case, would have to read the RFC about how the encoding is done for
feat len, which I did some weeks ago, but...
  
>  #ifdef __KERNEL__
>  
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -505,6 +505,34 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
>  	return rc;
>  }
>  
> +static int dccp_setsockopt_ccid(struct sock *sk, int type,
> +				char __user *optval, int optlen)
> +{
> +	u8 *val;
> +	int rc = 0;
> +
> +	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
> +		return -EINVAL;
> +
> +	val = kmalloc(optlen, GFP_KERNEL);
> +	if (val = NULL)
> +		return -ENOMEM;
> +
> +	if (copy_from_user(val, optval, optlen))
> +		rc = -EFAULT;
> +
> +	lock_sock(sk);
> +	if (!rc && (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID))
> +		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
> +

This _really_ is confusing! Why not:

	rc = -EFAULT;
	if (copy_from_user(val, optval, optlen))
		goto out;

	lock_sock(sk);
	rc = 0;
	if (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID)
		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);

	if (!rc && (type = DCCP_SOCKOPT_RX_CCID || type = DCCP_SOCKOPT_CCID))
		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
	release_sock(sk);
out:
> +	kfree(val);
> +	return rc;
> +}

:-)

And even then that '0' or '1' requires one to look at what this binary
number means, we could have something like
dccp_feat_register_sp_{local,remote} perhaps, IIRC that is the is_local
parameter, no?

> +
>  static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  		char __user *optval, int optlen)
>  {
> @@ -519,6 +547,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
>  	case DCCP_SOCKOPT_CHANGE_R:
>  		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
>  		return 0;
> +	case DCCP_SOCKOPT_CCID:
> +	case DCCP_SOCKOPT_RX_CCID:
> +	case DCCP_SOCKOPT_TX_CCID:
> +		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
>  	default:
>  		if (optlen < sizeof(int))
>  			return -EINVAL;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 16/37] dccp: API to query the current TX/RX CCID
  2008-08-28 17:44                                   ` Gerrit Renker
@ 2008-08-28 21:47                                     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:47 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:51PM +0200, Gerrit Renker escreveu:
> This provides function to query the current TX/RX CCID dynamically, without
> reliance on the minisock value, using dynamic information available in the
> currently loaded CCID module.
> 
> This query function is then used to
>  (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
>  (b) replace the current test for "which CCID is in use" in probe.c.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ccid.h  |    9 +++++++++
>  net/dccp/probe.c |    7 ++-----
>  net/dccp/proto.c |    6 ++++++
>  3 files changed, 17 insertions(+), 5 deletions(-)
> 
> --- a/net/dccp/ccid.h
> +++ b/net/dccp/ccid.h
> @@ -116,6 +116,15 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
>  extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
>  				   gfp_t gfp);
>  
> +static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
> +{
> +	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
> +
> +	if (ccid == NULL || ccid->ccid_ops == NULL)
> +		return -1;
> +	return ccid->ccid_ops->ccid_id;
> +}
> +
>  extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
>  extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
>  
> --- a/net/dccp/probe.c
> +++ b/net/dccp/probe.c
> @@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
>  static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
>  			 struct msghdr *msg, size_t size)
>  {
> -	const struct dccp_minisock *dmsk = dccp_msk(sk);
>  	const struct inet_sock *inet = inet_sk(sk);
> -	const struct ccid3_hc_tx_sock *hctx;
> +	struct ccid3_hc_tx_sock *hctx = NULL;
>  
> -	if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
> +	if (ccid_get_current_id(dccp_sk(sk), false) == DCCPC_CCID3)

The use of boolean here also hurts the brain, I guess we could have
ccid_get_current_rx_id or something along these lines?

>  		hctx = ccid3_hc_tx_sk(sk);
> -	else
> -		hctx = NULL;
>  
>  	if (port == 0 || ntohs(inet->dport) == port ||
>  	    ntohs(inet->sport) == port) {
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -664,6 +664,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
>  		break;
>  	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
>  		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
> +	case DCCP_SOCKOPT_TX_CCID:
> +	case DCCP_SOCKOPT_RX_CCID:
> +		val = ccid_get_current_id(dp, optname == DCCP_SOCKOPT_RX_CCID);
> +		if (val < 0)
> +			return -ENOPROTOOPT;
> +		break;
>  	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
>  		val = dp->dccps_server_timewait;
>  		break;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 16/37] dccp: API to query the current TX/RX CCID
@ 2008-08-28 21:47                                     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:47 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:51PM +0200, Gerrit Renker escreveu:
> This provides function to query the current TX/RX CCID dynamically, without
> reliance on the minisock value, using dynamic information available in the
> currently loaded CCID module.
> 
> This query function is then used to
>  (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
>  (b) replace the current test for "which CCID is in use" in probe.c.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ccid.h  |    9 +++++++++
>  net/dccp/probe.c |    7 ++-----
>  net/dccp/proto.c |    6 ++++++
>  3 files changed, 17 insertions(+), 5 deletions(-)
> 
> --- a/net/dccp/ccid.h
> +++ b/net/dccp/ccid.h
> @@ -116,6 +116,15 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
>  extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
>  				   gfp_t gfp);
>  
> +static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
> +{
> +	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
> +
> +	if (ccid = NULL || ccid->ccid_ops = NULL)
> +		return -1;
> +	return ccid->ccid_ops->ccid_id;
> +}
> +
>  extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
>  extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
>  
> --- a/net/dccp/probe.c
> +++ b/net/dccp/probe.c
> @@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
>  static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
>  			 struct msghdr *msg, size_t size)
>  {
> -	const struct dccp_minisock *dmsk = dccp_msk(sk);
>  	const struct inet_sock *inet = inet_sk(sk);
> -	const struct ccid3_hc_tx_sock *hctx;
> +	struct ccid3_hc_tx_sock *hctx = NULL;
>  
> -	if (dmsk->dccpms_tx_ccid = DCCPC_CCID3)
> +	if (ccid_get_current_id(dccp_sk(sk), false) = DCCPC_CCID3)

The use of boolean here also hurts the brain, I guess we could have
ccid_get_current_rx_id or something along these lines?

>  		hctx = ccid3_hc_tx_sk(sk);
> -	else
> -		hctx = NULL;
>  
>  	if (port = 0 || ntohs(inet->dport) = port ||
>  	    ntohs(inet->sport) = port) {
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -664,6 +664,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
>  		break;
>  	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
>  		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
> +	case DCCP_SOCKOPT_TX_CCID:
> +	case DCCP_SOCKOPT_RX_CCID:
> +		val = ccid_get_current_id(dp, optname = DCCP_SOCKOPT_RX_CCID);
> +		if (val < 0)
> +			return -ENOPROTOOPT;
> +		break;
>  	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
>  		val = dp->dccps_server_timewait;
>  		break;
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 17/37] dccp: Increase the scope of variable-length htonl/ntohl functions
  2008-08-28 17:44                                     ` Gerrit Renker
@ 2008-08-28 21:48                                       ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:48 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:52PM +0200, Gerrit Renker escreveu:
> This extends the scope of two available functions, encode|decode_value_var,
> to work up to 6 (8) bytes, to match maximum requirements in the RFC.
> 
> These functions are going to be used both by general option processing and
> feature negotiation code, hence declarations have been put into feat.h.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>


Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> ---
>  net/dccp/feat.h    |   14 ++++++++++++++
>  net/dccp/options.c |   21 ++++++++++++++-------
>  2 files changed, 28 insertions(+), 7 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -122,4 +122,18 @@ extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
>  extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
>  extern int  dccp_feat_init(struct sock *sk);
>  
> +/*
> + * Encoding variable-length options and their maximum length.
> + *
> + * This affects NN options (SP options are all u8) and other variable-length
> + * options (see table 3 in RFC 4340). The limit is currently given the Sequence
> + * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
> + * options consume less than 6 bytes (timestamps are 4 bytes).
> + * When updating this constant (e.g. due to new internet drafts / RFCs), make
> + * sure that you also update all code which refers to it.
> + */
> +#define DCCP_OPTVAL_MAXLEN	6
> +
> +extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
> +extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -29,16 +29,20 @@ int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
>  int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
>  int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
>  
> -static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
> +u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>  {
> -	u32 value = 0;
> +	u64 value = 0;
>  
> +	if (len >= DCCP_OPTVAL_MAXLEN)
> +		value += ((u64)*bf++) << 40;
> +	if (len > 4)
> +		value += ((u64)*bf++) << 32;
>  	if (len > 3)
> -		value += *bf++ << 24;
> +		value += ((u64)*bf++) << 24;
>  	if (len > 2)
> -		value += *bf++ << 16;
> +		value += ((u64)*bf++) << 16;
>  	if (len > 1)
> -		value += *bf++ << 8;
> +		value += ((u64)*bf++) << 8;
>  	if (len > 0)
>  		value += *bf;
>  
> @@ -298,9 +302,12 @@ out_invalid_option:
>  
>  EXPORT_SYMBOL_GPL(dccp_parse_options);
>  
> -static void dccp_encode_value_var(const u32 value, unsigned char *to,
> -				  const unsigned int len)
> +void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
>  {
> +	if (len >= DCCP_OPTVAL_MAXLEN)
> +		*to++ = (value & 0xFF0000000000ull) >> 40;
> +	if (len > 4)
> +		*to++ = (value & 0xFF00000000ull) >> 32;
>  	if (len > 3)
>  		*to++ = (value & 0xFF000000) >> 24;
>  	if (len > 2)
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 17/37] dccp: Increase the scope of variable-length
@ 2008-08-28 21:48                                       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:48 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:52PM +0200, Gerrit Renker escreveu:
> This extends the scope of two available functions, encode|decode_value_var,
> to work up to 6 (8) bytes, to match maximum requirements in the RFC.
> 
> These functions are going to be used both by general option processing and
> feature negotiation code, hence declarations have been put into feat.h.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>


Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> ---
>  net/dccp/feat.h    |   14 ++++++++++++++
>  net/dccp/options.c |   21 ++++++++++++++-------
>  2 files changed, 28 insertions(+), 7 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -122,4 +122,18 @@ extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
>  extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
>  extern int  dccp_feat_init(struct sock *sk);
>  
> +/*
> + * Encoding variable-length options and their maximum length.
> + *
> + * This affects NN options (SP options are all u8) and other variable-length
> + * options (see table 3 in RFC 4340). The limit is currently given the Sequence
> + * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
> + * options consume less than 6 bytes (timestamps are 4 bytes).
> + * When updating this constant (e.g. due to new internet drafts / RFCs), make
> + * sure that you also update all code which refers to it.
> + */
> +#define DCCP_OPTVAL_MAXLEN	6
> +
> +extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
> +extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -29,16 +29,20 @@ int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
>  int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
>  int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
>  
> -static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
> +u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>  {
> -	u32 value = 0;
> +	u64 value = 0;
>  
> +	if (len >= DCCP_OPTVAL_MAXLEN)
> +		value += ((u64)*bf++) << 40;
> +	if (len > 4)
> +		value += ((u64)*bf++) << 32;
>  	if (len > 3)
> -		value += *bf++ << 24;
> +		value += ((u64)*bf++) << 24;
>  	if (len > 2)
> -		value += *bf++ << 16;
> +		value += ((u64)*bf++) << 16;
>  	if (len > 1)
> -		value += *bf++ << 8;
> +		value += ((u64)*bf++) << 8;
>  	if (len > 0)
>  		value += *bf;
>  
> @@ -298,9 +302,12 @@ out_invalid_option:
>  
>  EXPORT_SYMBOL_GPL(dccp_parse_options);
>  
> -static void dccp_encode_value_var(const u32 value, unsigned char *to,
> -				  const unsigned int len)
> +void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
>  {
> +	if (len >= DCCP_OPTVAL_MAXLEN)
> +		*to++ = (value & 0xFF0000000000ull) >> 40;
> +	if (len > 4)
> +		*to++ = (value & 0xFF00000000ull) >> 32;
>  	if (len > 3)
>  		*to++ = (value & 0xFF000000) >> 24;
>  	if (len > 2)
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 18/37] dccp: Support for Mandatory options
  2008-08-28 17:44                                       ` Gerrit Renker
@ 2008-08-28 21:50                                         ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:50 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Em Thu, Aug 28, 2008 at 07:44:53PM +0200, Gerrit Renker escreveu:
> Support for Mandatory options is provided by this patch, which will
> be used by subsequent feature-negotiation patches.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> ---
>  net/dccp/feat.h    |    2 ++
>  net/dccp/options.c |   15 +++++++++++++++
>  2 files changed, 17 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -136,4 +136,6 @@ extern int  dccp_feat_init(struct sock *sk);
>  
>  extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
>  extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
> +
> +extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -467,6 +467,21 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
>  	return 0;
>  }
>  
> +/**
> + * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
> + * Note that since we are using skb_push, this function needs to be called
> + * _after_ inserting the option it is supposed to influence (stack order).
> + */
> +int dccp_insert_option_mandatory(struct sk_buff *skb)
> +{
> +	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
> +		return -1;
> +
> +	DCCP_SKB_CB(skb)->dccpd_opt_len++;
> +	*skb_push(skb, 1) = DCCPO_MANDATORY;
> +	return 0;
> +}
> +
>  static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
>  				u8 *val, u8 len)
>  {
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 18/37] dccp: Support for Mandatory options
@ 2008-08-28 21:50                                         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-08-28 21:50 UTC (permalink / raw)
  To: dccp

Em Thu, Aug 28, 2008 at 07:44:53PM +0200, Gerrit Renker escreveu:
> Support for Mandatory options is provided by this patch, which will
> be used by subsequent feature-negotiation patches.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

> ---
>  net/dccp/feat.h    |    2 ++
>  net/dccp/options.c |   15 +++++++++++++++
>  2 files changed, 17 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -136,4 +136,6 @@ extern int  dccp_feat_init(struct sock *sk);
>  
>  extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
>  extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
> +
> +extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -467,6 +467,21 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
>  	return 0;
>  }
>  
> +/**
> + * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
> + * Note that since we are using skb_push, this function needs to be called
> + * _after_ inserting the option it is supposed to influence (stack order).
> + */
> +int dccp_insert_option_mandatory(struct sk_buff *skb)
> +{
> +	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
> +		return -1;
> +
> +	DCCP_SKB_CB(skb)->dccpd_opt_len++;
> +	*skb_push(skb, 1) = DCCPO_MANDATORY;
> +	return 0;
> +}
> +
>  static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
>  				u8 *val, u8 len)
>  {
> -- 
> 1.6.0.rc2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 03/37] dccp: List management for new feature negotiation
  2008-08-28 17:44         ` Gerrit Renker
@ 2008-08-29  5:22             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  5:22 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > +/*
| > + *	List management functions
| > + */
| > +
| > +/**
| > + * dccp_feat_entry_new  -  Central list update routine (called by all others)
| > + * @fn: list to add to
| > + * @feat: feature number
| > + * @is_local: whether the local (1) or remote feature with number @feat is meant
| > + * The function maintains and relies on the following invariants:
| > + *  - each feat_num in the list is known, ie. we know its type and default value
| > + *  - each feat_num/is_local combination is unique (old entries are overwritten)
| > + *  - SP values are always freshly allocated
| > + *  - list is sorted in increasing order of feature number (faster lookup)
| > + */
| > +static struct dccp_feat_entry *
| > +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +	struct list_head *pos_head = fn;
| > +
| > +	list_for_each(pos_head, fn) {
| > +		entry = list_entry(pos_head, struct dccp_feat_entry, node);
| 
| Why not use list_for_each_entry()?
As I recall (and that is now over a year ago), there were reasons for doing
it this way, but at the moment I can not figure out which. It is too
long ago, one of the disadvantages of keeping patches out for so long.


| > +		if (feat < entry->feat_num)
| > +			break;
| > +		if (entry->feat_num == feat && entry->is_local == is_local) {
| > +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
| 
| <first reaction>
| You call dccp_feat_val_destructor on entry->val, that kfrees a field and
| then return it? I havent checked, but would it be safer to set the field
| kfree'ed in dccp_feat_val_destructor to NULL since
| dccp_feat_val_destructor is not a destructor (i.e. its not the last
| function in the life of dccp_feat_val)?
| 
| Humm, and shouldn't this entry be removed from the list?
| </>
Please refer to the comments above the function: 
 | > + *  - each feat_num/is_local combination is unique (old entries are overwritten)
A user is free to call setsocktopt as many times as s/he wants. To avoid
ending up with different values for the same feature in the same list,
there is one a single entry for each {feature, remote|local}
combination. Hence the list is searched first:
	 * if an entry already exists, its entry->val is deallocated
	 * and later filled in new
This is necessary since a user may first allocate {3,2} for a CCID and
then decide to overwrite later with {3}.

If there is no entry yet, a new list entry is kmalloced. Each {feature,	local|remote}
combination is allocated at most once, due to the uniqueness requirement.

| I got confused with a _new routine that ends up not being a constructor
| and _destructor being called on an object, then not setting what it
| frees to NULL and then reusing it somehow
|
It seems that the web server (www.erg.abdn.ac.uk/users/gerrit) is still
down, but this discussion would be much easier with the documentation at
hand. But the purpose of the function should be clear from the comments
above it - it is not a "standard" _new routine, due to the specific
requirements of performing feature negotiation safely.


| > +static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
| > +						     u8 feat_num, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +
| > +	list_for_each_entry(entry, fn_list, node)
| 
| cool, here you use list_for_each_entry :-)
| 
What is "cool" about it?

| > +		if (entry->feat_num == feat_num && entry->is_local == is_local)
| > +			return entry;
| > +		else if (entry->feat_num > feat_num)
| > +			break;
| > +	return NULL;
| > +}
| 
| Humm, wouldn't it be better to make the users of dccp_feat_entry_new
| call dccp_feat_list_lookup and if it returns NULL call
| dccp_feat_entry_new that now would just be what its name implies, i.e. a
| constructor, doing just the kmalloc + member init?
| 
This conflicts with the other requirement
 | > + *  - list is sorted in increasing order of feature number (faster lookup)
I agree, the code may look similar, but in feat_entry_new, the purpose
of the list search is to advance to the position within the sorted list
where to put a new feature. When returning NULL, feat_entry_new would
need to start the same search again.

| > +/**
| > + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
| > + * @fn_list: feature-negotiation list to update
| > + * @feat: one of %dccp_feature_numbers
| > + * @local: whether local (1) or remote (0) @feat_num is meant
| > + * @needs_mandatory: whether to use Mandatory feature negotiation options
| > + * @fval: pointer to NN/SP value to be inserted (will be copied)
| > + */
| > +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
| > +				 u8 mandatory, dccp_feat_val *fval)
| > +{
| > +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
| > +
| > +	if (new == NULL)
| > +		return -ENOMEM;
| > +
| > +	new->feat_num	     = feat;
| > +	new->is_local	     = local;
| > +	new->state	     = FEAT_INITIALISING;
| > +	new->needs_confirm   = 0;
| > +	new->empty_confirm   = 0;
| > +	new->val	     = *fval;
| > +	new->needs_mandatory = mandatory;
| > +
| > +	return 0;
| > +}
| > +
| > +/**
| > + * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
| > + * @fn_list: feature-negotiation list to add to
| > + * @feat: one of %dccp_feature_numbers
| > + * @local: whether local (1) or remote (0) @feat_num is being confirmed
| > + * @fval: pointer to NN/SP value to be inserted or NULL
| > + * Returns 0 on success, a Reset code for further processing otherwise.
| > + */
| > +static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
| > +				  dccp_feat_val *fval)
| > +{
| > +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
| > +
| > +	if (new == NULL)
| > +		return DCCP_RESET_CODE_TOO_BUSY;
| > +
| > +	new->feat_num	     = feat;
| > +	new->is_local	     = local;
| > +	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
| > +	new->needs_confirm   = 1;
| > +	new->empty_confirm   = (fval == NULL);
| > +	new->val.nn	     = 0;		/* zeroes the whole structure */
| > +	if (!new->empty_confirm)
| > +		new->val     = *fval;
| > +	new->needs_mandatory = 0;
| > +
| > +	return 0;
| > +}
| > +
| > +static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
| > +{
| > +	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
| > +}
| > +
| > +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
| > +{
| > +	list_del(&entry->node);
| > +	dccp_feat_entry_destructor(entry);
| > +}
| 
| So dccp_feat_entry will always be embedded on other structs? i.e.
| dccp_feat_entry_destructor doesn't frees its space, only fields that
| points to memory allocated elsewhere
| 
Please note that there is a "val destructor" and an "entry destructor",
whose definition is (from the other patch) below:       

static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
{
        if (entry != NULL) {
                dccp_feat_val_destructor(entry->feat_num, &entry->val);
                kfree(entry);
        }
}

So this takes care of freeing the value first and then de-allocating the
list entry.

| > +void dccp_feat_list_purge(struct list_head *fn_list)
| > +{
| > +	struct dccp_feat_entry *entry, *next;
| > +
| > +	list_for_each_entry_safe(entry, next, fn_list, node)
| > +		dccp_feat_entry_destructor(entry);
| > +	INIT_LIST_HEAD(fn_list);
| > +}
| 
| Ditto, who frees the struct dccp_feat_entry instances?
| 
Please see above.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-29  5:22             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  5:22 UTC (permalink / raw)
  To: dccp

| > +/*
| > + *	List management functions
| > + */
| > +
| > +/**
| > + * dccp_feat_entry_new  -  Central list update routine (called by all others)
| > + * @fn: list to add to
| > + * @feat: feature number
| > + * @is_local: whether the local (1) or remote feature with number @feat is meant
| > + * The function maintains and relies on the following invariants:
| > + *  - each feat_num in the list is known, ie. we know its type and default value
| > + *  - each feat_num/is_local combination is unique (old entries are overwritten)
| > + *  - SP values are always freshly allocated
| > + *  - list is sorted in increasing order of feature number (faster lookup)
| > + */
| > +static struct dccp_feat_entry *
| > +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +	struct list_head *pos_head = fn;
| > +
| > +	list_for_each(pos_head, fn) {
| > +		entry = list_entry(pos_head, struct dccp_feat_entry, node);
| 
| Why not use list_for_each_entry()?
As I recall (and that is now over a year ago), there were reasons for doing
it this way, but at the moment I can not figure out which. It is too
long ago, one of the disadvantages of keeping patches out for so long.


| > +		if (feat < entry->feat_num)
| > +			break;
| > +		if (entry->feat_num = feat && entry->is_local = is_local) {
| > +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
| 
| <first reaction>
| You call dccp_feat_val_destructor on entry->val, that kfrees a field and
| then return it? I havent checked, but would it be safer to set the field
| kfree'ed in dccp_feat_val_destructor to NULL since
| dccp_feat_val_destructor is not a destructor (i.e. its not the last
| function in the life of dccp_feat_val)?
| 
| Humm, and shouldn't this entry be removed from the list?
| </>
Please refer to the comments above the function: 
 | > + *  - each feat_num/is_local combination is unique (old entries are overwritten)
A user is free to call setsocktopt as many times as s/he wants. To avoid
ending up with different values for the same feature in the same list,
there is one a single entry for each {feature, remote|local}
combination. Hence the list is searched first:
	 * if an entry already exists, its entry->val is deallocated
	 * and later filled in new
This is necessary since a user may first allocate {3,2} for a CCID and
then decide to overwrite later with {3}.

If there is no entry yet, a new list entry is kmalloced. Each {feature,	local|remote}
combination is allocated at most once, due to the uniqueness requirement.

| I got confused with a _new routine that ends up not being a constructor
| and _destructor being called on an object, then not setting what it
| frees to NULL and then reusing it somehow
|
It seems that the web server (www.erg.abdn.ac.uk/users/gerrit) is still
down, but this discussion would be much easier with the documentation at
hand. But the purpose of the function should be clear from the comments
above it - it is not a "standard" _new routine, due to the specific
requirements of performing feature negotiation safely.


| > +static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
| > +						     u8 feat_num, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +
| > +	list_for_each_entry(entry, fn_list, node)
| 
| cool, here you use list_for_each_entry :-)
| 
What is "cool" about it?

| > +		if (entry->feat_num = feat_num && entry->is_local = is_local)
| > +			return entry;
| > +		else if (entry->feat_num > feat_num)
| > +			break;
| > +	return NULL;
| > +}
| 
| Humm, wouldn't it be better to make the users of dccp_feat_entry_new
| call dccp_feat_list_lookup and if it returns NULL call
| dccp_feat_entry_new that now would just be what its name implies, i.e. a
| constructor, doing just the kmalloc + member init?
| 
This conflicts with the other requirement
 | > + *  - list is sorted in increasing order of feature number (faster lookup)
I agree, the code may look similar, but in feat_entry_new, the purpose
of the list search is to advance to the position within the sorted list
where to put a new feature. When returning NULL, feat_entry_new would
need to start the same search again.

| > +/**
| > + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
| > + * @fn_list: feature-negotiation list to update
| > + * @feat: one of %dccp_feature_numbers
| > + * @local: whether local (1) or remote (0) @feat_num is meant
| > + * @needs_mandatory: whether to use Mandatory feature negotiation options
| > + * @fval: pointer to NN/SP value to be inserted (will be copied)
| > + */
| > +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
| > +				 u8 mandatory, dccp_feat_val *fval)
| > +{
| > +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
| > +
| > +	if (new = NULL)
| > +		return -ENOMEM;
| > +
| > +	new->feat_num	     = feat;
| > +	new->is_local	     = local;
| > +	new->state	     = FEAT_INITIALISING;
| > +	new->needs_confirm   = 0;
| > +	new->empty_confirm   = 0;
| > +	new->val	     = *fval;
| > +	new->needs_mandatory = mandatory;
| > +
| > +	return 0;
| > +}
| > +
| > +/**
| > + * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
| > + * @fn_list: feature-negotiation list to add to
| > + * @feat: one of %dccp_feature_numbers
| > + * @local: whether local (1) or remote (0) @feat_num is being confirmed
| > + * @fval: pointer to NN/SP value to be inserted or NULL
| > + * Returns 0 on success, a Reset code for further processing otherwise.
| > + */
| > +static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
| > +				  dccp_feat_val *fval)
| > +{
| > +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
| > +
| > +	if (new = NULL)
| > +		return DCCP_RESET_CODE_TOO_BUSY;
| > +
| > +	new->feat_num	     = feat;
| > +	new->is_local	     = local;
| > +	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
| > +	new->needs_confirm   = 1;
| > +	new->empty_confirm   = (fval = NULL);
| > +	new->val.nn	     = 0;		/* zeroes the whole structure */
| > +	if (!new->empty_confirm)
| > +		new->val     = *fval;
| > +	new->needs_mandatory = 0;
| > +
| > +	return 0;
| > +}
| > +
| > +static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
| > +{
| > +	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
| > +}
| > +
| > +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
| > +{
| > +	list_del(&entry->node);
| > +	dccp_feat_entry_destructor(entry);
| > +}
| 
| So dccp_feat_entry will always be embedded on other structs? i.e.
| dccp_feat_entry_destructor doesn't frees its space, only fields that
| points to memory allocated elsewhere
| 
Please note that there is a "val destructor" and an "entry destructor",
whose definition is (from the other patch) below:       

static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
{
        if (entry != NULL) {
                dccp_feat_val_destructor(entry->feat_num, &entry->val);
                kfree(entry);
        }
}

So this takes care of freeing the value first and then de-allocating the
list entry.

| > +void dccp_feat_list_purge(struct list_head *fn_list)
| > +{
| > +	struct dccp_feat_entry *entry, *next;
| > +
| > +	list_for_each_entry_safe(entry, next, fn_list, node)
| > +		dccp_feat_entry_destructor(entry);
| > +	INIT_LIST_HEAD(fn_list);
| > +}
| 
| Ditto, who frees the struct dccp_feat_entry instances?
| 
Please see above.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 04/37] dccp: Per-socket initialisation of feature negotiation
  2008-08-28 17:44           ` Gerrit Renker
@ 2008-08-29  5:41               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  5:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > --- a/include/linux/dccp.h
| > +++ b/include/linux/dccp.h
| > @@ -421,6 +422,7 @@ struct dccp_request_sock {
| >  	__u64			 dreq_iss;
| >  	__u64			 dreq_isr;
| >  	__be32			 dreq_service;
| > +	struct list_head	 dreq_featneg;
| 
| Wouldn't be better to use hlist here? So that we use 8 bytes less per
| struct dccp_request_sock, after all we don't use struct sock while in
| embryonic stage exactly to reduce the footprint at this point in the
| socket lifetime :-)
| 
That may be a possible consideration for future time, but I have doubts
from the feature-negotiation side: true, the feature-negotiation list is
sorted in ascending order, but it is frequently necessary to delete an
entry in the middle or at the end of the list (when a pending Confirm has
arrived), and there may be other parts that need changing.
On the whole, I have tried to use as little space as possible, which
accounts for some of the perhaps non-obvious design decisions.

| > +/* generate @to as full clone of @from - @to must not contain any nodes */
| > +int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
| > +{
| > +	struct dccp_feat_entry *entry, *new;
| > +
| > +	INIT_LIST_HEAD(to);
| > +	list_for_each_entry(entry, from, node) {
| > +		new = dccp_feat_clone_entry(entry);
| 
| dccp_feat_clone_entry uses kmemdup for a new dccp_feat_entry _and_
| possibly for sp.vec, and goes on adding it to the 'to' list, but if
| one fails you go to cloning_failed: and dccp_feat_list_purge will
| call just dccp_feat_entry_destructor that doesn't frees the
| dccp_feat_entry instances, just the sp.vec. 
| 
| Looks like major leakage, or am I missing something?
| 
Hm, I am beginning to doubt that I have chosen the right granularity for
the patches. Apparently this format is confusing and makes discussion
difficult. Here is the definition, taken from the other patch:

static struct dccp_feat_entry *
              dccp_feat_clone_entry(struct dccp_feat_entry const *original)
{
        struct dccp_feat_entry *new;
        u8 type = dccp_feat_type(original->feat_num);

        if (type == FEAT_UNKNOWN)
                return NULL;

        new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
        if (new == NULL)
                return NULL;

        if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
                                                      original->val.sp.vec,
                                                      original->val.sp.len)) {
                kfree(new);
                return NULL;
        }
        return new;
}

Now, dccp_feat_clone_entry returns NULL:
 * when the feature is not known - in this case no new memory is allocated;
 * when kmemdup fails 
 * when, for an SP feature, dccp_feat_clone_sp_val fails
So we need to continue with its definition, below:

static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
{
        fval->sp.len = len;
        if (fval->sp.len > 0) {
                fval->sp.vec = kmemdup(val, len, gfp_any());
                if (fval->sp.vec == NULL) {
                        fval->sp.len = 0;
                        return -ENOBUFS;
                }
        }
        return 0;
}

The function returns a non-0 value if kmemdup fails. 

To summarize, I think I have chosen the wrong granularity for the
patches. Sorry, I actually intended to make it easier to spot mistakes.
I thank you for checking through.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 04/37] dccp: Per-socket initialisation of feature
@ 2008-08-29  5:41               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  5:41 UTC (permalink / raw)
  To: dccp

| > --- a/include/linux/dccp.h
| > +++ b/include/linux/dccp.h
| > @@ -421,6 +422,7 @@ struct dccp_request_sock {
| >  	__u64			 dreq_iss;
| >  	__u64			 dreq_isr;
| >  	__be32			 dreq_service;
| > +	struct list_head	 dreq_featneg;
| 
| Wouldn't be better to use hlist here? So that we use 8 bytes less per
| struct dccp_request_sock, after all we don't use struct sock while in
| embryonic stage exactly to reduce the footprint at this point in the
| socket lifetime :-)
| 
That may be a possible consideration for future time, but I have doubts
from the feature-negotiation side: true, the feature-negotiation list is
sorted in ascending order, but it is frequently necessary to delete an
entry in the middle or at the end of the list (when a pending Confirm has
arrived), and there may be other parts that need changing.
On the whole, I have tried to use as little space as possible, which
accounts for some of the perhaps non-obvious design decisions.

| > +/* generate @to as full clone of @from - @to must not contain any nodes */
| > +int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
| > +{
| > +	struct dccp_feat_entry *entry, *new;
| > +
| > +	INIT_LIST_HEAD(to);
| > +	list_for_each_entry(entry, from, node) {
| > +		new = dccp_feat_clone_entry(entry);
| 
| dccp_feat_clone_entry uses kmemdup for a new dccp_feat_entry _and_
| possibly for sp.vec, and goes on adding it to the 'to' list, but if
| one fails you go to cloning_failed: and dccp_feat_list_purge will
| call just dccp_feat_entry_destructor that doesn't frees the
| dccp_feat_entry instances, just the sp.vec. 
| 
| Looks like major leakage, or am I missing something?
| 
Hm, I am beginning to doubt that I have chosen the right granularity for
the patches. Apparently this format is confusing and makes discussion
difficult. Here is the definition, taken from the other patch:

static struct dccp_feat_entry *
              dccp_feat_clone_entry(struct dccp_feat_entry const *original)
{
        struct dccp_feat_entry *new;
        u8 type = dccp_feat_type(original->feat_num);

        if (type = FEAT_UNKNOWN)
                return NULL;

        new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
        if (new = NULL)
                return NULL;

        if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
                                                      original->val.sp.vec,
                                                      original->val.sp.len)) {
                kfree(new);
                return NULL;
        }
        return new;
}

Now, dccp_feat_clone_entry returns NULL:
 * when the feature is not known - in this case no new memory is allocated;
 * when kmemdup fails 
 * when, for an SP feature, dccp_feat_clone_sp_val fails
So we need to continue with its definition, below:

static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
{
        fval->sp.len = len;
        if (fval->sp.len > 0) {
                fval->sp.vec = kmemdup(val, len, gfp_any());
                if (fval->sp.vec = NULL) {
                        fval->sp.len = 0;
                        return -ENOBUFS;
                }
        }
        return 0;
}

The function returns a non-0 value if kmemdup fails. 

To summarize, I think I have chosen the wrong granularity for the
patches. Sorry, I actually intended to make it easier to spot mistakes.
I thank you for checking through.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase
  2008-08-28 17:44               ` Gerrit Renker
@ 2008-08-29  5:54                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  5:54 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > This patch starts the new implementation of feature negotiation:
| >  1. Although it is theoretically possible to perform feature negotiation at any
| >     time (and RFC 4340 supports this), in practice this is prohibitively complex,
| >     as it requires to put traffic on hold for each new negotiation.
| >  2. As a byproduct of restricting feature negotiation to connection setup, the
| >     feature-negotiation retransmit timer is no longer required. This part is now
| >     mapped onto the protocol-level retransmission.
| >     Details indicating why timers are no longer needed can be found on
| >     http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
| > 	                                      implementation_notes.html
| > 
| > This patch disables anytime negotiation, subsequent patches work out full
| > feature negotiation support for connection setup.
| 
| While I agree that its better to initially support only negotiation at
| connection startup, I wonder if the response to feature negotiation
| after connection startup should be plainly ignore the request or if we
| should reset the connection, telling the other side that what it wants
| to do is not implemented currently.
| 
The implementation will ignore any peer-attempt at feature negotiation
as soon as the connection has reached established (OPEN/PARTOPEN) state.

This is done in dccp_feat_parse_options() which is shown for reference below.

Considering doing a reset is something we could consider when it comes
to Interoperability tests; it may be that the current policy of ignoring
is sufficient.

There are two main points that I think are important here:
 1. At the begin of the connection, both endpoints really negotiate their
    capabilities, i.e. A says to B "I want to do X, but could do Y" and
    B says to A "can't do X, so will settle for Y".
    Doing the same in the middle of an established connection seems mad
    to me - for example changing the CCID in mid-connection.
 2. There is an actual need for exchanging feature negotiation options
    even when the connection is established. But this is past the
    checking-capabilities phase and the only known uses require NN
    (non-negotiable) options. In this case, if the peer does not
    understand, the reset will happen as a consequence of receiving an
    empty Confirm. However, in a well-behaved connection this will not
    occur, since both peers have negotiated their capabilities in (1).

The second point is actually not part of this patch set, it is in the
second set which I wanted to send after this one. 

Here is the parse routine as it is currently in the test git tree:

int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                            u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
{
        struct dccp_sock *dp = dccp_sk(sk);
        struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
        bool server = false;

        switch (sk->sk_state) {
        /*
         *      Negotiation during connection setup
         */
        case DCCP_LISTEN:
                server = true;                  /* fall through */
        case DCCP_REQUESTING:
                switch (opt) {
                case DCCPO_CHANGE_L:
                case DCCPO_CHANGE_R:
                        return dccp_feat_change_recv(fn, mandatory, opt, feat,
                                                     val, len, server);
                case DCCPO_CONFIRM_R:
                case DCCPO_CONFIRM_L:
                        return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
                                                      val, len, server);
                }
                break;
        /*
         *      Support for exchanging NN options on an established connection
         *      This is currently restricted to Ack Ratio (RFC 4341, 6.1.2)
         */
        case DCCP_OPEN:
        case DCCP_PARTOPEN:
                return dccp_feat_handle_nn_established(sk, mandatory, opt, feat,
                                                       val, len);
        }
        return 0;       /* ignore FN options in all other states */
}

===> The first two cases are for the initial phase and allow
     full/unrestricted negotiation.
     The dccp_feat_handle_nn_established() is part of the second patch
     set and basically allows dynamic updates of NN (Sequence Window and 
     Ack Ratio).
     In all other cases, 0 is returned to dccp_parse_options(), which means
     that the option is merely eaten up, but not reacted on.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 06/37] dccp: Limit feature negotiation to connection
@ 2008-08-29  5:54                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  5:54 UTC (permalink / raw)
  To: dccp

| > This patch starts the new implementation of feature negotiation:
| >  1. Although it is theoretically possible to perform feature negotiation at any
| >     time (and RFC 4340 supports this), in practice this is prohibitively complex,
| >     as it requires to put traffic on hold for each new negotiation.
| >  2. As a byproduct of restricting feature negotiation to connection setup, the
| >     feature-negotiation retransmit timer is no longer required. This part is now
| >     mapped onto the protocol-level retransmission.
| >     Details indicating why timers are no longer needed can be found on
| >     http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
| > 	                                      implementation_notes.html
| > 
| > This patch disables anytime negotiation, subsequent patches work out full
| > feature negotiation support for connection setup.
| 
| While I agree that its better to initially support only negotiation at
| connection startup, I wonder if the response to feature negotiation
| after connection startup should be plainly ignore the request or if we
| should reset the connection, telling the other side that what it wants
| to do is not implemented currently.
| 
The implementation will ignore any peer-attempt at feature negotiation
as soon as the connection has reached established (OPEN/PARTOPEN) state.

This is done in dccp_feat_parse_options() which is shown for reference below.

Considering doing a reset is something we could consider when it comes
to Interoperability tests; it may be that the current policy of ignoring
is sufficient.

There are two main points that I think are important here:
 1. At the begin of the connection, both endpoints really negotiate their
    capabilities, i.e. A says to B "I want to do X, but could do Y" and
    B says to A "can't do X, so will settle for Y".
    Doing the same in the middle of an established connection seems mad
    to me - for example changing the CCID in mid-connection.
 2. There is an actual need for exchanging feature negotiation options
    even when the connection is established. But this is past the
    checking-capabilities phase and the only known uses require NN
    (non-negotiable) options. In this case, if the peer does not
    understand, the reset will happen as a consequence of receiving an
    empty Confirm. However, in a well-behaved connection this will not
    occur, since both peers have negotiated their capabilities in (1).

The second point is actually not part of this patch set, it is in the
second set which I wanted to send after this one. 

Here is the parse routine as it is currently in the test git tree:

int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                            u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
{
        struct dccp_sock *dp = dccp_sk(sk);
        struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
        bool server = false;

        switch (sk->sk_state) {
        /*
         *      Negotiation during connection setup
         */
        case DCCP_LISTEN:
                server = true;                  /* fall through */
        case DCCP_REQUESTING:
                switch (opt) {
                case DCCPO_CHANGE_L:
                case DCCPO_CHANGE_R:
                        return dccp_feat_change_recv(fn, mandatory, opt, feat,
                                                     val, len, server);
                case DCCPO_CONFIRM_R:
                case DCCPO_CONFIRM_L:
                        return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
                                                      val, len, server);
                }
                break;
        /*
         *      Support for exchanging NN options on an established connection
         *      This is currently restricted to Ack Ratio (RFC 4341, 6.1.2)
         */
        case DCCP_OPEN:
        case DCCP_PARTOPEN:
                return dccp_feat_handle_nn_established(sk, mandatory, opt, feat,
                                                       val, len);
        }
        return 0;       /* ignore FN options in all other states */
}

==> The first two cases are for the initial phase and allow
     full/unrestricted negotiation.
     The dccp_feat_handle_nn_established() is part of the second patch
     set and basically allows dynamic updates of NN (Sequence Window and 
     Ack Ratio).
     In all other cases, 0 is returned to dccp_parse_options(), which means
     that the option is merely eaten up, but not reacted on.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature values
  2008-08-28 17:44                 ` Gerrit Renker
@ 2008-08-29  6:12                     ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:12 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > +/* check that SP values are within the ranges defined in RFC 4340 */
| > +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
| > +{
| > +	switch (feat_num) {
| > +	case DCCPF_CCID:
| > +		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
| 
| Shouldn't we look at the registered CCIDs and do validation based on the
| modules loaded? Doing it this hardcoded way will prevent testing CCID4,
| for instance, or require that the kernel be patched, which can not be
| possible with enterprise distros, etc. And defeats the purpose of having
| multiple pluggable congestion control algorithms :-)
| 
The point is valid and actually such a check is done, see further below.

In the CCID-4 subtree, the above statement changes to
 | > +		val >= DCCPC_CCID2 && val <= DCCPC_CCID4;
The above function only serves as sanity-check for SP values, so that no
unknown values appear. There is a registry for CCID identifiers, only
ones that are in RFC documents are "valid". With regard to RFC 4340,
19.5 we could consider adding the experimental identifiers here
(248-254 are valid, we could use one for the "UDP-like" CCID).	

With regard to doing validation based on the modules loaded, the
mechanism works as follows:
 1. at socket initialisation time dccp_init_sock calls dccp_feat_init
 2. dccp_feat_init queries the compiled-in CCIDs:
        /*
         * We advertise the available list of CCIDs and reorder according to
         * preferences, to avoid failure resulting from negotiating different
         * singleton values (which always leads to failure).
         * These settings can still (later) be overridden via sockopts.
         */
        if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
            ccid_get_builtin_ccids(&rx.val, &rx.len))
                return -ENOBUFS;
    ==> If it succeeds, the `tx' and `rx' entries will be identical copies.

 3. The next step in dccp_feat_init is to try and load all configured  CCIDs:

        if (ccid_request_modules(tx.val, tx.len))
                goto free_ccid_lists;

    ==> If this succeeds, the host is ready to answer to any request by
	the peer.

 4. Finally, if the peer tries to negotiate an unknown CCID, negotiation
    will fail as per the server-priority negotiation rules (6.3.1), unless
    the peer has an entry in its CCID list which agrees with an entry of
    our list.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature
@ 2008-08-29  6:12                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:12 UTC (permalink / raw)
  To: dccp

| > +/* check that SP values are within the ranges defined in RFC 4340 */
| > +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
| > +{
| > +	switch (feat_num) {
| > +	case DCCPF_CCID:
| > +		return val = DCCPC_CCID2 || val = DCCPC_CCID3;
| 
| Shouldn't we look at the registered CCIDs and do validation based on the
| modules loaded? Doing it this hardcoded way will prevent testing CCID4,
| for instance, or require that the kernel be patched, which can not be
| possible with enterprise distros, etc. And defeats the purpose of having
| multiple pluggable congestion control algorithms :-)
| 
The point is valid and actually such a check is done, see further below.

In the CCID-4 subtree, the above statement changes to
 | > +		val >= DCCPC_CCID2 && val <= DCCPC_CCID4;
The above function only serves as sanity-check for SP values, so that no
unknown values appear. There is a registry for CCID identifiers, only
ones that are in RFC documents are "valid". With regard to RFC 4340,
19.5 we could consider adding the experimental identifiers here
(248-254 are valid, we could use one for the "UDP-like" CCID).	

With regard to doing validation based on the modules loaded, the
mechanism works as follows:
 1. at socket initialisation time dccp_init_sock calls dccp_feat_init
 2. dccp_feat_init queries the compiled-in CCIDs:
        /*
         * We advertise the available list of CCIDs and reorder according to
         * preferences, to avoid failure resulting from negotiating different
         * singleton values (which always leads to failure).
         * These settings can still (later) be overridden via sockopts.
         */
        if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
            ccid_get_builtin_ccids(&rx.val, &rx.len))
                return -ENOBUFS;
    => If it succeeds, the `tx' and `rx' entries will be identical copies.

 3. The next step in dccp_feat_init is to try and load all configured  CCIDs:

        if (ccid_request_modules(tx.val, tx.len))
                goto free_ccid_lists;

    => If this succeeds, the host is ready to answer to any request by
	the peer.

 4. Finally, if the peer tries to negotiate an unknown CCID, negotiation
    will fail as per the server-priority negotiation rules (6.3.1), unless
    the peer has an entry in its CCID list which agrees with an entry of
    our list.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 08/37] dccp: Query supported CCIDs
  2008-08-28 17:44                   ` Gerrit Renker
@ 2008-08-29  6:17                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:17 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

Quoting Arnaldo:
| Em Thu, Aug 28, 2008 at 07:44:43PM +0200, Gerrit Renker escreveu:
| > This provides a data structure to record which CCIDs are locally supported
| > and three accessor functions:
| >  - a test function for internal use which is used to validate CCID requests
| >    made by the user;
| >  - a copy function so that the list can be used for feature-negotiation;
| >  - documented getsockopt() support so that the user can query capabilities.
| > 
| > The data structure is a table which is filled in at compile-time with the
| > list of available CCIDs (which in turn depends on the Kconfig choices).
| > 
| > Using the copy function for cloning the list of supported CCIDs is useful for
| > feature negotiation, since the negotiation is now with the full list of available
| > CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
| > will not fail if the peer requests to use CCID3 instead of CCID2.
| 
| But this limits us to the CCIDs at kernel build time, what if I want to
| test CCID4? I guess we could have something like a bitmap and check if
| the bit for that CCID is set, and it would be set at ccid_register time.
| 
| Perhaps using include/linux/bitmap.h :-)
| 
Or have a look at how it has been done in the CCID-4 subtree for about a year?
Please take a look at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=d88f6d5505f83f4c19a3417fbf3ee8874c87d227

And also (shows age of the patches):
http://www.mail-archive.com/dccp@vger.kernel.org/msg02613.html	


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 08/37] dccp: Query supported CCIDs
@ 2008-08-29  6:17                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:17 UTC (permalink / raw)
  To: dccp

Quoting Arnaldo:
| Em Thu, Aug 28, 2008 at 07:44:43PM +0200, Gerrit Renker escreveu:
| > This provides a data structure to record which CCIDs are locally supported
| > and three accessor functions:
| >  - a test function for internal use which is used to validate CCID requests
| >    made by the user;
| >  - a copy function so that the list can be used for feature-negotiation;
| >  - documented getsockopt() support so that the user can query capabilities.
| > 
| > The data structure is a table which is filled in at compile-time with the
| > list of available CCIDs (which in turn depends on the Kconfig choices).
| > 
| > Using the copy function for cloning the list of supported CCIDs is useful for
| > feature negotiation, since the negotiation is now with the full list of available
| > CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
| > will not fail if the peer requests to use CCID3 instead of CCID2.
| 
| But this limits us to the CCIDs at kernel build time, what if I want to
| test CCID4? I guess we could have something like a bitmap and check if
| the bit for that CCID is set, and it would be set at ccid_register time.
| 
| Perhaps using include/linux/bitmap.h :-)
| 
Or have a look at how it has been done in the CCID-4 subtree for about a year?
Please take a look at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;hÿ8f6d5505f83f4c19a3417fbf3ee8874c87d227

And also (shows age of the patches):
http://www.mail-archive.com/dccp@vger.kernel.org/msg02613.html	

--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID
  2008-08-28 17:44                     ` Gerrit Renker
@ 2008-08-29  6:34                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:34 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

Quoting Arnaldo:
| Em Thu, Aug 28, 2008 at 07:44:44PM +0200, Gerrit Renker escreveu:
| > This provides a missing link in the code chain, as several features implicitly
| > depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
| > feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
| > 
| > For Send Ack Vector, the situation is as follows:
| >  * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
| >    endpoints which use CCID2 to disable Ack Vector features such a connection;
| > 
| >  * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
| >    with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);
| > 
| >  * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
| >    negotiable. However, this implies that the code negotiating the use of Ack
| >    Vectors also supports it (i.e. is able to supply and to either parse or
| >    ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
| >    Vector support), the use of Ack Vectors is here disabled, with a comment
| >    in the source code.
| > 
| > An analogous consideration arises for the Send Loss Event Rate feature,
| > since the CCID-3 implementation does not support the loss interval options
| > of RFC 4342. To make such use explicit, corresponding feature-negotiation
| > options are inserted which signal the use of the loss event rate option,
| > as it is used by the CCID3 code.
| > 
| > Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.
| > 
| > The patch implements this as a function which is called after the user has
| > made all other registrations for changing default values of features.
| > 
| > The table is variable-length, the reserved (and hence for feature-negotiation
| > invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
| > is used to mark the end of the table.
| 
| Doesn't this belongs into struct ccid_operations? Why has the core feature
| negotiation have knowledge of any specific CCID? When people want to
| merge CCID 4, 5, etc will we need to change net/dccp/feat.c?
| 
| I think that this needs thus to go to struct ccid_operations, and then the feature
| negotiation code can just use use the ccid number to access:
| 
| struct ccid_operations *ccids[CCID_MAX]
| 
| ccids[ccid_number]->deps
|  
Your point is valid and one could do it this way. At the moment I can
not see an advantage. From experience, there is actually an advantage of
keeping all the dependencies in one file (feat.c): since CCID-4 use
mostly the same (TFRC) concepts as CCID-3, it can reuse the existing
ccid3_dependencies[] table, rather than copy-and-pasting it (this can
be seen in the commitdiff link for CCID-4 in the other posting).

For the moment, I would suggest keeping it in place. It is an easy patch
to do it later. The reason I am holding back here is that there is a
much larger potential for integration - as in the initial patches by
Tommi and Leandro, the mostly-identical TFRC functionality of CCID-3
and CCID-4 can be combined. Progress here has been impeded by waiting
for rfc3448bis-06 to reach RFC status, which it very soon:
ftp://ftp.rfc-editor.org/in-notes/authors/rfc5348.txt

But all this does not mean I disagree. There is a related spot which
I think should be CCID-specific: the "print" subroutine in
net/dccp/probe.c - at the moment, the CCIDs are hardcoded. Here it would
indeed be good to have a struct ccid_operations function pointer instead
of hardcoding the current CCID.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice
@ 2008-08-29  6:34                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:34 UTC (permalink / raw)
  To: dccp

Quoting Arnaldo:
| Em Thu, Aug 28, 2008 at 07:44:44PM +0200, Gerrit Renker escreveu:
| > This provides a missing link in the code chain, as several features implicitly
| > depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
| > feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
| > 
| > For Send Ack Vector, the situation is as follows:
| >  * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
| >    endpoints which use CCID2 to disable Ack Vector features such a connection;
| > 
| >  * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
| >    with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);
| > 
| >  * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
| >    negotiable. However, this implies that the code negotiating the use of Ack
| >    Vectors also supports it (i.e. is able to supply and to either parse or
| >    ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
| >    Vector support), the use of Ack Vectors is here disabled, with a comment
| >    in the source code.
| > 
| > An analogous consideration arises for the Send Loss Event Rate feature,
| > since the CCID-3 implementation does not support the loss interval options
| > of RFC 4342. To make such use explicit, corresponding feature-negotiation
| > options are inserted which signal the use of the loss event rate option,
| > as it is used by the CCID3 code.
| > 
| > Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.
| > 
| > The patch implements this as a function which is called after the user has
| > made all other registrations for changing default values of features.
| > 
| > The table is variable-length, the reserved (and hence for feature-negotiation
| > invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
| > is used to mark the end of the table.
| 
| Doesn't this belongs into struct ccid_operations? Why has the core feature
| negotiation have knowledge of any specific CCID? When people want to
| merge CCID 4, 5, etc will we need to change net/dccp/feat.c?
| 
| I think that this needs thus to go to struct ccid_operations, and then the feature
| negotiation code can just use use the ccid number to access:
| 
| struct ccid_operations *ccids[CCID_MAX]
| 
| ccids[ccid_number]->deps
|  
Your point is valid and one could do it this way. At the moment I can
not see an advantage. From experience, there is actually an advantage of
keeping all the dependencies in one file (feat.c): since CCID-4 use
mostly the same (TFRC) concepts as CCID-3, it can reuse the existing
ccid3_dependencies[] table, rather than copy-and-pasting it (this can
be seen in the commitdiff link for CCID-4 in the other posting).

For the moment, I would suggest keeping it in place. It is an easy patch
to do it later. The reason I am holding back here is that there is a
much larger potential for integration - as in the initial patches by
Tommi and Leandro, the mostly-identical TFRC functionality of CCID-3
and CCID-4 can be combined. Progress here has been impeded by waiting
for rfc3448bis-06 to reach RFC status, which it very soon:
ftp://ftp.rfc-editor.org/in-notes/authors/rfc5348.txt

But all this does not mean I disagree. There is a related spot which
I think should be CCID-specific: the "print" subroutine in
net/dccp/probe.c - at the moment, the CCIDs are hardcoded. Here it would
indeed be good to have a struct ccid_operations function pointer instead
of hardcoding the current CCID.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage
  2008-08-28 17:44                           ` Gerrit Renker
@ 2008-08-29  6:47                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:47 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

This addresses Arnaldo's comment - change the socket state only after
 * memory has been successfully allocated and
 * the setsockopt value has been successfully registered.

The inter-diff is:

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -477,11 +477,6 @@ static int dccp_setsockopt_cscov(struct 
 
 	if (cscov < 0 || cscov > 15)
 		return -EINVAL;
-
-	if (rx)
-		dccp_sk(sk)->dccps_pcrlen = cscov;
-	else
-		dccp_sk(sk)->dccps_pcslen = cscov;
 	/*
 	 * Populate a list of permissible values, in the range cscov...15. This
 	 * is necessary since feature negotiation of single values only works if
@@ -501,6 +496,12 @@ static int dccp_setsockopt_cscov(struct 
 
 	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
 
+	if (rc == 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
 	kfree(list);
 	return rc;
 }

>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Feature negotiation for minimum-checksum-coverage

This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +--
 net/dccp/proto.c     |   53 ++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 42 insertions(+), 15 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,6 +470,42 @@ static int dccp_setsockopt_service(struc
 	return 0;
 }
 
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
+{
+	u8 *list, len;
+	int i, rc;
+
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
+	/*
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
+	 */
+	if (cscov == 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list == NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	if (rc == 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
+	kfree(list);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -502,20 +538,11 @@ static int do_dccp_setsockopt(struct soc
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 12/37] dccp: Feature negotiation for
@ 2008-08-29  6:47                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:47 UTC (permalink / raw)
  To: dccp

This addresses Arnaldo's comment - change the socket state only after
 * memory has been successfully allocated and
 * the setsockopt value has been successfully registered.

The inter-diff is:

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -477,11 +477,6 @@ static int dccp_setsockopt_cscov(struct 
 
 	if (cscov < 0 || cscov > 15)
 		return -EINVAL;
-
-	if (rx)
-		dccp_sk(sk)->dccps_pcrlen = cscov;
-	else
-		dccp_sk(sk)->dccps_pcslen = cscov;
 	/*
 	 * Populate a list of permissible values, in the range cscov...15. This
 	 * is necessary since feature negotiation of single values only works if
@@ -501,6 +496,12 @@ static int dccp_setsockopt_cscov(struct 
 
 	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
 
+	if (rc = 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
 	kfree(list);
 	return rc;
 }

>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Feature negotiation for minimum-checksum-coverage

This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +--
 net/dccp/proto.c     |   53 ++++++++++++++++++++++++++++++++++++++-------------
 2 files changed, 42 insertions(+), 15 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,6 +470,42 @@ static int dccp_setsockopt_service(struc
 	return 0;
 }
 
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
+{
+	u8 *list, len;
+	int i, rc;
+
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
+	/*
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
+	 */
+	if (cscov = 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list = NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	if (rc = 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
+	kfree(list);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -502,20 +538,11 @@ static int do_dccp_setsockopt(struct soc
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
  2008-08-28 17:44                               ` Gerrit Renker
@ 2008-08-29  6:57                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:57 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > This splits the setsockopt calls into two groups, depending on whether an
| > integer argument (val) is required and whether routines being called do
| > their own locking.
| > 
| > Some options (such as setting the CCID) use u8 rather than int, so that for
| > these the test with regard to integer-sizeof can not be used.
| > 
| > The second switch-case statement now only has those statements which need
| > locking and which make use of `val'.
| > 
<snip>
| > --- a/net/dccp/proto.c
| > +++ b/net/dccp/proto.c
| > @@ -511,26 +511,27 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
| >  	struct dccp_sock *dp = dccp_sk(sk);
| >  	int val, err = 0;
| >  
| > -	if (optlen < sizeof(int))
| > -		return -EINVAL;
| > -
| > -	if (get_user(val, (int __user *)optval))
| > -		return -EFAULT;
| > -
| > -	if (optname == DCCP_SOCKOPT_SERVICE)
| > -		return dccp_setsockopt_service(sk, val, optval, optlen);
| > -
| > -	lock_sock(sk);
| >  	switch (optname) {
| >  	case DCCP_SOCKOPT_PACKET_SIZE:
| >  		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
| > -		err = 0;
| > -		break;
| > +		return 0;
| >  	case DCCP_SOCKOPT_CHANGE_L:
| >  	case DCCP_SOCKOPT_CHANGE_R:
| >  		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
| > -		err = 0;
| > -		break;
| > +		return 0;
| > +	default:
| > +		if (optlen < sizeof(int))
| > +			return -EINVAL;
| > +
| > +		if (get_user(val, (int __user *)optval))
| > +			return -EFAULT;
| > +
| > +		if (optname == DCCP_SOCKOPT_SERVICE)
| > +			return dccp_setsockopt_service(sk, val, optval, optlen);
| 
| What is in the default could well continue outside the switch
| statatement, since all the other cases return directly.
| 
Would you be ok to return to this question at a later stage? - agreed
that there is potential here to unify things. I have not done much here
for the main reason that most of the API is still open for people to
define, i.e. although this patch set is about a new API, there is
actually only a single new setsockopt functionality -- for
setting/getting the CCID. 

Since the old mechanism (struct dccp_so_feat) has been removed, there
is potential for making up a complete new API, but the patch set does
not do much in this way, so input/discussion would be good.

| > +	}
| > +
| > +	lock_sock(sk);
| > +	switch (optname) {
| >  	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
| >  		if (dp->dccps_role != DCCP_ROLE_SERVER)
| >  			err = -EOPNOTSUPP;
| > @@ -547,8 +548,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
| >  		err = -ENOPROTOOPT;
| >  		break;
| >  	}
| > -
| >  	release_sock(sk);
| > +
| >  	return err;
| >  }

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
@ 2008-08-29  6:57                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  6:57 UTC (permalink / raw)
  To: dccp

| > This splits the setsockopt calls into two groups, depending on whether an
| > integer argument (val) is required and whether routines being called do
| > their own locking.
| > 
| > Some options (such as setting the CCID) use u8 rather than int, so that for
| > these the test with regard to integer-sizeof can not be used.
| > 
| > The second switch-case statement now only has those statements which need
| > locking and which make use of `val'.
| > 
<snip>
| > --- a/net/dccp/proto.c
| > +++ b/net/dccp/proto.c
| > @@ -511,26 +511,27 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
| >  	struct dccp_sock *dp = dccp_sk(sk);
| >  	int val, err = 0;
| >  
| > -	if (optlen < sizeof(int))
| > -		return -EINVAL;
| > -
| > -	if (get_user(val, (int __user *)optval))
| > -		return -EFAULT;
| > -
| > -	if (optname = DCCP_SOCKOPT_SERVICE)
| > -		return dccp_setsockopt_service(sk, val, optval, optlen);
| > -
| > -	lock_sock(sk);
| >  	switch (optname) {
| >  	case DCCP_SOCKOPT_PACKET_SIZE:
| >  		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
| > -		err = 0;
| > -		break;
| > +		return 0;
| >  	case DCCP_SOCKOPT_CHANGE_L:
| >  	case DCCP_SOCKOPT_CHANGE_R:
| >  		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
| > -		err = 0;
| > -		break;
| > +		return 0;
| > +	default:
| > +		if (optlen < sizeof(int))
| > +			return -EINVAL;
| > +
| > +		if (get_user(val, (int __user *)optval))
| > +			return -EFAULT;
| > +
| > +		if (optname = DCCP_SOCKOPT_SERVICE)
| > +			return dccp_setsockopt_service(sk, val, optval, optlen);
| 
| What is in the default could well continue outside the switch
| statatement, since all the other cases return directly.
| 
Would you be ok to return to this question at a later stage? - agreed
that there is potential here to unify things. I have not done much here
for the main reason that most of the API is still open for people to
define, i.e. although this patch set is about a new API, there is
actually only a single new setsockopt functionality -- for
setting/getting the CCID. 

Since the old mechanism (struct dccp_so_feat) has been removed, there
is potential for making up a complete new API, but the patch set does
not do much in this way, so input/discussion would be good.

| > +	}
| > +
| > +	lock_sock(sk);
| > +	switch (optname) {
| >  	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
| >  		if (dp->dccps_role != DCCP_ROLE_SERVER)
| >  			err = -EOPNOTSUPP;
| > @@ -547,8 +548,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
| >  		err = -ENOPROTOOPT;
| >  		break;
| >  	}
| > -
| >  	release_sock(sk);
| > +
| >  	return err;
| >  }

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
  2008-08-28 17:44                                 ` Gerrit Renker
@ 2008-08-29  7:17                                     ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  7:17 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| >  /* maximum number of services provided on the same listening port */
| >  #define DCCP_SERVICE_LIST_MAX_LEN      32
| > +/* maximum number of CCID preferences that can be registered at one time */
| > +#define DCCP_CCID_LIST_MAX_LEN	       16
| 
| Since this is an arbitrary lenght up to 253, it could as well be 253,
| no? Or is there any other limit that I'm forgetting? :-) It may well be
| that case, would have to read the RFC about how the encoding is done for
| feat len, which I did some weeks ago, but...
|   
The worst-case consideration is the Confirm option:
max value =  255
          - 2 bytes for type/length
          - 1 byte for feature number 
          - 1 byte for confirmed value (6.2)
	  = max 251 distinct values.

So make it 251 instead?	- we will need some new RFCs :)


| >  #ifdef __KERNEL__
| >  
| > --- a/net/dccp/proto.c
| > +++ b/net/dccp/proto.c
| > @@ -505,6 +505,34 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
| >  	return rc;
| >  }
| >  
| > +static int dccp_setsockopt_ccid(struct sock *sk, int type,
| > +				char __user *optval, int optlen)
| > +{
| > +	u8 *val;
| > +	int rc = 0;
| > +
| > +	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
| > +		return -EINVAL;
| > +
| > +	val = kmalloc(optlen, GFP_KERNEL);
| > +	if (val == NULL)
| > +		return -ENOMEM;
| > +
| > +	if (copy_from_user(val, optval, optlen))
| > +		rc = -EFAULT;
| > +
| > +	lock_sock(sk);
| > +	if (!rc && (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID))
| > +		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
| > +
| 
| This _really_ is confusing! Why not:
| 
| 	rc = -EFAULT;
| 	if (copy_from_user(val, optval, optlen))
| 		goto out;
| 
| 	lock_sock(sk);
| 	rc = 0;
| 	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
| 		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
| 
| 	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
| 		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
| 	release_sock(sk);
| out:
| > +	kfree(val);
| > +	return rc;
| > +}
| 
| :-)
| 
| And even then that '0' or '1' requires one to look at what this binary
| number means, we could have something like
| dccp_feat_register_sp_{local,remote} perhaps, IIRC that is the is_local
| parameter, no?
| 
Thanks, I will be revising this with regard to the above. 

If you want, we could consider dropping the DCCP_SOCKOPT_{RX,TX}_CCID 
since mixed-mode is at the moment not well understood and will lead
to bad performance (e.g. CCID-3 on the forward path and CCID-2 on the
reverse path). 

That would make both the above statements and the socket API much
simpler. Would that be ok?

With regard to the dccp_feat_register_sp_local() function, the price to
pay is that either lines will be longer than 80 characters or that we
will end up with more multi-line statements, which does IMO not help
readability.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
@ 2008-08-29  7:17                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  7:17 UTC (permalink / raw)
  To: dccp

| >  /* maximum number of services provided on the same listening port */
| >  #define DCCP_SERVICE_LIST_MAX_LEN      32
| > +/* maximum number of CCID preferences that can be registered at one time */
| > +#define DCCP_CCID_LIST_MAX_LEN	       16
| 
| Since this is an arbitrary lenght up to 253, it could as well be 253,
| no? Or is there any other limit that I'm forgetting? :-) It may well be
| that case, would have to read the RFC about how the encoding is done for
| feat len, which I did some weeks ago, but...
|   
The worst-case consideration is the Confirm option:
max value =  255
          - 2 bytes for type/length
          - 1 byte for feature number 
          - 1 byte for confirmed value (6.2)
	  = max 251 distinct values.

So make it 251 instead?	- we will need some new RFCs :)


| >  #ifdef __KERNEL__
| >  
| > --- a/net/dccp/proto.c
| > +++ b/net/dccp/proto.c
| > @@ -505,6 +505,34 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
| >  	return rc;
| >  }
| >  
| > +static int dccp_setsockopt_ccid(struct sock *sk, int type,
| > +				char __user *optval, int optlen)
| > +{
| > +	u8 *val;
| > +	int rc = 0;
| > +
| > +	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
| > +		return -EINVAL;
| > +
| > +	val = kmalloc(optlen, GFP_KERNEL);
| > +	if (val = NULL)
| > +		return -ENOMEM;
| > +
| > +	if (copy_from_user(val, optval, optlen))
| > +		rc = -EFAULT;
| > +
| > +	lock_sock(sk);
| > +	if (!rc && (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID))
| > +		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
| > +
| 
| This _really_ is confusing! Why not:
| 
| 	rc = -EFAULT;
| 	if (copy_from_user(val, optval, optlen))
| 		goto out;
| 
| 	lock_sock(sk);
| 	rc = 0;
| 	if (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID)
| 		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
| 
| 	if (!rc && (type = DCCP_SOCKOPT_RX_CCID || type = DCCP_SOCKOPT_CCID))
| 		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
| 	release_sock(sk);
| out:
| > +	kfree(val);
| > +	return rc;
| > +}
| 
| :-)
| 
| And even then that '0' or '1' requires one to look at what this binary
| number means, we could have something like
| dccp_feat_register_sp_{local,remote} perhaps, IIRC that is the is_local
| parameter, no?
| 
Thanks, I will be revising this with regard to the above. 

If you want, we could consider dropping the DCCP_SOCKOPT_{RX,TX}_CCID 
since mixed-mode is at the moment not well understood and will lead
to bad performance (e.g. CCID-3 on the forward path and CCID-2 on the
reverse path). 

That would make both the above statements and the socket API much
simpler. Would that be ok?

With regard to the dccp_feat_register_sp_local() function, the price to
pay is that either lines will be longer than 80 characters or that we
will end up with more multi-line statements, which does IMO not help
readability.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 16/37] dccp: API to query the current TX/RX CCID
  2008-08-28 17:44                                   ` Gerrit Renker
@ 2008-08-29  7:26                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  7:26 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

Quoting Arnaldo:
| Em Thu, Aug 28, 2008 at 07:44:51PM +0200, Gerrit Renker escreveu:
| > This provides function to query the current TX/RX CCID dynamically, without
| > reliance on the minisock value, using dynamic information available in the
| > currently loaded CCID module.
| > 
| > This query function is then used to
| >  (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
| >  (b) replace the current test for "which CCID is in use" in probe.c.
| > 
| > Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
| > Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
| > ---
| >  net/dccp/ccid.h  |    9 +++++++++
| >  net/dccp/probe.c |    7 ++-----
| >  net/dccp/proto.c |    6 ++++++
| >  3 files changed, 17 insertions(+), 5 deletions(-)
| > 
| > --- a/net/dccp/ccid.h
| > +++ b/net/dccp/ccid.h
| > @@ -116,6 +116,15 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
| >  extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
| >  				   gfp_t gfp);
| >  
| > +static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
| > +{
| > +	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
| > +
| > +	if (ccid == NULL || ccid->ccid_ops == NULL)
| > +		return -1;
| > +	return ccid->ccid_ops->ccid_id;
| > +}
| > +
| >  extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
| >  extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
| >  
| > --- a/net/dccp/probe.c
| > +++ b/net/dccp/probe.c
| > @@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
| >  static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
| >  			 struct msghdr *msg, size_t size)
| >  {
| > -	const struct dccp_minisock *dmsk = dccp_msk(sk);
| >  	const struct inet_sock *inet = inet_sk(sk);
| > -	const struct ccid3_hc_tx_sock *hctx;
| > +	struct ccid3_hc_tx_sock *hctx = NULL;
| >  
| > -	if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
| > +	if (ccid_get_current_id(dccp_sk(sk), false) == DCCPC_CCID3)
| 
| The use of boolean here also hurts the brain, I guess we could have
| ccid_get_current_rx_id or something along these lines?
| 
The only other place where ccid_get_current_id is called is in
do_dccp_getsockopt.

Rather than a yes/no, I think a third alternative is possible here:
it should actually not be necessary to have CCID-dependent code in
net/dccp/probe.c, i.e. in jdccp_write_xmit() we could have something like

f (!port || ntohs(inet->dport) == port || ntohs(inet->sport) == port) {

                tv  = ktime_to_timespec(ktime_sub(ktime_get(), dccpw.start));
                len = sprintf(buf, "%lu.%09lu %d.%d.%d.%d:%u %d.%d.%d.%d:%u %d",
                               (unsigned long)tv.tv_sec,
                               (unsigned long)tv.tv_nsec,
                               NIPQUAD(inet->saddr), ntohs(inet->sport),
                               NIPQUAD(inet->daddr), ntohs(inet->dport), ccid);

                len += ccid_hc_tx_print_sock_state(sk);
		/*     ^ new CCID-dependent function for printing */

		// ...


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 16/37] dccp: API to query the current TX/RX CCID
@ 2008-08-29  7:26                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-29  7:26 UTC (permalink / raw)
  To: dccp

Quoting Arnaldo:
| Em Thu, Aug 28, 2008 at 07:44:51PM +0200, Gerrit Renker escreveu:
| > This provides function to query the current TX/RX CCID dynamically, without
| > reliance on the minisock value, using dynamic information available in the
| > currently loaded CCID module.
| > 
| > This query function is then used to
| >  (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
| >  (b) replace the current test for "which CCID is in use" in probe.c.
| > 
| > Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
| > Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
| > ---
| >  net/dccp/ccid.h  |    9 +++++++++
| >  net/dccp/probe.c |    7 ++-----
| >  net/dccp/proto.c |    6 ++++++
| >  3 files changed, 17 insertions(+), 5 deletions(-)
| > 
| > --- a/net/dccp/ccid.h
| > +++ b/net/dccp/ccid.h
| > @@ -116,6 +116,15 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
| >  extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
| >  				   gfp_t gfp);
| >  
| > +static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
| > +{
| > +	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
| > +
| > +	if (ccid = NULL || ccid->ccid_ops = NULL)
| > +		return -1;
| > +	return ccid->ccid_ops->ccid_id;
| > +}
| > +
| >  extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
| >  extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
| >  
| > --- a/net/dccp/probe.c
| > +++ b/net/dccp/probe.c
| > @@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
| >  static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
| >  			 struct msghdr *msg, size_t size)
| >  {
| > -	const struct dccp_minisock *dmsk = dccp_msk(sk);
| >  	const struct inet_sock *inet = inet_sk(sk);
| > -	const struct ccid3_hc_tx_sock *hctx;
| > +	struct ccid3_hc_tx_sock *hctx = NULL;
| >  
| > -	if (dmsk->dccpms_tx_ccid = DCCPC_CCID3)
| > +	if (ccid_get_current_id(dccp_sk(sk), false) = DCCPC_CCID3)
| 
| The use of boolean here also hurts the brain, I guess we could have
| ccid_get_current_rx_id or something along these lines?
| 
The only other place where ccid_get_current_id is called is in
do_dccp_getsockopt.

Rather than a yes/no, I think a third alternative is possible here:
it should actually not be necessary to have CCID-dependent code in
net/dccp/probe.c, i.e. in jdccp_write_xmit() we could have something like

f (!port || ntohs(inet->dport) = port || ntohs(inet->sport) = port) {

                tv  = ktime_to_timespec(ktime_sub(ktime_get(), dccpw.start));
                len = sprintf(buf, "%lu.%09lu %d.%d.%d.%d:%u %d.%d.%d.%d:%u %d",
                               (unsigned long)tv.tv_sec,
                               (unsigned long)tv.tv_nsec,
                               NIPQUAD(inet->saddr), ntohs(inet->sport),
                               NIPQUAD(inet->daddr), ntohs(inet->dport), ccid);

                len += ccid_hc_tx_print_sock_state(sk);
		/*     ^ new CCID-dependent function for printing */

		// ...


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
  2008-08-28 17:44                               ` Gerrit Renker
@ 2008-08-29  9:25                                 ` Eugene Teo
  -1 siblings, 0 replies; 484+ messages in thread
From: Eugene Teo @ 2008-08-29  9:25 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

On Fri, Aug 29, 2008 at 1:44 AM, Gerrit Renker <gerrit@erg.abdn.ac.uk> wrote:
[...]
> +       default:
> +               if (optlen < sizeof(int))
> +                       return -EINVAL;

Although it is already checked in sys_setsockopt(), it's probably good
to change this to:

               if (optlen < (int)sizeof(int))
                       return -EINVAL;

Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>

Thanks, Eugene

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
@ 2008-08-29  9:25                                 ` Eugene Teo
  0 siblings, 0 replies; 484+ messages in thread
From: Eugene Teo @ 2008-08-29  9:25 UTC (permalink / raw)
  To: dccp

On Fri, Aug 29, 2008 at 1:44 AM, Gerrit Renker <gerrit@erg.abdn.ac.uk> wrote:
[...]
> +       default:
> +               if (optlen < sizeof(int))
> +                       return -EINVAL;

Although it is already checked in sys_setsockopt(), it's probably good
to change this to:

               if (optlen < (int)sizeof(int))
                       return -EINVAL;

Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>

Thanks, Eugene

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-30 13:51             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:51 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

dccp: List management for new feature negotiation

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Thanks to Arnaldo for suggestions to improve the code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -150,6 +150,125 @@ static void dccp_feat_entry_destructor(s
 	}
 }
 
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num == feat && entry->is_local == local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval == NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-30 13:51             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:51 UTC (permalink / raw)
  To: dccp

dccp: List management for new feature negotiation

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Thanks to Arnaldo for suggestions to improve the code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -150,6 +150,125 @@ static void dccp_feat_entry_destructor(s
 	}
 }
 
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num = feat_num && entry->is_local = is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num = feat && entry->is_local = local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval = NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 03/37] dccp: List management for new feature negotiation
  2008-08-28 17:44         ` Gerrit Renker
@ 2008-08-30 13:51             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:51 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > +static struct dccp_feat_entry *
| > +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +	struct list_head *pos_head = fn;
| > +
| > +	list_for_each(pos_head, fn) {
| > +		entry = list_entry(pos_head, struct dccp_feat_entry, node);
| > +		if (feat < entry->feat_num)
| > +			break;
| 
| Why not use list_for_each_entry()?
| 
I know now why list_for_each() was chosen - if the list does not contain
a feat/is_local entry yet, the pos_head is used later for the 
		list_add_tail(&entry->node, pos_head);
statement. I have rewritten the function now with list_for_each_entry
and will resubmit the new version.

| > +		if (entry->feat_num == feat && entry->is_local == is_local) {
| > +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
| 
| <first reaction>
| You call dccp_feat_val_destructor on entry->val, that kfrees a field and
| then return it? I havent checked, but would it be safer to set the field
| kfree'ed in dccp_feat_val_destructor to NULL since
| dccp_feat_val_destructor is not a destructor (i.e. its not the last
| function in the life of dccp_feat_val)?
|
Yes that is correct. As far as I can see, my own use of these functions is
consistent, but it does not allow someone else to use the functions in a
different setting. But the place to fix it was Patch 2/37, which has been
changed as follows:

 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
-	if (val && dccp_feat_type(feat_num) == FEAT_SP)
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
 		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
 }


| I got confused with a _new routine that ends up not being a constructor
| and _destructor being called on an object, then not setting what it
| frees to NULL and then reusing it somehow
| 
Suggestions for better names are welcome. I thought it over, and _new
was the best I could come up with. But I have rewritten the documentation
and added more text. Hopefully this will make things clearer.

I also thought about the two other suggestions
 (a) Whether to use dccp_feat_list_lookup() in the _new constructor to
     reduce code duplication:
     The constructor also keeps the list always sorted. So when the
     lookup function returns NULL, the search becomes O(2*n) instead
     of n. I tried it with a routine `dccp_feat_lookup_nearest' which
     returns the next list_head before which to insert. But then one
     would need to repeat the test
	if (entry->feat_num == feat && entry->is_local == is_local) {
     I think this is ugly.
 (b) Whether to use hlist instead:
     This is an optimisation. It seems in principle possible. However,
     as I am doing DCCP in my (limited) spare time and since there are
     many other things to fix - missing functionality or causes of
     failure - I'd suggest to enqueue this at the end of the todo list.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 03/37] dccp: List management for new feature negotiation
@ 2008-08-30 13:51             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:51 UTC (permalink / raw)
  To: dccp

| > +static struct dccp_feat_entry *
| > +	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
| > +{
| > +	struct dccp_feat_entry *entry;
| > +	struct list_head *pos_head = fn;
| > +
| > +	list_for_each(pos_head, fn) {
| > +		entry = list_entry(pos_head, struct dccp_feat_entry, node);
| > +		if (feat < entry->feat_num)
| > +			break;
| 
| Why not use list_for_each_entry()?
| 
I know now why list_for_each() was chosen - if the list does not contain
a feat/is_local entry yet, the pos_head is used later for the 
		list_add_tail(&entry->node, pos_head);
statement. I have rewritten the function now with list_for_each_entry
and will resubmit the new version.

| > +		if (entry->feat_num = feat && entry->is_local = is_local) {
| > +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
| 
| <first reaction>
| You call dccp_feat_val_destructor on entry->val, that kfrees a field and
| then return it? I havent checked, but would it be safer to set the field
| kfree'ed in dccp_feat_val_destructor to NULL since
| dccp_feat_val_destructor is not a destructor (i.e. its not the last
| function in the life of dccp_feat_val)?
|
Yes that is correct. As far as I can see, my own use of these functions is
consistent, but it does not allow someone else to use the functions in a
different setting. But the place to fix it was Patch 2/37, which has been
changed as follows:

 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
-	if (val && dccp_feat_type(feat_num) = FEAT_SP)
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
 		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
 }


| I got confused with a _new routine that ends up not being a constructor
| and _destructor being called on an object, then not setting what it
| frees to NULL and then reusing it somehow
| 
Suggestions for better names are welcome. I thought it over, and _new
was the best I could come up with. But I have rewritten the documentation
and added more text. Hopefully this will make things clearer.

I also thought about the two other suggestions
 (a) Whether to use dccp_feat_list_lookup() in the _new constructor to
     reduce code duplication:
     The constructor also keeps the list always sorted. So when the
     lookup function returns NULL, the search becomes O(2*n) instead
     of n. I tried it with a routine `dccp_feat_lookup_nearest' which
     returns the next list_head before which to insert. But then one
     would need to repeat the test
	if (entry->feat_num = feat && entry->is_local = is_local) {
     I think this is ugly.
 (b) Whether to use hlist instead:
     This is an optimisation. It seems in principle possible. However,
     as I am doing DCCP in my (limited) spare time and since there are
     many other things to fix - missing functionality or causes of
     failure - I'd suggest to enqueue this at the end of the todo list.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 08/37] dccp: Query supported CCIDs
  2008-08-28 17:44                   ` Gerrit Renker
@ 2008-08-30 13:52                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > This provides a data structure to record which CCIDs are locally supported
| > and three accessor functions:
<snip> 
| But this limits us to the CCIDs at kernel build time, what if I want to
| test CCID4? I guess we could have something like a bitmap and check if
| the bit for that CCID is set, and it would be set at ccid_register time.
| 
| Perhaps using include/linux/bitmap.h :-)
| 
I looked at it and it actually seems an attractive idea. I have the
following suggestion: the key point of this patch set to improve the
present (mainline) interface for feature negotiation.

People have complained earlier about crashes when trying to negotiate
different CCIDs with the present mechanism. I think this happened with D-ITG.

For the present patch set I would like to keep it as it is, since the
existing CCIDs are buggy/incomplete enough to delay work on entirely new
CCIDs.

But the test tree has still empty disk space for lots of patches, so
this is an invitation to contribute.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 08/37] dccp: Query supported CCIDs
@ 2008-08-30 13:52                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: dccp

| > This provides a data structure to record which CCIDs are locally supported
| > and three accessor functions:
<snip> 
| But this limits us to the CCIDs at kernel build time, what if I want to
| test CCID4? I guess we could have something like a bitmap and check if
| the bit for that CCID is set, and it would be set at ccid_register time.
| 
| Perhaps using include/linux/bitmap.h :-)
| 
I looked at it and it actually seems an attractive idea. I have the
following suggestion: the key point of this patch set to improve the
present (mainline) interface for feature negotiation.

People have complained earlier about crashes when trying to negotiate
different CCIDs with the present mechanism. I think this happened with D-ITG.

For the present patch set I would like to keep it as it is, since the
existing CCIDs are buggy/incomplete enough to delay work on entirely new
CCIDs.

But the test tree has still empty disk space for lots of patches, so
this is an invitation to contribute.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
  2008-08-28 17:44                               ` Gerrit Renker
@ 2008-08-30 13:52                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: Arnaldo, Eugene Teo, ian.mcdonald; +Cc: dccp, netdev

Resent for reference after incorporating the suggestions made by
Arnaldo and Eugene. Many thanks for comments and suggestions.

>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Tidy up setsockopt calls

This splits the setsockopt calls into two groups, depending on whether an
integer argument (val) is required and whether routines being called do
their own locking.

Some options (such as setting the CCID) use u8 rather than int, so that for
these the test with regard to integer-sizeof can not be used.

The second switch-case statement now only has those statements which need
locking and which make use of `val'.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>
---
 net/dccp/proto.c |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -512,7 +512,17 @@ static int do_dccp_setsockopt(struct soc
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
+	switch (optname) {
+	case DCCP_SOCKOPT_PACKET_SIZE:
+		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+		return 0;
+	case DCCP_SOCKOPT_CHANGE_L:
+	case DCCP_SOCKOPT_CHANGE_R:
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		return 0;
+	}
+
+	if (optlen < (int)sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
@@ -523,15 +533,6 @@ static int do_dccp_setsockopt(struct soc
 
 	lock_sock(sk);
 	switch (optname) {
-	case DCCP_SOCKOPT_PACKET_SIZE:
-		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
-	case DCCP_SOCKOPT_CHANGE_L:
-	case DCCP_SOCKOPT_CHANGE_R:
-		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
-		err = 0;
-		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
@@ -548,8 +549,8 @@ static int do_dccp_setsockopt(struct soc
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 14/37] dccp: Tidy up setsockopt calls
@ 2008-08-30 13:52                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: dccp

Resent for reference after incorporating the suggestions made by
Arnaldo and Eugene. Many thanks for comments and suggestions.

>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Tidy up setsockopt calls

This splits the setsockopt calls into two groups, depending on whether an
integer argument (val) is required and whether routines being called do
their own locking.

Some options (such as setting the CCID) use u8 rather than int, so that for
these the test with regard to integer-sizeof can not be used.

The second switch-case statement now only has those statements which need
locking and which make use of `val'.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>
---
 net/dccp/proto.c |   23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -512,7 +512,17 @@ static int do_dccp_setsockopt(struct soc
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
+	switch (optname) {
+	case DCCP_SOCKOPT_PACKET_SIZE:
+		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+		return 0;
+	case DCCP_SOCKOPT_CHANGE_L:
+	case DCCP_SOCKOPT_CHANGE_R:
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		return 0;
+	}
+
+	if (optlen < (int)sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
@@ -523,15 +533,6 @@ static int do_dccp_setsockopt(struct soc
 
 	lock_sock(sk);
 	switch (optname) {
-	case DCCP_SOCKOPT_PACKET_SIZE:
-		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
-	case DCCP_SOCKOPT_CHANGE_L:
-	case DCCP_SOCKOPT_CHANGE_R:
-		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
-		err = 0;
-		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
@@ -548,8 +549,8 @@ static int do_dccp_setsockopt(struct soc
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
@ 2008-08-30 13:52                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

This is a revised version which reflects both comments made by Arnaldo.
With regard to the option length, the patch has been combined with a
chunk from a later patch of the same set, where the problem of "maximum
size of a TLV option" reappears: 

  --- a/include/linux/dccp.h
  +++ b/include/linux/dccp.h
  @@ -209,10 +209,12 @@ enum dccp_feature_numbers {
   #define DCCP_SOCKOPT_CCID_RX_INFO	128
   #define DCCP_SOCKOPT_CCID_TX_INFO	192
   
  +/* maximum size of a single TLV-encoded option (sans type/len bytes) */
  +#define DCCP_SINGLE_OPT_MAXLEN         253
  +/* maximum number of CCID preferences that can be registered at one time */
  +#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
   /* maximum number of services provided on the same listening port */
   #define DCCP_SERVICE_LIST_MAX_LEN      32
  -/* maximum number of CCID preferences that can be registered at one time */
  -#define DCCP_CCID_LIST_MAX_LEN	    16
 
Documentation has been added below why the maximum number of CCIDs is 253 - 2.

>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Set per-connection CCIDs via socket options

With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
overrides the defaults set by the global sysctl variables for TX/RX CCIDs.

To make full use of this facility, the remaining patches of this patch set are
needed, which track dependencies and activate negotiated feature values.

Note on the maximum number of CCIDs that can be registered:
-----------------------------------------------------------
The maximum number of CCIDs that can be registered on the socket is constrained
by the space in a Confirm/Change feature negotiation option. 

The space in these in turn depends on the size of header options as defined
in RFC 4340, 5.8. Since this is a recurring constant, it has been moved from
ackvec.h into linux/dccp.h, clarifying its purpose.

Relative to this size, the maximum number of CCID identifiers that can be 
present in a Confirm option (which always consumes 1 byte more than a Change
option, cf. 6.1) is 2 bytes less than the maximum TLV size: one for the
CCID-feature-type and one for the selected value.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 Documentation/networking/dccp.txt |   14 ++++++++++++++
 include/linux/dccp.h              |    7 +++++++
 net/dccp/ackvec.c                 |    9 ++++-----
 net/dccp/ackvec.h                 |    5 ++---
 net/dccp/proto.c                  |   34 ++++++++++++++++++++++++++++++++++
 5 files changed, 61 insertions(+), 8 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also rea
 supported by the endpoint (see include/linux/dccp.h for symbolic constants).
 The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
 
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -203,9 +203,16 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
+/* maximum size of a single TLV-encoded option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN         253
+/* maximum number of CCID preferences that can be registered at one time */
+#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -506,6 +506,36 @@ static int dccp_setsockopt_cscov(struct 
 	return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
+		return -EINVAL;
+
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
+	}
+
+	lock_sock(sk);
+	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
+
+	kfree(val);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -520,6 +550,10 @@ static int do_dccp_setsockopt(struct soc
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
 		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
 	}
 
 	if (optlen < (int)sizeof(int))
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,15 +11,14 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -12,7 +12,6 @@
 #include "ackvec.h"
 #include "dccp.h"
 
-#include <linux/dccp.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -68,7 +67,7 @@ int dccp_insert_option_ackvec(struct soc
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +99,8 @@ int dccp_insert_option_ackvec(struct soc
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +431,7 @@ found:
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 15/37] dccp: Set per-connection CCIDs via socket options
@ 2008-08-30 13:52                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: dccp

This is a revised version which reflects both comments made by Arnaldo.
With regard to the option length, the patch has been combined with a
chunk from a later patch of the same set, where the problem of "maximum
size of a TLV option" reappears: 

  --- a/include/linux/dccp.h
  +++ b/include/linux/dccp.h
  @@ -209,10 +209,12 @@ enum dccp_feature_numbers {
   #define DCCP_SOCKOPT_CCID_RX_INFO	128
   #define DCCP_SOCKOPT_CCID_TX_INFO	192
   
  +/* maximum size of a single TLV-encoded option (sans type/len bytes) */
  +#define DCCP_SINGLE_OPT_MAXLEN         253
  +/* maximum number of CCID preferences that can be registered at one time */
  +#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
   /* maximum number of services provided on the same listening port */
   #define DCCP_SERVICE_LIST_MAX_LEN      32
  -/* maximum number of CCID preferences that can be registered at one time */
  -#define DCCP_CCID_LIST_MAX_LEN	    16
 
Documentation has been added below why the maximum number of CCIDs is 253 - 2.

>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Set per-connection CCIDs via socket options

With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
overrides the defaults set by the global sysctl variables for TX/RX CCIDs.

To make full use of this facility, the remaining patches of this patch set are
needed, which track dependencies and activate negotiated feature values.

Note on the maximum number of CCIDs that can be registered:
-----------------------------------------------------------
The maximum number of CCIDs that can be registered on the socket is constrained
by the space in a Confirm/Change feature negotiation option. 

The space in these in turn depends on the size of header options as defined
in RFC 4340, 5.8. Since this is a recurring constant, it has been moved from
ackvec.h into linux/dccp.h, clarifying its purpose.

Relative to this size, the maximum number of CCID identifiers that can be 
present in a Confirm option (which always consumes 1 byte more than a Change
option, cf. 6.1) is 2 bytes less than the maximum TLV size: one for the
CCID-feature-type and one for the selected value.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 Documentation/networking/dccp.txt |   14 ++++++++++++++
 include/linux/dccp.h              |    7 +++++++
 net/dccp/ackvec.c                 |    9 ++++-----
 net/dccp/ackvec.h                 |    5 ++---
 net/dccp/proto.c                  |   34 ++++++++++++++++++++++++++++++++++
 5 files changed, 61 insertions(+), 8 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also rea
 supported by the endpoint (see include/linux/dccp.h for symbolic constants).
 The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
 
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -203,9 +203,16 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
+/* maximum size of a single TLV-encoded option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN         253
+/* maximum number of CCID preferences that can be registered at one time */
+#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -506,6 +506,36 @@ static int dccp_setsockopt_cscov(struct 
 	return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
+		return -EINVAL;
+
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val = NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
+	}
+
+	lock_sock(sk);
+	if (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID)
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+	if (!rc && (type = DCCP_SOCKOPT_RX_CCID || type = DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
+
+	kfree(val);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -520,6 +550,10 @@ static int do_dccp_setsockopt(struct soc
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
 		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
 	}
 
 	if (optlen < (int)sizeof(int))
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,15 +11,14 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -12,7 +12,6 @@
 #include "ackvec.h"
 #include "dccp.h"
 
-#include <linux/dccp.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -68,7 +67,7 @@ int dccp_insert_option_ackvec(struct soc
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +99,8 @@ int dccp_insert_option_ackvec(struct soc
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +431,7 @@ found:
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 16/37] dccp: API to query the current TX/RX CCID
@ 2008-08-30 13:52                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev; +Cc: ian.mcdonald

Revised, sent for reference after incorporating suggestions by Arnaldo.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: API to query the current TX/RX CCID

This provides function to query the current TX/RX CCID dynamically, without
reliance on the minisock value, using dynamic information available in the
currently loaded CCID module.

This query function is then used to 
 (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
 (b) replace the current test for "which CCID is in use" in probe.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h  |   18 ++++++++++++++++++
 net/dccp/probe.c |    7 ++-----
 net/dccp/proto.c |   10 ++++++++++
 3 files changed, 30 insertions(+), 5 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -116,6 +116,24 @@ extern struct ccid *ccid_hc_rx_new(unsig
 extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
 				   gfp_t gfp);
 
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -667,6 +667,16 @@ static int do_dccp_getsockopt(struct soc
 		break;
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_rx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
+	if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port == 0 || ntohs(inet->dport) == port ||
 	    ntohs(inet->sport) == port) {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 16/37] dccp: API to query the current TX/RX CCID
@ 2008-08-30 13:52                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 13:52 UTC (permalink / raw)
  To: dccp

Revised, sent for reference after incorporating suggestions by Arnaldo.

>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: API to query the current TX/RX CCID

This provides function to query the current TX/RX CCID dynamically, without
reliance on the minisock value, using dynamic information available in the
currently loaded CCID module.

This query function is then used to 
 (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
 (b) replace the current test for "which CCID is in use" in probe.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h  |   18 ++++++++++++++++++
 net/dccp/probe.c |    7 ++-----
 net/dccp/proto.c |   10 ++++++++++
 3 files changed, 30 insertions(+), 5 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -116,6 +116,24 @@ extern struct ccid *ccid_hc_rx_new(unsig
 extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
 				   gfp_t gfp);
 
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid = NULL || ccid->ccid_ops = NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
+
+	if (ccid = NULL || ccid->ccid_ops = NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -667,6 +667,16 @@ static int do_dccp_getsockopt(struct soc
 		break;
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_rx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid = DCCPC_CCID3)
+	if (ccid_get_current_tx_ccid(dccp_sk(sk)) = DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port = 0 || ntohs(inet->dport) = port ||
 	    ntohs(inet->sport) = port) {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 0/37] --- Summary of revision changes so far
@ 2008-08-30 17:25             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 17:25 UTC (permalink / raw)
  To: dccp, netdev

Below is the summary of changes after the revision.
Thanks to everyone who sent comments and suggestions.

I will wait a few more days for further comments and then
prepare a pull request. 

It is not a problem to send comments, patches and suggestions afterwards.
Changes can then go into the test tree or, in case there are any errors,
be added.


The statistics are:
-------------------
 include/linux/dccp.h |    6 ++--
 net/dccp/ackvec.h    |    3 --
 net/dccp/ccid.h      |   13 +++++++--
 net/dccp/feat.c      |   71 ++++++++++++++++++++++++++-------------------------
 net/dccp/probe.c     |    2 -
 net/dccp/proto.c     |   41 +++++++++++++++++------------
 6 files changed, 78 insertions(+), 58 deletions(-)


--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -228,10 +228,12 @@ enum dccp_packet_dequeueing_policy {
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
+/* maximum size of a single TLV-encoded option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN         253
+/* maximum number of CCID preferences that can be registered at one time */
+#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
-/* maximum number of CCID preferences that can be registered at one time */
-#define DCCP_CCID_LIST_MAX_LEN	       16
 
 #ifdef __KERNEL__
 
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,12 +11,11 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* maximum size of a single TLV-encoded option (sans type/len bytes) */
-#define DCCP_SINGLE_OPT_MAXLEN	253
 /*
  * Ack Vector buffer space is static, in multiples of %DCCP_SINGLE_OPT_MAXLEN,
  * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -108,9 +108,18 @@ extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
 {
-	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
 
 	if (ccid == NULL || ccid->ccid_ops == NULL)
 		return -1;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -387,8 +387,11 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 
 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
-	if (val && dccp_feat_type(feat_num) == FEAT_SP)
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
 		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
 }
 
 static struct dccp_feat_entry *
@@ -422,57 +425,57 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 }
 
 /*
- *	List management functions
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
  */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
 
 /**
  * dccp_feat_entry_new  -  Central list update routine (called by all others)
- * @fn: list to add to
- * @feat: feature number
- * @is_local: whether the local (1) or remote feature with number @feat is meant
- * The function maintains and relies on the following invariants:
- *  - each feat_num in the list is known, ie. we know its type and default value
- *  - each feat_num/is_local combination is unique (old entries are overwritten)
- *  - SP values are always freshly allocated
- *  - list is sorted in increasing order of feature number (faster lookup)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
  */
 static struct dccp_feat_entry *
-	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
 {
 	struct dccp_feat_entry *entry;
-	struct list_head *pos_head = fn;
 
-	list_for_each(pos_head, fn) {
-		entry = list_entry(pos_head, struct dccp_feat_entry, node);
-		if (feat < entry->feat_num)
-			break;
-		if (entry->feat_num == feat && entry->is_local == is_local) {
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num == feat && entry->is_local == local) {
 			dccp_feat_val_destructor(entry->feat_num, &entry->val);
 			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
 		}
-	}
-	entry = kmalloc(sizeof(struct dccp_feat_entry), gfp_any());
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
 	if (entry != NULL) {
 		entry->feat_num = feat;
-		entry->is_local = is_local;
-		list_add_tail(&entry->node, pos_head);
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
 	}
 	return entry;
 }
 
-static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
-						     u8 feat_num, u8 is_local)
-{
-	struct dccp_feat_entry *entry;
-
-	list_for_each_entry(entry, fn_list, node)
-		if (entry->feat_num == feat_num && entry->is_local == is_local)
-			return entry;
-		else if (entry->feat_num > feat_num)
-			break;
-	return NULL;
-}
-
 /**
  * dccp_feat_push_change  -  Add/overwrite a Change option in the list
  * @fn_list: feature-negotiation list to update
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -55,7 +55,7 @@ static void jdccp_write_xmit(struct sock *sk)
 	struct ccid3_hc_tx_sock *hctx = NULL;
 	struct timespec tv;
 	char buf[256];
-	int len, ccid = ccid_get_current_id(dccp_sk(sk), false);
+	int len, ccid = ccid_get_current_tx_ccid(dccp_sk(sk));
 
 	if (ccid == DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -440,11 +440,6 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 
 	if (cscov < 0 || cscov > 15)
 		return -EINVAL;
-
-	if (rx)
-		dccp_sk(sk)->dccps_pcrlen = cscov;
-	else
-		dccp_sk(sk)->dccps_pcslen = cscov;
 	/*
 	 * Populate a list of permissible values, in the range cscov...15. This
 	 * is necessary since feature negotiation of single values only works if
@@ -464,6 +459,12 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 
 	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
 
+	if (rc == 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
 	kfree(list);
 	return rc;
 }
@@ -481,11 +482,13 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
 	if (val == NULL)
 		return -ENOMEM;
 
-	if (copy_from_user(val, optval, optlen))
-		rc = -EFAULT;
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
+	}
 
 	lock_sock(sk);
-	if (!rc && (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID))
+	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
 		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
 
 	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
@@ -514,16 +517,16 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_RX_CCID:
 	case DCCP_SOCKOPT_TX_CCID:
 		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
-	default:
-		if (optlen < sizeof(int))
-			return -EINVAL;
+	}
 
-		if (get_user(val, (int __user *)optval))
-			return -EFAULT;
+	if (optlen < (int)sizeof(int))
+		return -EINVAL;
 
-		if (optname == DCCP_SOCKOPT_SERVICE)
-			return dccp_setsockopt_service(sk, val, optval, optlen);
-	}
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	if (optname == DCCP_SOCKOPT_SERVICE)
+		return dccp_setsockopt_service(sk, val, optval, optlen);
 
 	lock_sock(sk);
 	switch (optname) {
@@ -642,8 +645,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_RX_CCID:
-		val = ccid_get_current_id(dp, optname == DCCP_SOCKOPT_RX_CCID);
+		val = ccid_get_current_rx_ccid(dp);
 		if (val < 0)
 			return -ENOPROTOOPT;
 		break;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 0/37] --- Summary of revision changes so far
@ 2008-08-30 17:25             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-08-30 17:25 UTC (permalink / raw)
  To: dccp

Below is the summary of changes after the revision.
Thanks to everyone who sent comments and suggestions.

I will wait a few more days for further comments and then
prepare a pull request. 

It is not a problem to send comments, patches and suggestions afterwards.
Changes can then go into the test tree or, in case there are any errors,
be added.


The statistics are:
-------------------
 include/linux/dccp.h |    6 ++--
 net/dccp/ackvec.h    |    3 --
 net/dccp/ccid.h      |   13 +++++++--
 net/dccp/feat.c      |   71 ++++++++++++++++++++++++++-------------------------
 net/dccp/probe.c     |    2 -
 net/dccp/proto.c     |   41 +++++++++++++++++------------
 6 files changed, 78 insertions(+), 58 deletions(-)


--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -228,10 +228,12 @@ enum dccp_packet_dequeueing_policy {
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
+/* maximum size of a single TLV-encoded option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN         253
+/* maximum number of CCID preferences that can be registered at one time */
+#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
-/* maximum number of CCID preferences that can be registered at one time */
-#define DCCP_CCID_LIST_MAX_LEN	       16
 
 #ifdef __KERNEL__
 
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,12 +11,11 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* maximum size of a single TLV-encoded option (sans type/len bytes) */
-#define DCCP_SINGLE_OPT_MAXLEN	253
 /*
  * Ack Vector buffer space is static, in multiples of %DCCP_SINGLE_OPT_MAXLEN,
  * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -108,9 +108,18 @@ extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-static inline int ccid_get_current_id(struct dccp_sock *dp, bool rx)
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
 {
-	struct ccid *ccid = rx ? dp->dccps_hc_rx_ccid : dp->dccps_hc_tx_ccid;
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid = NULL || ccid->ccid_ops = NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
 
 	if (ccid = NULL || ccid->ccid_ops = NULL)
 		return -1;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -387,8 +387,11 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 
 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
-	if (val && dccp_feat_type(feat_num) = FEAT_SP)
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
 		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
 }
 
 static struct dccp_feat_entry *
@@ -422,57 +425,57 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 }
 
 /*
- *	List management functions
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
  */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num = feat_num && entry->is_local = is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
 
 /**
  * dccp_feat_entry_new  -  Central list update routine (called by all others)
- * @fn: list to add to
- * @feat: feature number
- * @is_local: whether the local (1) or remote feature with number @feat is meant
- * The function maintains and relies on the following invariants:
- *  - each feat_num in the list is known, ie. we know its type and default value
- *  - each feat_num/is_local combination is unique (old entries are overwritten)
- *  - SP values are always freshly allocated
- *  - list is sorted in increasing order of feature number (faster lookup)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
  */
 static struct dccp_feat_entry *
-	      dccp_feat_entry_new(struct list_head *fn, u8 feat, u8 is_local)
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
 {
 	struct dccp_feat_entry *entry;
-	struct list_head *pos_head = fn;
 
-	list_for_each(pos_head, fn) {
-		entry = list_entry(pos_head, struct dccp_feat_entry, node);
-		if (feat < entry->feat_num)
-			break;
-		if (entry->feat_num = feat && entry->is_local = is_local) {
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num = feat && entry->is_local = local) {
 			dccp_feat_val_destructor(entry->feat_num, &entry->val);
 			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
 		}
-	}
-	entry = kmalloc(sizeof(struct dccp_feat_entry), gfp_any());
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
 	if (entry != NULL) {
 		entry->feat_num = feat;
-		entry->is_local = is_local;
-		list_add_tail(&entry->node, pos_head);
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
 	}
 	return entry;
 }
 
-static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
-						     u8 feat_num, u8 is_local)
-{
-	struct dccp_feat_entry *entry;
-
-	list_for_each_entry(entry, fn_list, node)
-		if (entry->feat_num = feat_num && entry->is_local = is_local)
-			return entry;
-		else if (entry->feat_num > feat_num)
-			break;
-	return NULL;
-}
-
 /**
  * dccp_feat_push_change  -  Add/overwrite a Change option in the list
  * @fn_list: feature-negotiation list to update
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -55,7 +55,7 @@ static void jdccp_write_xmit(struct sock *sk)
 	struct ccid3_hc_tx_sock *hctx = NULL;
 	struct timespec tv;
 	char buf[256];
-	int len, ccid = ccid_get_current_id(dccp_sk(sk), false);
+	int len, ccid = ccid_get_current_tx_ccid(dccp_sk(sk));
 
 	if (ccid = DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -440,11 +440,6 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 
 	if (cscov < 0 || cscov > 15)
 		return -EINVAL;
-
-	if (rx)
-		dccp_sk(sk)->dccps_pcrlen = cscov;
-	else
-		dccp_sk(sk)->dccps_pcslen = cscov;
 	/*
 	 * Populate a list of permissible values, in the range cscov...15. This
 	 * is necessary since feature negotiation of single values only works if
@@ -464,6 +459,12 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 
 	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
 
+	if (rc = 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
 	kfree(list);
 	return rc;
 }
@@ -481,11 +482,13 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
 	if (val = NULL)
 		return -ENOMEM;
 
-	if (copy_from_user(val, optval, optlen))
-		rc = -EFAULT;
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
+	}
 
 	lock_sock(sk);
-	if (!rc && (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID))
+	if (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID)
 		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
 
 	if (!rc && (type = DCCP_SOCKOPT_RX_CCID || type = DCCP_SOCKOPT_CCID))
@@ -514,16 +517,16 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_RX_CCID:
 	case DCCP_SOCKOPT_TX_CCID:
 		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
-	default:
-		if (optlen < sizeof(int))
-			return -EINVAL;
+	}
 
-		if (get_user(val, (int __user *)optval))
-			return -EFAULT;
+	if (optlen < (int)sizeof(int))
+		return -EINVAL;
 
-		if (optname = DCCP_SOCKOPT_SERVICE)
-			return dccp_setsockopt_service(sk, val, optval, optlen);
-	}
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	if (optname = DCCP_SOCKOPT_SERVICE)
+		return dccp_setsockopt_service(sk, val, optval, optlen);
 
 	lock_sock(sk);
 	switch (optname) {
@@ -642,8 +645,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_RX_CCID:
-		val = ccid_get_current_id(dp, optname = DCCP_SOCKOPT_RX_CCID);
+		val = ccid_get_current_rx_ccid(dp);
 		if (val < 0)
 			return -ENOPROTOOPT;
 		break;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
@ 2008-09-01 16:46               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-01 16:46 UTC (permalink / raw)
  To: David S. Miller, dccp, netdev

Hi Dave,

can you please consider the following DCCP set of patches. It is a
self-contained set for feature negotiation among endpoints.

These have been tested over a long period in the test tree. 

The set contains the same patches as submitted to netdev/dccp@vger last week.
Thanks to contributions from several people, this revised set contains several
improvements. I have just verified that the set is still fully bisectable.

The set can be pulled from

	git://eden-feed.erg.abdn.ac.uk/net-next-2.6 	[subtree `master']

which uses a fresh net-next-2.6 from today, also compile-tested.

A summary is below, changes can be viewed online at
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git

- Gerrit

Part I - Basis
---------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  
Patch #6: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #7: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #8: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #9: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

Part II - Core	  
--------------
Patch #10: Provides a mechanism to then resolve CCID-dependent features. Since
           CCIDs are a server-priority feature, this is done by the server.
Patch #11: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #12: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #13: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #14: Tidies up the setsockopt interface for new additions.
Patch #15: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #16: Socket API to query the current CCID from userspace.
Patch #17: Prepares the variable-length htonl/ntohl functions for 48 bits.
           Such a length is needed by e.g. the Sequence Window feature.
Patch #18: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #19: Routine to insert feature-negotiation header options.
Patch #20: Complements #19, to add feature-negotiation options onto the skb.
Patch #21: Complements #20 and completes the insertion of featneg options.
Patch #22: Logic/algorithm to actually reconcile negotiation options.
Patch #23: Receiver support to process incoming Change L/R options. 
Patch #24: Receiver support to process incoming Confirm R/L options.
Patch #25: Handlers for activating successfully negotiated features.

Part III - Integration and cleanup
----------------------------------
Patch #26: Integration of dynamic negotiation, part I (socket setup).
Patch #27: Integration of dynamic negotiation, part II (server side).
Patch #28: Integration of dynamic negotiation, part III (client side).

Patch #29: Cleans up the older infrastructure.
Patch #30: Removes obsolete parts of the old CCID interface.
Patch #31: Removes manual intervention on NDP count (now automatic).
Patch #32: Removes Ack Vector sysctl (handled automatically now).

Patch #33: Initialisation framework for the supported features.
Patch #34: Auto-loading of CCID modules so that the modules are available
           when the negotiation is completed.
Patch #35: Adds full support for local/remote Sequence Window.
Patch #36: Initialisation and type-checking of involved sysctls.
Patch #37: A set of (useful) debugging/printing helper functions.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-01 16:46               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-01 16:46 UTC (permalink / raw)
  To: dccp

Hi Dave,

can you please consider the following DCCP set of patches. It is a
self-contained set for feature negotiation among endpoints.

These have been tested over a long period in the test tree. 

The set contains the same patches as submitted to netdev/dccp@vger last week.
Thanks to contributions from several people, this revised set contains several
improvements. I have just verified that the set is still fully bisectable.

The set can be pulled from

	git://eden-feed.erg.abdn.ac.uk/net-next-2.6 	[subtree `master']

which uses a fresh net-next-2.6 from today, also compile-tested.

A summary is below, changes can be viewed online at
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git

- Gerrit

Part I - Basis
---------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  
Patch #6: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #7: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #8: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #9: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

Part II - Core	  
--------------
Patch #10: Provides a mechanism to then resolve CCID-dependent features. Since
           CCIDs are a server-priority feature, this is done by the server.
Patch #11: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #12: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #13: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #14: Tidies up the setsockopt interface for new additions.
Patch #15: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #16: Socket API to query the current CCID from userspace.
Patch #17: Prepares the variable-length htonl/ntohl functions for 48 bits.
           Such a length is needed by e.g. the Sequence Window feature.
Patch #18: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #19: Routine to insert feature-negotiation header options.
Patch #20: Complements #19, to add feature-negotiation options onto the skb.
Patch #21: Complements #20 and completes the insertion of featneg options.
Patch #22: Logic/algorithm to actually reconcile negotiation options.
Patch #23: Receiver support to process incoming Change L/R options. 
Patch #24: Receiver support to process incoming Confirm R/L options.
Patch #25: Handlers for activating successfully negotiated features.

Part III - Integration and cleanup
----------------------------------
Patch #26: Integration of dynamic negotiation, part I (socket setup).
Patch #27: Integration of dynamic negotiation, part II (server side).
Patch #28: Integration of dynamic negotiation, part III (client side).

Patch #29: Cleans up the older infrastructure.
Patch #30: Removes obsolete parts of the old CCID interface.
Patch #31: Removes manual intervention on NDP count (now automatic).
Patch #32: Removes Ack Vector sysctl (handled automatically now).

Patch #33: Initialisation framework for the supported features.
Patch #34: Auto-loading of CCID modules so that the modules are available
           when the negotiation is completed.
Patch #35: Adds full support for local/remote Sequence Window.
Patch #36: Initialisation and type-checking of involved sysctls.
Patch #37: A set of (useful) debugging/printing helper functions.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-01 21:20                 ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-01 21:20 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 1 Sep 2008 18:46:33 +0200

> The set contains the same patches as submitted to netdev/dccp@vger last week.
> Thanks to contributions from several people, this revised set contains several
> improvements. I have just verified that the set is still fully bisectable.

>From what I can tell the only person who reviewed this set was Arnaldo
and he was only able to review about half of the patches before passing
out.

Surely I can imagine he would come up with similar fixups and commentary
for the rest of these patches were he given the chance to do so.

So I'd like to wait and give him the chance to provide that feedback.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-01 21:20                 ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-01 21:20 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 1 Sep 2008 18:46:33 +0200

> The set contains the same patches as submitted to netdev/dccp@vger last week.
> Thanks to contributions from several people, this revised set contains several
> improvements. I have just verified that the set is still fully bisectable.

From what I can tell the only person who reviewed this set was Arnaldo
and he was only able to review about half of the patches before passing
out.

Surely I can imagine he would come up with similar fixups and commentary
for the rest of these patches were he given the chance to do so.

So I'd like to wait and give him the chance to provide that feedback.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
  2008-08-28 17:44                                         ` Gerrit Renker
@ 2008-09-02  5:48                                           ` Wei Yongjun
  -1 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-02  5:48 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Gerrit Renker wrote:
> The patch extends existing code:
>  * Confirm options divide into the confirmed value plus an optional preference
>    list for SP values. Previously only the preference list was echoed for SP
>    values, now the confirmed value is added as per RFC 4340, 6.1;
>  * length and sanity checks are added to avoid illegal memory (or NULL) access;
>  * clarified the use of TLV length constant, which does not have anything to do
>    with ECN, but with the fact that Type-Length-Value options whose length is
>    determined by an u8 field provide Value space for at most 255 - 2 = 253 bytes
>    due to the Type/Length fields.
>
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ackvec.c  |    8 ++--
>  net/dccp/ackvec.h  |    6 ++--
>  net/dccp/feat.h    |    2 +
>  net/dccp/options.c |   91 ++++++++++++++++++----------------------------------
>  4 files changed, 40 insertions(+), 67 deletions(-)
>
> --- a/net/dccp/ackvec.c
> +++ b/net/dccp/ackvec.c
> @@ -68,7 +68,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
>  	struct dccp_sock *dp = dccp_sk(sk);
>  	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
>  	/* Figure out how many options do we need to represent the ackvec */
> -	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
> +	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
>  	u16 len = av->av_vec_len + 2 * nr_opts, i;
>  	u32 elapsed_time;
>  	const unsigned char *tail, *from;
> @@ -100,8 +100,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
>  	for (i = 0; i < nr_opts; ++i) {
>  		int copylen = len;
>  
> -		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
> -			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
> +		if (len > DCCP_SINGLE_OPT_MAXLEN)
> +			copylen = DCCP_SINGLE_OPT_MAXLEN;
>  
>  		*to++ = DCCPO_ACK_VECTOR_0;
>  		*to++ = copylen + 2;
> @@ -432,7 +432,7 @@ found:
>  int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
>  		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
>  {
> -	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
> +	if (len > DCCP_SINGLE_OPT_MAXLEN)
>  		return -1;
>  
>  	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
> --- a/net/dccp/ackvec.h
> +++ b/net/dccp/ackvec.h
> @@ -16,10 +16,10 @@
>  #include <linux/list.h>
>  #include <linux/types.h>
>  
> -/* Read about the ECN nonce to see why it is 253 */
> -#define DCCP_MAX_ACKVEC_OPT_LEN 253
> +/* maximum size of a single TLV-encoded option (sans type/len bytes) */
> +#define DCCP_SINGLE_OPT_MAXLEN	253
>  /* We can spread an ack vector across multiple options */
> -#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
> +#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
>  
>  #define DCCP_ACKVEC_STATE_RECEIVED	0
>  #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -138,4 +138,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
>  extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
>  
>  extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
> +extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
> +			       u8 *val, u8 len, bool repeat_first);
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb)
>  	return 0;
>  }
>  
> -static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
> -				u8 *val, u8 len)
> +/**
> + * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
> + * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
> + * @feat: one out of %dccp_feature_numbers
> + * @val: NN value or SP array (preferred element first) to copy
> + * @len: true length of @val in bytes (excluding first element repetition)
> + * @repeat_first: whether to copy the first element of @val twice
> + * The last argument is used to construct Confirm options, where the preferred
> + * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
> + * lists are kept such that the preferred entry is always first, so we only need
> + * to copy twice, and avoid the overhead of cloning into a bigger array.
> + */
> +int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
> +		       u8 *val, u8 len, bool repeat_first)
>  {
> -	u8 *to;
> +	u8 tot_len, *to;
>  
> -	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
> -		DCCP_WARN("packet too small for feature %d option!\n", feat);
> +	/* take the `Feature' field and possible repetition into account */
> +	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
> +		DCCP_WARN("length %u for feature %u too large\n", len, feat);
>  		return -1;
>  	}
>   

Here, should check (len > DCCP_SINGLE_OPT_MAXLEN - 3 - repeat_first)?

if len == DCCP_SINGLE_OPT_MAXLEN - 2, then

tot_len = 3 + repeat_first + len == (DCCP_SINGLE_OPT_MAXLEN + 1 +
repeat_first)

The total length of this option will larger than DCCP_SINGLE_OPT_MAXLEN.



>  
> -	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
> +	if (unlikely(val == NULL || len == 0))
> +		len = repeat_first = 0;
> +	tot_len = 3 + repeat_first + len;
> +
> +	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
> +		DCCP_WARN("packet too small for feature %d option!\n", feat);
> +		return -1;
> +	}
> +	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
>  
> -	to    = skb_push(skb, len + 3);
> +	to    = skb_push(skb, tot_len);
>  	*to++ = type;
> -	*to++ = len + 3;
> +	*to++ = tot_len;
>  	*to++ = feat;
>  
> +	if (repeat_first)
> +		*to++ = *val;
>  	if (len)
>  		memcpy(to, val, len);
>  
> @@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
>  	return 0;
>  }
>  
> -static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
> -{
> -	struct dccp_minisock *dmsk = dccp_msk(sk);
> -	struct dccp_opt_pend *opt, *next;
> -	int change = 0;
> -
> -	/* confirm any options [NN opts] */
> -	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
> -		dccp_insert_feat_opt(skb, opt->dccpop_type,
> -				     opt->dccpop_feat, opt->dccpop_val,
> -				     opt->dccpop_len);
> -		/* fear empty confirms */
> -		if (opt->dccpop_val)
> -			kfree(opt->dccpop_val);
> -		kfree(opt);
> -	}
> -	INIT_LIST_HEAD(&dmsk->dccpms_conf);
> -
> -	/* see which features we need to send */
> -	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
> -		/* see if we need to send any confirm */
> -		if (opt->dccpop_sc) {
> -			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
> -					     opt->dccpop_feat,
> -					     opt->dccpop_sc->dccpoc_val,
> -					     opt->dccpop_sc->dccpoc_len);
> -
> -			BUG_ON(!opt->dccpop_sc->dccpoc_val);
> -			kfree(opt->dccpop_sc->dccpoc_val);
> -			kfree(opt->dccpop_sc);
> -			opt->dccpop_sc = NULL;
> -		}
> -
> -		/* any option not confirmed, re-send it */
> -		if (!opt->dccpop_conf) {
> -			dccp_insert_feat_opt(skb, opt->dccpop_type,
> -					     opt->dccpop_feat, opt->dccpop_val,
> -					     opt->dccpop_len);
> -			change++;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
>  /* The length of all options needs to be a multiple of 4 (5.8) */
>  static void dccp_insert_option_padding(struct sk_buff *skb)
>  {
> @@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
>  		dp->dccps_hc_rx_insert_options = 0;
>  	}
>  
> -	/* Feature negotiation */
> -	/* Data packets can't do feat negotiation */
> -	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
> -	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
> -	    dccp_insert_options_feat(sk, skb))
> -		return -1;
> -
>  	/*
>  	 * Obtain RTT sample from Request/Response exchange.
>  	 * This is currently used in CCID 3 initialisation.
>   


-- 
--------------------------------------------------
Wei Yongjun
Development Dept.I
Nanjing Fujitsu Nanda Software Tech. Co., Ltd.(FNST)
8/F., Civil Defense Building, No.189 Guangzhou Road,
Nanjing, 210029, China
TEL: +86+25-86630523-836
COINS: 79955-836
FAX: +86+25-83317685
MAIL: yjwei@cn.fujitsu.com
--------------------------------------------------
This communication is for use by the intended recipient(s) only and may contain information that is privileged, confidential and exempt from disclosure under applicable law. If you are not an intended recipient of this communication, you are hereby notified that any dissemination, distribution or copying hereof is strictly prohibited.  If you have received this communication in error, please notify me by reply e-mail, permanently delete this communication from your system, and destroy any hard copies you may have printed


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
@ 2008-09-02  5:48                                           ` Wei Yongjun
  0 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-02  5:48 UTC (permalink / raw)
  To: dccp

Gerrit Renker wrote:
> The patch extends existing code:
>  * Confirm options divide into the confirmed value plus an optional preference
>    list for SP values. Previously only the preference list was echoed for SP
>    values, now the confirmed value is added as per RFC 4340, 6.1;
>  * length and sanity checks are added to avoid illegal memory (or NULL) access;
>  * clarified the use of TLV length constant, which does not have anything to do
>    with ECN, but with the fact that Type-Length-Value options whose length is
>    determined by an u8 field provide Value space for at most 255 - 2 = 253 bytes
>    due to the Type/Length fields.
>
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ackvec.c  |    8 ++--
>  net/dccp/ackvec.h  |    6 ++--
>  net/dccp/feat.h    |    2 +
>  net/dccp/options.c |   91 ++++++++++++++++++----------------------------------
>  4 files changed, 40 insertions(+), 67 deletions(-)
>
> --- a/net/dccp/ackvec.c
> +++ b/net/dccp/ackvec.c
> @@ -68,7 +68,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
>  	struct dccp_sock *dp = dccp_sk(sk);
>  	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
>  	/* Figure out how many options do we need to represent the ackvec */
> -	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
> +	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
>  	u16 len = av->av_vec_len + 2 * nr_opts, i;
>  	u32 elapsed_time;
>  	const unsigned char *tail, *from;
> @@ -100,8 +100,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
>  	for (i = 0; i < nr_opts; ++i) {
>  		int copylen = len;
>  
> -		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
> -			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
> +		if (len > DCCP_SINGLE_OPT_MAXLEN)
> +			copylen = DCCP_SINGLE_OPT_MAXLEN;
>  
>  		*to++ = DCCPO_ACK_VECTOR_0;
>  		*to++ = copylen + 2;
> @@ -432,7 +432,7 @@ found:
>  int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
>  		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
>  {
> -	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
> +	if (len > DCCP_SINGLE_OPT_MAXLEN)
>  		return -1;
>  
>  	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
> --- a/net/dccp/ackvec.h
> +++ b/net/dccp/ackvec.h
> @@ -16,10 +16,10 @@
>  #include <linux/list.h>
>  #include <linux/types.h>
>  
> -/* Read about the ECN nonce to see why it is 253 */
> -#define DCCP_MAX_ACKVEC_OPT_LEN 253
> +/* maximum size of a single TLV-encoded option (sans type/len bytes) */
> +#define DCCP_SINGLE_OPT_MAXLEN	253
>  /* We can spread an ack vector across multiple options */
> -#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
> +#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
>  
>  #define DCCP_ACKVEC_STATE_RECEIVED	0
>  #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -138,4 +138,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
>  extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
>  
>  extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
> +extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
> +			       u8 *val, u8 len, bool repeat_first);
>  #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb)
>  	return 0;
>  }
>  
> -static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
> -				u8 *val, u8 len)
> +/**
> + * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
> + * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
> + * @feat: one out of %dccp_feature_numbers
> + * @val: NN value or SP array (preferred element first) to copy
> + * @len: true length of @val in bytes (excluding first element repetition)
> + * @repeat_first: whether to copy the first element of @val twice
> + * The last argument is used to construct Confirm options, where the preferred
> + * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
> + * lists are kept such that the preferred entry is always first, so we only need
> + * to copy twice, and avoid the overhead of cloning into a bigger array.
> + */
> +int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
> +		       u8 *val, u8 len, bool repeat_first)
>  {
> -	u8 *to;
> +	u8 tot_len, *to;
>  
> -	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
> -		DCCP_WARN("packet too small for feature %d option!\n", feat);
> +	/* take the `Feature' field and possible repetition into account */
> +	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
> +		DCCP_WARN("length %u for feature %u too large\n", len, feat);
>  		return -1;
>  	}
>   

Here, should check (len > DCCP_SINGLE_OPT_MAXLEN - 3 - repeat_first)?

if len = DCCP_SINGLE_OPT_MAXLEN - 2, then

tot_len = 3 + repeat_first + len = (DCCP_SINGLE_OPT_MAXLEN + 1 +
repeat_first)

The total length of this option will larger than DCCP_SINGLE_OPT_MAXLEN.



>  
> -	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
> +	if (unlikely(val = NULL || len = 0))
> +		len = repeat_first = 0;
> +	tot_len = 3 + repeat_first + len;
> +
> +	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
> +		DCCP_WARN("packet too small for feature %d option!\n", feat);
> +		return -1;
> +	}
> +	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
>  
> -	to    = skb_push(skb, len + 3);
> +	to    = skb_push(skb, tot_len);
>  	*to++ = type;
> -	*to++ = len + 3;
> +	*to++ = tot_len;
>  	*to++ = feat;
>  
> +	if (repeat_first)
> +		*to++ = *val;
>  	if (len)
>  		memcpy(to, val, len);
>  
> @@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
>  	return 0;
>  }
>  
> -static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
> -{
> -	struct dccp_minisock *dmsk = dccp_msk(sk);
> -	struct dccp_opt_pend *opt, *next;
> -	int change = 0;
> -
> -	/* confirm any options [NN opts] */
> -	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
> -		dccp_insert_feat_opt(skb, opt->dccpop_type,
> -				     opt->dccpop_feat, opt->dccpop_val,
> -				     opt->dccpop_len);
> -		/* fear empty confirms */
> -		if (opt->dccpop_val)
> -			kfree(opt->dccpop_val);
> -		kfree(opt);
> -	}
> -	INIT_LIST_HEAD(&dmsk->dccpms_conf);
> -
> -	/* see which features we need to send */
> -	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
> -		/* see if we need to send any confirm */
> -		if (opt->dccpop_sc) {
> -			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
> -					     opt->dccpop_feat,
> -					     opt->dccpop_sc->dccpoc_val,
> -					     opt->dccpop_sc->dccpoc_len);
> -
> -			BUG_ON(!opt->dccpop_sc->dccpoc_val);
> -			kfree(opt->dccpop_sc->dccpoc_val);
> -			kfree(opt->dccpop_sc);
> -			opt->dccpop_sc = NULL;
> -		}
> -
> -		/* any option not confirmed, re-send it */
> -		if (!opt->dccpop_conf) {
> -			dccp_insert_feat_opt(skb, opt->dccpop_type,
> -					     opt->dccpop_feat, opt->dccpop_val,
> -					     opt->dccpop_len);
> -			change++;
> -		}
> -	}
> -
> -	return 0;
> -}
> -
>  /* The length of all options needs to be a multiple of 4 (5.8) */
>  static void dccp_insert_option_padding(struct sk_buff *skb)
>  {
> @@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
>  		dp->dccps_hc_rx_insert_options = 0;
>  	}
>  
> -	/* Feature negotiation */
> -	/* Data packets can't do feat negotiation */
> -	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
> -	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
> -	    dccp_insert_options_feat(sk, skb))
> -		return -1;
> -
>  	/*
>  	 * Obtain RTT sample from Request/Response exchange.
>  	 * This is currently used in CCID 3 initialisation.
>   


-- 
--------------------------------------------------
Wei Yongjun
Development Dept.I
Nanjing Fujitsu Nanda Software Tech. Co., Ltd.(FNST)
8/F., Civil Defense Building, No.189 Guangzhou Road,
Nanjing, 210029, China
TEL: +86+25-86630523-836
COINS: 79955-836
FAX: +86+25-83317685
MAIL: yjwei@cn.fujitsu.com
--------------------------------------------------
This communication is for use by the intended recipient(s) only and may contain information that is privileged, confidential and exempt from disclosure under applicable law. If you are not an intended recipient of this communication, you are hereby notified that any dissemination, distribution or copying hereof is strictly prohibited.  If you have received this communication in error, please notify me by reply e-mail, permanently delete this communication from your system, and destroy any hard copies you may have printed


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature values
  2008-08-28 17:44                 ` Gerrit Renker
@ 2008-09-02  6:12                       ` Wei Yongjun
  -1 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-02  6:12 UTC (permalink / raw)
  To: Gerrit Renker, Arnaldo Carvalho de Melo, dccp, netdev

Gerrit Renker wrote:
> | > +/* check that SP values are within the ranges defined in RFC 4340 */
> | > +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
> | > +{
> | > +	switch (feat_num) {
> | > +	case DCCPF_CCID:
> | > +		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
> | 
> | Shouldn't we look at the registered CCIDs and do validation based on the
> | modules loaded? Doing it this hardcoded way will prevent testing CCID4,
> | for instance, or require that the kernel be patched, which can not be
> | possible with enterprise distros, etc. And defeats the purpose of having
> | multiple pluggable congestion control algorithms :-)
> | 
> The point is valid and actually such a check is done, see further below.
>
> In the CCID-4 subtree, the above statement changes to
>  | > +		val >= DCCPC_CCID2 && val <= DCCPC_CCID4;
>   

This may cause DCCP client which support only CCID 2 and CCID 3 can not 
connect to a DCCP server which support CCID2 to CCID4.

See as following:

DCCP client                    DCCP server
REQUEST           ------->
(CHANGE_R/CCID 2 3)
                  <-------     RESPONSE
                               (CONFIRM_R/CCID 2 2 3 4)


RESPONSE from DCCP server with CONFIRM_R(CCID 2 2 3 4) will cause DCCP 
client send a reset to DCCP server.

This is because dccp_feat_confirm_recv() will check whether the feat 
list is valid before accept the CCID.

static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, 
u8 opt, ... {
    ...
    if (!dccp_feat_sp_list_ok(feat, val, len))
        goto confirmation_failed;
    ...
}


> The above function only serves as sanity-check for SP values, so that no
> unknown values appear. There is a registry for CCID identifiers, only
> ones that are in RFC documents are "valid". With regard to RFC 4340,
> 19.5 we could consider adding the experimental identifiers here
> (248-254 are valid, we could use one for the "UDP-like" CCID).	
>
> With regard to doing validation based on the modules loaded, the
> mechanism works as follows:
>  1. at socket initialisation time dccp_init_sock calls dccp_feat_init
>  2. dccp_feat_init queries the compiled-in CCIDs:
>         /*
>          * We advertise the available list of CCIDs and reorder according to
>          * preferences, to avoid failure resulting from negotiating different
>          * singleton values (which always leads to failure).
>          * These settings can still (later) be overridden via sockopts.
>          */
>         if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
>             ccid_get_builtin_ccids(&rx.val, &rx.len))
>                 return -ENOBUFS;
>     ==> If it succeeds, the `tx' and `rx' entries will be identical copies.
>
>  3. The next step in dccp_feat_init is to try and load all configured  CCIDs:
>
>         if (ccid_request_modules(tx.val, tx.len))
>                 goto free_ccid_lists;
>
>     ==> If this succeeds, the host is ready to answer to any request by
> 	the peer.
>
>  4. Finally, if the peer tries to negotiate an unknown CCID, negotiation
>     will fail as per the server-priority negotiation rules (6.3.1), unless
>     the peer has an entry in its CCID list which agrees with an entry of
>     our list.
>   


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature
@ 2008-09-02  6:12                       ` Wei Yongjun
  0 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-02  6:12 UTC (permalink / raw)
  To: dccp

Gerrit Renker wrote:
> | > +/* check that SP values are within the ranges defined in RFC 4340 */
> | > +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
> | > +{
> | > +	switch (feat_num) {
> | > +	case DCCPF_CCID:
> | > +		return val = DCCPC_CCID2 || val = DCCPC_CCID3;
> | 
> | Shouldn't we look at the registered CCIDs and do validation based on the
> | modules loaded? Doing it this hardcoded way will prevent testing CCID4,
> | for instance, or require that the kernel be patched, which can not be
> | possible with enterprise distros, etc. And defeats the purpose of having
> | multiple pluggable congestion control algorithms :-)
> | 
> The point is valid and actually such a check is done, see further below.
>
> In the CCID-4 subtree, the above statement changes to
>  | > +		val >= DCCPC_CCID2 && val <= DCCPC_CCID4;
>   

This may cause DCCP client which support only CCID 2 and CCID 3 can not 
connect to a DCCP server which support CCID2 to CCID4.

See as following:

DCCP client                    DCCP server
REQUEST           ------->
(CHANGE_R/CCID 2 3)
                  <-------     RESPONSE
                               (CONFIRM_R/CCID 2 2 3 4)


RESPONSE from DCCP server with CONFIRM_R(CCID 2 2 3 4) will cause DCCP 
client send a reset to DCCP server.

This is because dccp_feat_confirm_recv() will check whether the feat 
list is valid before accept the CCID.

static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, 
u8 opt, ... {
    ...
    if (!dccp_feat_sp_list_ok(feat, val, len))
        goto confirmation_failed;
    ...
}


> The above function only serves as sanity-check for SP values, so that no
> unknown values appear. There is a registry for CCID identifiers, only
> ones that are in RFC documents are "valid". With regard to RFC 4340,
> 19.5 we could consider adding the experimental identifiers here
> (248-254 are valid, we could use one for the "UDP-like" CCID).	
>
> With regard to doing validation based on the modules loaded, the
> mechanism works as follows:
>  1. at socket initialisation time dccp_init_sock calls dccp_feat_init
>  2. dccp_feat_init queries the compiled-in CCIDs:
>         /*
>          * We advertise the available list of CCIDs and reorder according to
>          * preferences, to avoid failure resulting from negotiating different
>          * singleton values (which always leads to failure).
>          * These settings can still (later) be overridden via sockopts.
>          */
>         if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
>             ccid_get_builtin_ccids(&rx.val, &rx.len))
>                 return -ENOBUFS;
>     => If it succeeds, the `tx' and `rx' entries will be identical copies.
>
>  3. The next step in dccp_feat_init is to try and load all configured  CCIDs:
>
>         if (ccid_request_modules(tx.val, tx.len))
>                 goto free_ccid_lists;
>
>     => If this succeeds, the host is ready to answer to any request by
> 	the peer.
>
>  4. Finally, if the peer tries to negotiate an unknown CCID, negotiation
>     will fail as per the server-priority negotiation rules (6.3.1), unless
>     the peer has an entry in its CCID list which agrees with an entry of
>     our list.
>   


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
  2008-08-28 17:45                                                     ` Gerrit Renker
@ 2008-09-02  6:34                                                       ` Wei Yongjun
  -1 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-02  6:34 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: dccp, netdev

Gerrit Renker 写道:
> This patch provides the post-processing of feature negotiation state, after
> the negotiation has completed.
>
> To this purpose, handlers are used and added to the dccp_feat_table. Each
> handler is passed a boolean flag whether the RX or TX side of the feature
> is meant.
>
> Several handlers are provided already, new handlers can easily be added.
>
> The initialisation is now fully dynamic, i.e. CCIDs are activated only
> after the feature negotiation. The integration of this dynamic activation
> is done in the subsequent patches.
>
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/dccp.h |    1 +
>  net/dccp/feat.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 211 insertions(+), 10 deletions(-)
>
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -445,6 +445,7 @@ 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*,
>  				  struct sk_buff *skb);
> +extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
>  extern void dccp_feat_list_purge(struct list_head *fn_list);
>  
>  extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -25,11 +25,101 @@
>  
>  #define DCCP_FEAT_SP_NOAGREE (-123)
>  
> +/*
> + * Feature activation handlers.
> + *
> + * These all use an u64 argument, to provide enough room for NN/SP features. At
> + * this stage the negotiated values have been checked to be within their range.
> + */
> +static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
> +
> +	if (new_ccid == NULL)
> +		return -ENOMEM;
> +
> +	if (rx) {
> +		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
> +		dp->dccps_hc_rx_ccid = new_ccid;
> +	} else {
> +		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
> +		dp->dccps_hc_tx_ccid = new_ccid;
> +	}
> +	return 0;
> +}
> +
> +static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
> +{
> +	if (!rx)
> +		dccp_msk(sk)->dccpms_sequence_window = seq_win;
> +	return 0;
> +}
> +
> +static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
> +{
> +	if (rx)
> +		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
> +	else
> +		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
> +	return 0;
> +}
> +
> +static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +
> +	if (rx) {
> +		if (enable && dp->dccps_hc_rx_ackvec == NULL) {
> +			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
> +			if (dp->dccps_hc_rx_ackvec == NULL)
> +				return -ENOMEM;
> +		} else if (!enable) {
> +			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
> +			dp->dccps_hc_rx_ackvec = NULL;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
> +{
> +	if (!rx)
> +		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
> +	return 0;
> +}
> +
> +/*
> + * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
> + * `rx' holds when the sending peer informs about his partial coverage via a
> + * ChangeR() option. In the other case, we are the sender and the receiver
> + * announces its coverage via ChangeL() options. The policy here is to honour
> + * such communication by enabling the corresponding partial coverage - but only
> + * if it has not been set manually before; the warning here means that all
> + * packets will be dropped.
> + */
> +static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +
> +	if (rx)
> +		dp->dccps_pcrlen = cscov;
> +	else {
> +		if (dp->dccps_pcslen == 0)
> +			dp->dccps_pcslen = cscov;
> +		else if (cscov > dp->dccps_pcslen)
> +			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
> +				  dp->dccps_pcslen, (u8)cscov);
> +	}
> +	return 0;
> +}
> +
>  static const struct {
>  	u8			feat_num;		/* DCCPF_xxx */
>  	enum dccp_feat_type	rxtx;			/* RX or TX  */
>  	enum dccp_feat_type	reconciliation;		/* SP or NN  */
>  	u8			default_value;		/* as in 6.4 */
> +	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
>  /*
>   *    Lookup table for location and type of features (from RFC 4340/4342)
>   *  +--------------------------+----+-----+----+----+---------+-----------+
> @@ -49,16 +139,16 @@ static const struct {
>   *  +--------------------------+----+-----+----+----+---------+-----------+
>   */
>  } dccp_feat_table[] = {
> -	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
> -	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
> -	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
> -	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
> -	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
> -	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
> +	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
> +	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
> +	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
> +	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
> +	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
> +	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
> +	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
> +	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
> +	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
> +	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
>  };
>  #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
>  
> @@ -99,6 +189,55 @@ static int dccp_feat_default_value(u8 feat_num)
>  	return idx < 0 ? : dccp_feat_table[idx].default_value;
>  }
>  
> +static int __dccp_feat_activate(struct sock *sk, const int idx,
> +				const bool is_local, dccp_feat_val const *fval)
> +{
> +	bool rx;
> +	u64 val;
> +
> +	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
> +		return -1;
> +	if (dccp_feat_table[idx].activation_hdlr == NULL)
> +		return 0;
> +
> +	if (fval == NULL) {
> +		val = dccp_feat_table[idx].default_value;
> +	} else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
> +		if (fval->sp.vec == NULL) {
> +			/*
> +			 * This can happen when an empty Confirm is sent
> +			 * for an SP (i.e. known) feature. In this case
> +			 * we would be using the default anyway.
> +			 */
> +			DCCP_CRIT("Feature #%d undefined: using default", idx);
> +			val = dccp_feat_table[idx].default_value;
> +		} else {
> +			val = fval->sp.vec[0];
> +		}
> +	} else {
> +		val = fval->nn;
> +	}
> +
> +	/* Location is RX if this is a local-RX or remote-TX feature */
> +	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
> +
> +	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 mean 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)
>  {
> @@ -1504,6 +1643,67 @@ out:
>  
>  EXPORT_SYMBOL_GPL(dccp_feat_init);
>  
> +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +	struct dccp_feat_entry *cur, *next;
> +	int idx;
> +	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
> +		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
> +	};
> +
> +	list_for_each_entry(cur, fn_list, node) {
> +
> +		idx = dccp_feat_index(cur->feat_num);
> +		if (idx < 0) {
> +			DCCP_BUG("Unknown feature %u", cur->feat_num);
> +			goto activation_failed;
>   

idx < 0 is possible, if you goto activation_failed, the connection from
endpoint which want to change feature we unkonwn, the connection will be
always fail by reset. So I think it should just continue process the next
feature(s).
-----------------------------------
if (idx < 0)
continue;
-----------------------------------

idx < 0 is happended when we recv a change option with unknown feature type.


> +		}
> +		if (cur->state != FEAT_STABLE) {
> +			DCCP_CRIT("Negotiation of %s %u failed in state %u",
> +				  cur->is_local ? "local" : "remote",
> +				  cur->feat_num, cur->state);
> +			goto activation_failed;
> +		}
> +		fvals[idx][cur->is_local] = &cur->val;
> +	}
> +
> +	/*
> +	 * Activate in decreasing order of index, so that the CCIDs are always
> +	 * activated as the last feature. This avoids the case where a CCID
> +	 * relies on the initialisation of one or more features that it depends
> +	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
> +	 */
> +	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
> +		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
> +		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
> +			DCCP_CRIT("Could not activate %d", idx);
> +			goto activation_failed;
> +		}
> +
> +	/* Clean up Change options which have been confirmed already */
> +	list_for_each_entry_safe(cur, next, fn_list, node)
> +		if (!cur->needs_confirm)
> +			dccp_feat_list_pop(cur);
> +
> +	dccp_pr_debug("Activation OK\n");
> +	return 0;
> +
> +activation_failed:
> +	/*
> +	 * We clean up everything that may have been allocated, since
> +	 * it is difficult to track at which stage negotiation failed.
> +	 * This is ok, since all allocation functions below are robust
> +	 * against NULL arguments.
> +	 */
> +	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
> +	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
> +	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
> +	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
> +	dp->dccps_hc_rx_ackvec = NULL;
> +	return -1;
> +}
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  const char *dccp_feat_typename(const u8 type)
>  {
>   


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
@ 2008-09-02  6:34                                                       ` Wei Yongjun
  0 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-02  6:34 UTC (permalink / raw)
  To: dccp

Gerrit Renker дµÀ:
> This patch provides the post-processing of feature negotiation state, after
> the negotiation has completed.
>
> To this purpose, handlers are used and added to the dccp_feat_table. Each
> handler is passed a boolean flag whether the RX or TX side of the feature
> is meant.
>
> Several handlers are provided already, new handlers can easily be added.
>
> The initialisation is now fully dynamic, i.e. CCIDs are activated only
> after the feature negotiation. The integration of this dynamic activation
> is done in the subsequent patches.
>
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/dccp.h |    1 +
>  net/dccp/feat.c |  220 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 211 insertions(+), 10 deletions(-)
>
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -445,6 +445,7 @@ 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*,
>  				  struct sk_buff *skb);
> +extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
>  extern void dccp_feat_list_purge(struct list_head *fn_list);
>  
>  extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -25,11 +25,101 @@
>  
>  #define DCCP_FEAT_SP_NOAGREE (-123)
>  
> +/*
> + * Feature activation handlers.
> + *
> + * These all use an u64 argument, to provide enough room for NN/SP features. At
> + * this stage the negotiated values have been checked to be within their range.
> + */
> +static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
> +
> +	if (new_ccid = NULL)
> +		return -ENOMEM;
> +
> +	if (rx) {
> +		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
> +		dp->dccps_hc_rx_ccid = new_ccid;
> +	} else {
> +		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
> +		dp->dccps_hc_tx_ccid = new_ccid;
> +	}
> +	return 0;
> +}
> +
> +static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
> +{
> +	if (!rx)
> +		dccp_msk(sk)->dccpms_sequence_window = seq_win;
> +	return 0;
> +}
> +
> +static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
> +{
> +	if (rx)
> +		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
> +	else
> +		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
> +	return 0;
> +}
> +
> +static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +
> +	if (rx) {
> +		if (enable && dp->dccps_hc_rx_ackvec = NULL) {
> +			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
> +			if (dp->dccps_hc_rx_ackvec = NULL)
> +				return -ENOMEM;
> +		} else if (!enable) {
> +			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
> +			dp->dccps_hc_rx_ackvec = NULL;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
> +{
> +	if (!rx)
> +		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
> +	return 0;
> +}
> +
> +/*
> + * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
> + * `rx' holds when the sending peer informs about his partial coverage via a
> + * ChangeR() option. In the other case, we are the sender and the receiver
> + * announces its coverage via ChangeL() options. The policy here is to honour
> + * such communication by enabling the corresponding partial coverage - but only
> + * if it has not been set manually before; the warning here means that all
> + * packets will be dropped.
> + */
> +static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +
> +	if (rx)
> +		dp->dccps_pcrlen = cscov;
> +	else {
> +		if (dp->dccps_pcslen = 0)
> +			dp->dccps_pcslen = cscov;
> +		else if (cscov > dp->dccps_pcslen)
> +			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
> +				  dp->dccps_pcslen, (u8)cscov);
> +	}
> +	return 0;
> +}
> +
>  static const struct {
>  	u8			feat_num;		/* DCCPF_xxx */
>  	enum dccp_feat_type	rxtx;			/* RX or TX  */
>  	enum dccp_feat_type	reconciliation;		/* SP or NN  */
>  	u8			default_value;		/* as in 6.4 */
> +	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
>  /*
>   *    Lookup table for location and type of features (from RFC 4340/4342)
>   *  +--------------------------+----+-----+----+----+---------+-----------+
> @@ -49,16 +139,16 @@ static const struct {
>   *  +--------------------------+----+-----+----+----+---------+-----------+
>   */
>  } dccp_feat_table[] = {
> -	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
> -	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
> -	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
> -	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
> -	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
> -	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
> -	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
> +	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
> +	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
> +	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
> +	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
> +	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
> +	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
> +	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
> +	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
> +	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
> +	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
>  };
>  #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
>  
> @@ -99,6 +189,55 @@ static int dccp_feat_default_value(u8 feat_num)
>  	return idx < 0 ? : dccp_feat_table[idx].default_value;
>  }
>  
> +static int __dccp_feat_activate(struct sock *sk, const int idx,
> +				const bool is_local, dccp_feat_val const *fval)
> +{
> +	bool rx;
> +	u64 val;
> +
> +	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
> +		return -1;
> +	if (dccp_feat_table[idx].activation_hdlr = NULL)
> +		return 0;
> +
> +	if (fval = NULL) {
> +		val = dccp_feat_table[idx].default_value;
> +	} else if (dccp_feat_table[idx].reconciliation = FEAT_SP) {
> +		if (fval->sp.vec = NULL) {
> +			/*
> +			 * This can happen when an empty Confirm is sent
> +			 * for an SP (i.e. known) feature. In this case
> +			 * we would be using the default anyway.
> +			 */
> +			DCCP_CRIT("Feature #%d undefined: using default", idx);
> +			val = dccp_feat_table[idx].default_value;
> +		} else {
> +			val = fval->sp.vec[0];
> +		}
> +	} else {
> +		val = fval->nn;
> +	}
> +
> +	/* Location is RX if this is a local-RX or remote-TX feature */
> +	rx = (is_local = (dccp_feat_table[idx].rxtx = FEAT_AT_RX));
> +
> +	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 mean 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)
>  {
> @@ -1504,6 +1643,67 @@ out:
>  
>  EXPORT_SYMBOL_GPL(dccp_feat_init);
>  
> +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
> +{
> +	struct dccp_sock *dp = dccp_sk(sk);
> +	struct dccp_feat_entry *cur, *next;
> +	int idx;
> +	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
> +		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
> +	};
> +
> +	list_for_each_entry(cur, fn_list, node) {
> +
> +		idx = dccp_feat_index(cur->feat_num);
> +		if (idx < 0) {
> +			DCCP_BUG("Unknown feature %u", cur->feat_num);
> +			goto activation_failed;
>   

idx < 0 is possible, if you goto activation_failed, the connection from
endpoint which want to change feature we unkonwn, the connection will be
always fail by reset. So I think it should just continue process the next
feature(s).
-----------------------------------
if (idx < 0)
continue;
-----------------------------------

idx < 0 is happended when we recv a change option with unknown feature type.


> +		}
> +		if (cur->state != FEAT_STABLE) {
> +			DCCP_CRIT("Negotiation of %s %u failed in state %u",
> +				  cur->is_local ? "local" : "remote",
> +				  cur->feat_num, cur->state);
> +			goto activation_failed;
> +		}
> +		fvals[idx][cur->is_local] = &cur->val;
> +	}
> +
> +	/*
> +	 * Activate in decreasing order of index, so that the CCIDs are always
> +	 * activated as the last feature. This avoids the case where a CCID
> +	 * relies on the initialisation of one or more features that it depends
> +	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
> +	 */
> +	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
> +		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
> +		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
> +			DCCP_CRIT("Could not activate %d", idx);
> +			goto activation_failed;
> +		}
> +
> +	/* Clean up Change options which have been confirmed already */
> +	list_for_each_entry_safe(cur, next, fn_list, node)
> +		if (!cur->needs_confirm)
> +			dccp_feat_list_pop(cur);
> +
> +	dccp_pr_debug("Activation OK\n");
> +	return 0;
> +
> +activation_failed:
> +	/*
> +	 * We clean up everything that may have been allocated, since
> +	 * it is difficult to track at which stage negotiation failed.
> +	 * This is ok, since all allocation functions below are robust
> +	 * against NULL arguments.
> +	 */
> +	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
> +	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
> +	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
> +	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
> +	dp->dccps_hc_rx_ackvec = NULL;
> +	return -1;
> +}
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  const char *dccp_feat_typename(const u8 type)
>  {
>   


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-02 13:50                   ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-02 13:50 UTC (permalink / raw)
  To: David Miller; +Cc: gerrit, dccp, netdev

Em Mon, Sep 01, 2008 at 02:20:55PM -0700, David Miller escreveu:
> From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Date: Mon, 1 Sep 2008 18:46:33 +0200
> 
> > The set contains the same patches as submitted to netdev/dccp@vger last week.
> > Thanks to contributions from several people, this revised set contains several
> > improvements. I have just verified that the set is still fully bisectable.
> 
> >From what I can tell the only person who reviewed this set was Arnaldo
> and he was only able to review about half of the patches before passing
> out.
> 
> Surely I can imagine he would come up with similar fixups and commentary
> for the rest of these patches were he given the chance to do so.
> 
> So I'd like to wait and give him the chance to provide that feedback.


Hi,

	Thanks Dave, but now there is also Wei looking over this patch
set, I'll try to get back to this soon, but I'm busy with other stuff, so if
you think it is ok don't wait too much for me :-)

	I just would love if the core code doesn't get things that are
specific to a particular CCID implementation, as I saw in this patchset in
the net/dccp/feat.c file. struct ccid and ccid_operations were designed
to avoid that.

- Arnaldo
       

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-02 13:50                   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-02 13:50 UTC (permalink / raw)
  To: dccp

Em Mon, Sep 01, 2008 at 02:20:55PM -0700, David Miller escreveu:
> From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Date: Mon, 1 Sep 2008 18:46:33 +0200
> 
> > The set contains the same patches as submitted to netdev/dccp@vger last week.
> > Thanks to contributions from several people, this revised set contains several
> > improvements. I have just verified that the set is still fully bisectable.
> 
> >From what I can tell the only person who reviewed this set was Arnaldo
> and he was only able to review about half of the patches before passing
> out.
> 
> Surely I can imagine he would come up with similar fixups and commentary
> for the rest of these patches were he given the chance to do so.
> 
> So I'd like to wait and give him the chance to provide that feedback.


Hi,

	Thanks Dave, but now there is also Wei looking over this patch
set, I'll try to get back to this soon, but I'm busy with other stuff, so if
you think it is ok don't wait too much for me :-)

	I just would love if the core code doesn't get things that are
specific to a particular CCID implementation, as I saw in this patchset in
the net/dccp/feat.c file. struct ccid and ccid_operations were designed
to avoid that.

- Arnaldo
       

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-03  4:24                     ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:24 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, David Miller, dccp, netdev

| > So I'd like to wait and give him the chance to provide that feedback.
| 
| 
| Hi,
| 
| 	Thanks Dave, but now there is also Wei looking over this patch
| set, I'll try to get back to this soon, but I'm busy with other stuff, so if
| you think it is ok don't wait too much for me :-)
| 
| 	I just would love if the core code doesn't get things that are
| specific to a particular CCID implementation, as I saw in this patchset in
| the net/dccp/feat.c file. struct ccid and ccid_operations were designed
| to avoid that.
| 
So how long should we wait? I am willing to address all reasonable
comments, but it is not true that there has been no time for providing
feedback. The patches were first submitted last October, and if this
means waiting for another year while the patches in the test tree keep
piling up then I will need to draw a line.
Dave what would you like to do?

Arnaldo, I am answering the point raised above as a separate answer in
the thread were it was originally raised. The suggestion to separate out
the dependency table is something which only arose last week. In fact
the current format of the dependency table is thanks to your comments in
http://www.mail-archive.com/dccp@vger.kernel.org/msg02548.html
(October 2007), where this split was not suggested.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-03  4:24                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:24 UTC (permalink / raw)
  To: dccp

| > So I'd like to wait and give him the chance to provide that feedback.
| 
| 
| Hi,
| 
| 	Thanks Dave, but now there is also Wei looking over this patch
| set, I'll try to get back to this soon, but I'm busy with other stuff, so if
| you think it is ok don't wait too much for me :-)
| 
| 	I just would love if the core code doesn't get things that are
| specific to a particular CCID implementation, as I saw in this patchset in
| the net/dccp/feat.c file. struct ccid and ccid_operations were designed
| to avoid that.
| 
So how long should we wait? I am willing to address all reasonable
comments, but it is not true that there has been no time for providing
feedback. The patches were first submitted last October, and if this
means waiting for another year while the patches in the test tree keep
piling up then I will need to draw a line.
Dave what would you like to do?

Arnaldo, I am answering the point raised above as a separate answer in
the thread were it was originally raised. The suggestion to separate out
the dependency table is something which only arose last week. In fact
the current format of the dependency table is thanks to your comments in
http://www.mail-archive.com/dccp@vger.kernel.org/msg02548.html
(October 2007), where this split was not suggested.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
  2008-08-28 17:45                                                     ` Gerrit Renker
@ 2008-09-03  4:38                                                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:38 UTC (permalink / raw)
  To: Wei Yongjun; +Cc: dccp, netdev

| > This patch provides the post-processing of feature negotiation state, after
| > the negotiation has completed.

<snip>
| >  
| > +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
| > +{
| > +	struct dccp_sock *dp = dccp_sk(sk);
| > +	struct dccp_feat_entry *cur, *next;
| > +	int idx;
| > +	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
| > +		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
| > +	};
| > +
| > +	list_for_each_entry(cur, fn_list, node) {
| > +
| > +		idx = dccp_feat_index(cur->feat_num);
| > +		if (idx < 0) {
| > +			DCCP_BUG("Unknown feature %u", cur->feat_num);
| > +			goto activation_failed;
| >   
| 
| idx < 0 is possible, if you goto activation_failed, the connection from
| endpoint which want to change feature we unkonwn, the connection will be
| always fail by reset. So I think it should just continue process the next
| feature(s).
| -----------------------------------
| if (idx < 0)
| continue;
| -----------------------------------
| 
| idx < 0 is happended when we recv a change option with unknown feature type.
| 
| 
No, since an unknown feature at this stage would most definitively be a bug.

The validity checking happens earlier:
 * for NN values every valid value is accepted as per RFC -
   this is ensured via dccp_feat_is_valid_nn_val();
 * for SP values at least the confirmed value must be valid -
   - this is checked in confirm_recv(),
   - setsockopt is protected against registering invalid feature values,
   - for CCIDs, additional a check for availability is made before
     entering negotiation.

These conditions (should) ensure that the above condition is never
triggered, the test is like an assert() clause.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
@ 2008-09-03  4:38                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:38 UTC (permalink / raw)
  To: dccp

| > This patch provides the post-processing of feature negotiation state, after
| > the negotiation has completed.

<snip>
| >  
| > +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
| > +{
| > +	struct dccp_sock *dp = dccp_sk(sk);
| > +	struct dccp_feat_entry *cur, *next;
| > +	int idx;
| > +	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
| > +		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
| > +	};
| > +
| > +	list_for_each_entry(cur, fn_list, node) {
| > +
| > +		idx = dccp_feat_index(cur->feat_num);
| > +		if (idx < 0) {
| > +			DCCP_BUG("Unknown feature %u", cur->feat_num);
| > +			goto activation_failed;
| >   
| 
| idx < 0 is possible, if you goto activation_failed, the connection from
| endpoint which want to change feature we unkonwn, the connection will be
| always fail by reset. So I think it should just continue process the next
| feature(s).
| -----------------------------------
| if (idx < 0)
| continue;
| -----------------------------------
| 
| idx < 0 is happended when we recv a change option with unknown feature type.
| 
| 
No, since an unknown feature at this stage would most definitively be a bug.

The validity checking happens earlier:
 * for NN values every valid value is accepted as per RFC -
   this is ensured via dccp_feat_is_valid_nn_val();
 * for SP values at least the confirmed value must be valid -
   - this is checked in confirm_recv(),
   - setsockopt is protected against registering invalid feature values,
   - for CCIDs, additional a check for availability is made before
     entering negotiation.

These conditions (should) ensure that the above condition is never
triggered, the test is like an assert() clause.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
  2008-08-28 17:44                                         ` Gerrit Renker
@ 2008-09-03  4:40                                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:40 UTC (permalink / raw)
  To: Wei Yongjun; +Cc: dccp, netdev

| > +/**
| > + * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
| > + * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
| > + * @feat: one out of %dccp_feature_numbers
| > + * @val: NN value or SP array (preferred element first) to copy
| > + * @len: true length of @val in bytes (excluding first element repetition)
| > + * @repeat_first: whether to copy the first element of @val twice
| > + * The last argument is used to construct Confirm options, where the preferred
| > + * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
| > + * lists are kept such that the preferred entry is always first, so we only need
| > + * to copy twice, and avoid the overhead of cloning into a bigger array.
| > + */
| > +int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
| > +		       u8 *val, u8 len, bool repeat_first)
| >  {
| > -	u8 *to;
| > +	u8 tot_len, *to;
| >  
| > -	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
| > -		DCCP_WARN("packet too small for feature %d option!\n", feat);
| > +	/* take the `Feature' field and possible repetition into account */
| > +	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
| > +		DCCP_WARN("length %u for feature %u too large\n", len, feat);
| >  		return -1;
| >  	}
| >   
| 
| Here, should check (len > DCCP_SINGLE_OPT_MAXLEN - 3 - repeat_first)?
| 
| if len == DCCP_SINGLE_OPT_MAXLEN - 2, then
| 
| tot_len = 3 + repeat_first + len == (DCCP_SINGLE_OPT_MAXLEN + 1 +
| repeat_first)
| 
| The total length of this option will larger than DCCP_SINGLE_OPT_MAXLEN.
| 
in linux/dccp.h
/* maximum size of a single TLV-encoded option (sans type/len bytes) */
#define DCCP_SINGLE_OPT_MAXLEN         253

So if we assume that len = DCCP_SINGLE_OPT_MAXLEN - 2 = 251, then
tot_len = 3 + 251 + repeat_first, which is
  * 254 if repeat_first = 0
  * 255 if repeat_first = 1
	
So it is correct. 

But your input is useful, since it relates to another question, one line
below in linux/dccp.h:

#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)

this value is the same as in the above test, so will revise to use
something like

#define DCCP_FEAT_MAX_SP_VALS	       (DCCP_SINGLE_OPT_MAXLEN - 2)

to limit the maximum number of server-priority values, in feat.h.

Thanks,
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 19/37] dccp: Header option insertion routine for
@ 2008-09-03  4:40                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:40 UTC (permalink / raw)
  To: dccp

| > +/**
| > + * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
| > + * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
| > + * @feat: one out of %dccp_feature_numbers
| > + * @val: NN value or SP array (preferred element first) to copy
| > + * @len: true length of @val in bytes (excluding first element repetition)
| > + * @repeat_first: whether to copy the first element of @val twice
| > + * The last argument is used to construct Confirm options, where the preferred
| > + * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
| > + * lists are kept such that the preferred entry is always first, so we only need
| > + * to copy twice, and avoid the overhead of cloning into a bigger array.
| > + */
| > +int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
| > +		       u8 *val, u8 len, bool repeat_first)
| >  {
| > -	u8 *to;
| > +	u8 tot_len, *to;
| >  
| > -	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
| > -		DCCP_WARN("packet too small for feature %d option!\n", feat);
| > +	/* take the `Feature' field and possible repetition into account */
| > +	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
| > +		DCCP_WARN("length %u for feature %u too large\n", len, feat);
| >  		return -1;
| >  	}
| >   
| 
| Here, should check (len > DCCP_SINGLE_OPT_MAXLEN - 3 - repeat_first)?
| 
| if len = DCCP_SINGLE_OPT_MAXLEN - 2, then
| 
| tot_len = 3 + repeat_first + len = (DCCP_SINGLE_OPT_MAXLEN + 1 +
| repeat_first)
| 
| The total length of this option will larger than DCCP_SINGLE_OPT_MAXLEN.
| 
in linux/dccp.h
/* maximum size of a single TLV-encoded option (sans type/len bytes) */
#define DCCP_SINGLE_OPT_MAXLEN         253

So if we assume that len = DCCP_SINGLE_OPT_MAXLEN - 2 = 251, then
tot_len = 3 + 251 + repeat_first, which is
  * 254 if repeat_first = 0
  * 255 if repeat_first = 1
	
So it is correct. 

But your input is useful, since it relates to another question, one line
below in linux/dccp.h:

#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)

this value is the same as in the above test, so will revise to use
something like

#define DCCP_FEAT_MAX_SP_VALS	       (DCCP_SINGLE_OPT_MAXLEN - 2)

to limit the maximum number of server-priority values, in feat.h.

Thanks,
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature values
  2008-08-28 17:44                 ` Gerrit Renker
@ 2008-09-03  4:46                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:46 UTC (permalink / raw)
  To: Wei Yongjun; +Cc: Arnaldo Carvalho de Melo, dccp, netdev

>> | > +/* check that SP values are within the ranges defined in RFC 4340 */
>> | > +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
>> | > +{
<snip>	
>> In the CCID-4 subtree, the above statement changes to
>>  | > +		val >= DCCPC_CCID2 && val <= DCCPC_CCID4;
>>   
>
> This may cause DCCP client which support only CCID 2 and CCID 3 can not  
> connect to a DCCP server which support CCID2 to CCID4.
>
> See as following:
>
> DCCP client                    DCCP server
> REQUEST           ------->
> (CHANGE_R/CCID 2 3)
>                  <-------     RESPONSE
>                               (CONFIRM_R/CCID 2 2 3 4)
>
>
> RESPONSE from DCCP server with CONFIRM_R(CCID 2 2 3 4) will cause DCCP  
> client send a reset to DCCP server.
>
> This is because dccp_feat_confirm_recv() will check whether the feat  
> list is valid before accept the CCID.
>
> static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory,  
> u8 opt, ... {
>    ...
>    if (!dccp_feat_sp_list_ok(feat, val, len))
>        goto confirmation_failed;
>    ...
> }
>
Excellent catch, but the problem you point out is not in the range of
CCID values. It means that the validity checking for SP values in
general is too restrictive: the same problem will reappear not only
for CCIDs, but for all SP features that could have values in the Confirm
list which may locally be unknown. It is also not what 6.6.8 says:
  "Note that server-priority features do not have value limitations,
   since unknown values are handled as a matter of course."

So thank you I will restrict the validity check to the confirmed value only.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 07/37] dccp: Registration routines for changing feature
@ 2008-09-03  4:46                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:46 UTC (permalink / raw)
  To: dccp

>> | > +/* check that SP values are within the ranges defined in RFC 4340 */
>> | > +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
>> | > +{
<snip>	
>> In the CCID-4 subtree, the above statement changes to
>>  | > +		val >= DCCPC_CCID2 && val <= DCCPC_CCID4;
>>   
>
> This may cause DCCP client which support only CCID 2 and CCID 3 can not  
> connect to a DCCP server which support CCID2 to CCID4.
>
> See as following:
>
> DCCP client                    DCCP server
> REQUEST           ------->
> (CHANGE_R/CCID 2 3)
>                  <-------     RESPONSE
>                               (CONFIRM_R/CCID 2 2 3 4)
>
>
> RESPONSE from DCCP server with CONFIRM_R(CCID 2 2 3 4) will cause DCCP  
> client send a reset to DCCP server.
>
> This is because dccp_feat_confirm_recv() will check whether the feat  
> list is valid before accept the CCID.
>
> static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory,  
> u8 opt, ... {
>    ...
>    if (!dccp_feat_sp_list_ok(feat, val, len))
>        goto confirmation_failed;
>    ...
> }
>
Excellent catch, but the problem you point out is not in the range of
CCID values. It means that the validity checking for SP values in
general is too restrictive: the same problem will reappear not only
for CCIDs, but for all SP features that could have values in the Confirm
list which may locally be unknown. It is also not what 6.6.8 says:
  "Note that server-priority features do not have value limitations,
   since unknown values are handled as a matter of course."

So thank you I will restrict the validity check to the confirmed value only.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID
  2008-08-28 17:44                     ` Gerrit Renker
@ 2008-09-03  4:51                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:51 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, dccp, netdev

| > This provides a missing link in the code chain, as several features implicitly
| > depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
| > feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
| > 
<snip>
| 
| Doesn't this belongs into struct ccid_operations? Why has the core feature
| negotiation have knowledge of any specific CCID? When people want to
| merge CCID 4, 5, etc will we need to change net/dccp/feat.c?
| 
| I think that this needs thus to go to struct ccid_operations, and then the feature
| negotiation code can just use use the ccid number to access:
| 
| struct ccid_operations *ccids[CCID_MAX]
| 
| ccids[ccid_number]->deps
|  
I am answering this again as you raised the point in your answer to Dave.

The above is a sketch, I sat down and thought through how this might
actually be implemented.

For each CCID there are two dependencies - one for the RX and one for
the TX CCID.

Dependency lists are variable-length (CCID-2 has 1/1 and CCID-3 as well as
CCID-4 both have 3/4 for the RX/TX sides).

Using struct ccid_operations to query the CCID dependencies means that 
 * the CCID read lock needs to be taken;
 * protection against failed module-load is needed.

The second point should in principle not be a problem since the feature code
tries to request the modules before the negotiation begins. Implementing this
however would at the very least require to test for failure in these cases.

I don't know whether the fact that one module needs to traverse a memory
region of another module causes issues.

The biggest issue that I see is that there is an indirection now: instead 
of looking up the dependencies directly, one now needs to first go through
struct ccid_operations, from there to individual CCID modules, and then
back to the main dccp.ko module.

What we have here at the moment may not be the last word, but its virtue
is that it is simple, it works, and does not require an indirection via the
CCID sub-unit.

In principle I agree with you, what I am asking for is to defer this code
optimisation until later.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice
@ 2008-09-03  4:51                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  4:51 UTC (permalink / raw)
  To: dccp

| > This provides a missing link in the code chain, as several features implicitly
| > depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
| > feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
| > 
<snip>
| 
| Doesn't this belongs into struct ccid_operations? Why has the core feature
| negotiation have knowledge of any specific CCID? When people want to
| merge CCID 4, 5, etc will we need to change net/dccp/feat.c?
| 
| I think that this needs thus to go to struct ccid_operations, and then the feature
| negotiation code can just use use the ccid number to access:
| 
| struct ccid_operations *ccids[CCID_MAX]
| 
| ccids[ccid_number]->deps
|  
I am answering this again as you raised the point in your answer to Dave.

The above is a sketch, I sat down and thought through how this might
actually be implemented.

For each CCID there are two dependencies - one for the RX and one for
the TX CCID.

Dependency lists are variable-length (CCID-2 has 1/1 and CCID-3 as well as
CCID-4 both have 3/4 for the RX/TX sides).

Using struct ccid_operations to query the CCID dependencies means that 
 * the CCID read lock needs to be taken;
 * protection against failed module-load is needed.

The second point should in principle not be a problem since the feature code
tries to request the modules before the negotiation begins. Implementing this
however would at the very least require to test for failure in these cases.

I don't know whether the fact that one module needs to traverse a memory
region of another module causes issues.

The biggest issue that I see is that there is an indirection now: instead 
of looking up the dependencies directly, one now needs to first go through
struct ccid_operations, from there to individual CCID modules, and then
back to the main dccp.ko module.

What we have here at the moment may not be the last word, but its virtue
is that it is simple, it works, and does not require an indirection via the
CCID sub-unit.

In principle I agree with you, what I am asking for is to defer this code
optimisation until later.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
  2008-08-28 17:45                                                     ` Gerrit Renker
@ 2008-09-03  5:42                                                           ` Wei Yongjun
  -1 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-03  5:42 UTC (permalink / raw)
  To: Gerrit Renker, Wei Yongjun, dccp, netdev

Gerrit Renker wrote:
> | > This patch provides the post-processing of feature negotiation state, after
> | > the negotiation has completed.
>
> <snip>
> | >  
> | > +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
> | > +{
> | > +	struct dccp_sock *dp = dccp_sk(sk);
> | > +	struct dccp_feat_entry *cur, *next;
> | > +	int idx;
> | > +	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
> | > +		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
> | > +	};
> | > +
> | > +	list_for_each_entry(cur, fn_list, node) {
> | > +
> | > +		idx = dccp_feat_index(cur->feat_num);
> | > +		if (idx < 0) {
> | > +			DCCP_BUG("Unknown feature %u", cur->feat_num);
> | > +			goto activation_failed;
> | >   
> | 
> | idx < 0 is possible, if you goto activation_failed, the connection from
> | endpoint which want to change feature we unkonwn, the connection will be
> | always fail by reset. So I think it should just continue process the next
> | feature(s).
> | -----------------------------------
> | if (idx < 0)
> | continue;
> | -----------------------------------
> | 
> | idx < 0 is happended when we recv a change option with unknown feature type.
> | 
> | 
> No, since an unknown feature at this stage would most definitively be a bug.
>
> The validity checking happens earlier:
>  * for NN values every valid value is accepted as per RFC -
>    this is ensured via dccp_feat_is_valid_nn_val();
>  * for SP values at least the confirmed value must be valid -
>    - this is checked in confirm_recv(),
>    - setsockopt is protected against registering invalid feature values,
>    - for CCIDs, additional a check for availability is made before
>      entering negotiation.
>
> These conditions (should) ensure that the above condition is never
> triggered, the test is like an assert() clause.
>   

This special case it is not as you said. The packet seq as following:

Endpoint A                    Endpoing B
REQUEST        --------->
(CHANGE L/unknow feature)
               <---------     RESPONSE
                              (CONFIRM R/empty unknow feature)
ACK            ---------->
                              call dccp_feat_activate_values()
                              -->print DCCP_BUG("Unknown feature %u", cur->feat_num);


After Endpoint B send REPONSE with empty CONFIRM R option, the unknow
feature is *still remain* in the feature list. dccp_feat_insert_opts() 
never clean up
those features. So here we can get idx < 0. Features with is not needed 
is clean up
after active the feat value in dccp_feat_activate_values().

int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
{
    ...
    list_for_each_entry_safe(cur, next, fn_list, node)
        if (!cur->needs_confirm)
            dccp_feat_list_pop(cur);
    ...
}
 





^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
@ 2008-09-03  5:42                                                           ` Wei Yongjun
  0 siblings, 0 replies; 484+ messages in thread
From: Wei Yongjun @ 2008-09-03  5:42 UTC (permalink / raw)
  To: dccp

Gerrit Renker wrote:
> | > This patch provides the post-processing of feature negotiation state, after
> | > the negotiation has completed.
>
> <snip>
> | >  
> | > +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
> | > +{
> | > +	struct dccp_sock *dp = dccp_sk(sk);
> | > +	struct dccp_feat_entry *cur, *next;
> | > +	int idx;
> | > +	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
> | > +		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
> | > +	};
> | > +
> | > +	list_for_each_entry(cur, fn_list, node) {
> | > +
> | > +		idx = dccp_feat_index(cur->feat_num);
> | > +		if (idx < 0) {
> | > +			DCCP_BUG("Unknown feature %u", cur->feat_num);
> | > +			goto activation_failed;
> | >   
> | 
> | idx < 0 is possible, if you goto activation_failed, the connection from
> | endpoint which want to change feature we unkonwn, the connection will be
> | always fail by reset. So I think it should just continue process the next
> | feature(s).
> | -----------------------------------
> | if (idx < 0)
> | continue;
> | -----------------------------------
> | 
> | idx < 0 is happended when we recv a change option with unknown feature type.
> | 
> | 
> No, since an unknown feature at this stage would most definitively be a bug.
>
> The validity checking happens earlier:
>  * for NN values every valid value is accepted as per RFC -
>    this is ensured via dccp_feat_is_valid_nn_val();
>  * for SP values at least the confirmed value must be valid -
>    - this is checked in confirm_recv(),
>    - setsockopt is protected against registering invalid feature values,
>    - for CCIDs, additional a check for availability is made before
>      entering negotiation.
>
> These conditions (should) ensure that the above condition is never
> triggered, the test is like an assert() clause.
>   

This special case it is not as you said. The packet seq as following:

Endpoint A                    Endpoing B
REQUEST        --------->
(CHANGE L/unknow feature)
               <---------     RESPONSE
                              (CONFIRM R/empty unknow feature)
ACK            ---------->
                              call dccp_feat_activate_values()
                              -->print DCCP_BUG("Unknown feature %u", cur->feat_num);


After Endpoint B send REPONSE with empty CONFIRM R option, the unknow
feature is *still remain* in the feature list. dccp_feat_insert_opts() 
never clean up
those features. So here we can get idx < 0. Features with is not needed 
is clean up
after active the feat value in dccp_feat_activate_values().

int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
{
    ...
    list_for_each_entry_safe(cur, next, fn_list, node)
        if (!cur->needs_confirm)
            dccp_feat_list_pop(cur);
    ...
}
 





^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-03  6:06                       ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-03  6:06 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 3 Sep 2008 06:24:50 +0200

> Dave what would you like to do?

Why don't you put together a tree with just the changes that have
gone through review and for which you have processed the feedback?

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-03  6:06                       ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-03  6:06 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 3 Sep 2008 06:24:50 +0200

> Dave what would you like to do?

Why don't you put together a tree with just the changes that have
gone through review and for which you have processed the feedback?

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-03  8:18                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  8:18 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| Why don't you put together a tree with just the changes that have
| gone through review and for which you have processed the feedback?
| --
I have a tree for the comments addressed so far. Below is a summary of
the things that have been addressed, when and in which manner.

At the end of the email is an interdiff, relative to the one sent on
Saturday, to reflect the changes that have been newly made to the set.

Urls are
	git://eden-feed.erg.abdn.ac.uk/dccp_exp	[subtree `dccp']
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=shortlog;h=dccp

I will respond to Wei's comments after work.

------------------------------------ S u m m a r y ---------------------------

v3 [PATCH 1/1] dccp: Process incoming Change feature-negotiation options
 * fixed concern expressed by Wei to use an empty Confirm instead of a Reset in response to an invalid Change R
 * I am beginning to question whether this is really the right thing to do, may retract this change since it
   requires the host to send an invalid packet type. Anyway it is in the diff below and on
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=63036a38adc389ea49f84dc12f07fbc27be218e5

[PATCH 03/37] dccp: List management for new feature negotiation
 * addressed feedback by Arnaldo, using list_for_each_entry now
 * this was already addressed in the inter-diff from Saturday
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=e6340a7529dd5828a43828f6eb69344eff605902

[PATCH 04/37] dccp: Per-socket initialisation of feature negotiation 
 * not addressed the suggestion to use hlist instead of list_head
 * this may be a possible optimisation for later

[PATCH 06/37] dccp: Limit feature negotiation to connection setup phase
 * responded to comment suggesting to reset connection instead of ignoring anytime feature negotiation
 * to me it seems that the current policy of silently ignoring anytime negotiation is sufficient

[PATCH 07/37] dccp: Registration routines for changing feature values 
 * clarified that registration is based on the registered CCIDs
 * fixed problem identified by Wei: it is permissible to have Confirm lists of partially unknown values,
   the only requirement is that the confirmed value is valid
 * the update actually affects 
   http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=4d4a0a149a2bbdc4381dee02251e9acd6d4967a3	


[PATCH 08/37] dccp: Query supported CCIDs
 * clarified how the registration of new CCIDs is done (http://www.mail-archive.com/dccp@vger.kernel.org/msg02613.html)
 * the main point is that for the moment new CCIDs will remain highly experimental, as a new CCID first requires to
   get an RFC accepted and published by the IETF

[PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID                                                            
 * suggestion by Arnaldo to use struct ccid_operations for the dependencies
 * response in separate thread: this makes the code more complex and should be deferred

[PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage 
 * fixed problem pointed out by Arnaldo: changing state only after doing the validity checks
 * already addressed in Saturday's diff
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=952d0535860021c3d5b4b10ca41525c85b3adf69

[PATCH 14/37] dccp: Tidy up setsockopt calls
 * addressed Arnaldo's comment that the switch statement could be simplified
 * addressed Eugene's comment regarding the typecast of optlen
 * already in Saturday's diff
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=ee09a66c65c9eccc181be2aef6ea6af63063869b

[PATCH 15/37] dccp: Set per-connection CCIDs via socket options
 * addressed Arnaldo's comment regarding the maximum option length
 * further generalised it when discussing the maximum length of (Confirm) options
 * in Saturday's diff and below
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=eec7ba87785539c7840baadd0203c0a848fb70f2 

[PATCH 16/37] dccp: API to query the current TX/RX CCID 
 * addressed Arnaldo's comment to simplify ccid_get_current_id into separate ccid_get_current_{rx,tx}_ccid
 * already in Saturday's diff
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=8107a65e721bd36d97fc702796fa490884215b36

[PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
 * responded to Wei's concerns regarding that the length check may be invalid (it is not)
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=e8fa8c43e8741aec75e6a646885d0ab1009776b4


====> Here is the interdiff reflecting yesterday's changes, relative to Saturday <====

		 4 files changed, 10 insertions(+), 12 deletions(-)

--- b/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1083,13 +1083,10 @@
 
 	/*
 	 *	Negotiation of NN features: Change R is invalid, so there is no
-	 *	simultaneous negotiation; hence we do not consult the list.
+	 *	simultaneous negotiation; hence we do not look up in the list.
 	 */
 	if (type == FEAT_NN) {
-		if (local)
-			goto not_valid_or_not_known;
-
-		if (len > sizeof(fval.nn))
+		if (local || len > sizeof(fval.nn))
 			goto unknown_feature_or_value;
 
 		/* 6.3.2: "The feature remote MUST accept any valid value..." */
@@ -1230,8 +1227,9 @@
 	/*
 	 * Parsing SP Confirms: the first element of @val is the preferred
 	 * SP value which the peer confirms, the remainder depends on @len.
+	 * Note that only the confirmed value need to be a valid SP value.
 	 */
-	if (!dccp_feat_sp_list_ok(feat, val, len))
+	if (!dccp_feat_is_valid_sp_val(feat, val))
 		goto confirmation_failed;
 
 	if (len == 1) {		/* peer didn't supply a preference list */
--- b/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -170,6 +170,8 @@
 	DCCPO_MIN_TX_CCID_SPECIFIC = 192,	/* from receiver to sender */
 	DCCPO_MAX_TX_CCID_SPECIFIC = 255,
 };
+/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 
 /* DCCP CCIDS */
 enum {
@@ -228,10 +230,6 @@
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
-/* maximum size of a single TLV-encoded option (sans type/len bytes) */
-#define DCCP_SINGLE_OPT_MAXLEN         253
-/* maximum number of CCID preferences that can be registered at one time */
-#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
 
--- b/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -15,13 +15,15 @@
 #include "dccp.h"
 
 /*
- * Known limits of feature values.
+ * Known limit values
  */
 /* Ack Ratio takes 2-byte integer values (11.3) */
 #define DCCPF_ACK_RATIO_MAX	0xFFFF
 /* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
 #define DCCPF_SEQ_WMIN		32
 #define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+/* Maximum number of SP values that fit in a single (Confirm) option */
+#define DCCP_FEAT_MAX_SP_VALS	(DCCP_SINGLE_OPT_MAXLEN - 2)
 
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
--- b/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -475,7 +475,7 @@
 	u8 *val;
 	int rc = 0;
 
-	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
+	if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
 		return -EINVAL;
 
 	val = kmalloc(optlen, GFP_KERNEL);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-03  8:18                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-03  8:18 UTC (permalink / raw)
  To: dccp

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1252", Size: 7577 bytes --]

| Why don't you put together a tree with just the changes that have
| gone through review and for which you have processed the feedback?
| --
I have a tree for the comments addressed so far. Below is a summary of
the things that have been addressed, when and in which manner.

At the end of the email is an interdiff, relative to the one sent on
Saturday, to reflect the changes that have been newly made to the set.

Urls are
	git://eden-feed.erg.abdn.ac.uk/dccp_exp	[subtree `dccp']
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=shortlog;hÜcp

I will respond to Wei's comments after work.

------------------------------------ S u m m a r y ---------------------------

v3 [PATCH 1/1] dccp: Process incoming Change feature-negotiation options
 * fixed concern expressed by Wei to use an empty Confirm instead of a Reset in response to an invalid Change R
 * I am beginning to question whether this is really the right thing to do, may retract this change since it
   requires the host to send an invalid packet type. Anyway it is in the diff below and on
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hc036a38adc389ea49f84dc12f07fbc27be218e5

[PATCH 03/37] dccp: List management for new feature negotiation
 * addressed feedback by Arnaldo, using list_for_each_entry now
 * this was already addressed in the inter-diff from Saturday
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hæ340a7529dd5828a43828f6eb69344eff605902

[PATCH 04/37] dccp: Per-socket initialisation of feature negotiation 
 * not addressed the suggestion to use hlist instead of list_head
 * this may be a possible optimisation for later

[PATCH 06/37] dccp: Limit feature negotiation to connection setup phase
 * responded to comment suggesting to reset connection instead of ignoring anytime feature negotiation
 * to me it seems that the current policy of silently ignoring anytime negotiation is sufficient

[PATCH 07/37] dccp: Registration routines for changing feature values 
 * clarified that registration is based on the registered CCIDs
 * fixed problem identified by Wei: it is permissible to have Confirm lists of partially unknown values,
   the only requirement is that the confirmed value is valid
 * the update actually affects 
   http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hM4a0a149a2bbdc4381dee02251e9acd6d4967a3	


[PATCH 08/37] dccp: Query supported CCIDs
 * clarified how the registration of new CCIDs is done (http://www.mail-archive.com/dccp@vger.kernel.org/msg02613.html)
 * the main point is that for the moment new CCIDs will remain highly experimental, as a new CCID first requires to
   get an RFC accepted and published by the IETF

[PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID                                                            
 * suggestion by Arnaldo to use struct ccid_operations for the dependencies
 * response in separate thread: this makes the code more complex and should be deferred

[PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage 
 * fixed problem pointed out by Arnaldo: changing state only after doing the validity checks
 * already addressed in Saturday's diff
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;h•2d0535860021c3d5b4b10ca41525c85b3adf69

[PATCH 14/37] dccp: Tidy up setsockopt calls
 * addressed Arnaldo's comment that the switch statement could be simplified
 * addressed Eugene's comment regarding the typecast of optlen
 * already in Saturday's diff
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hî09a66c65c9eccc181be2aef6ea6af63063869b

[PATCH 15/37] dccp: Set per-connection CCIDs via socket options
 * addressed Arnaldo's comment regarding the maximum option length
 * further generalised it when discussing the maximum length of (Confirm) options
 * in Saturday's diff and below
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hîc7ba87785539c7840baadd0203c0a848fb70f2 

[PATCH 16/37] dccp: API to query the current TX/RX CCID 
 * addressed Arnaldo's comment to simplify ccid_get_current_id into separate ccid_get_current_{rx,tx}_ccid
 * already in Saturday's diff
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;h07a65e721bd36d97fc702796fa490884215b36

[PATCH 19/37] dccp: Header option insertion routine for feature-negotiation
 * responded to Wei's concerns regarding that the length check may be invalid (it is not)
 * http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hèfa8c43e8741aec75e6a646885d0ab1009776b4


==> Here is the interdiff reflecting yesterday's changes, relative to Saturday <==

		 4 files changed, 10 insertions(+), 12 deletions(-)

--- b/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1083,13 +1083,10 @@
 
 	/*
 	 *	Negotiation of NN features: Change R is invalid, so there is no
-	 *	simultaneous negotiation; hence we do not consult the list.
+	 *	simultaneous negotiation; hence we do not look up in the list.
 	 */
 	if (type = FEAT_NN) {
-		if (local)
-			goto not_valid_or_not_known;
-
-		if (len > sizeof(fval.nn))
+		if (local || len > sizeof(fval.nn))
 			goto unknown_feature_or_value;
 
 		/* 6.3.2: "The feature remote MUST accept any valid value..." */
@@ -1230,8 +1227,9 @@
 	/*
 	 * Parsing SP Confirms: the first element of @val is the preferred
 	 * SP value which the peer confirms, the remainder depends on @len.
+	 * Note that only the confirmed value need to be a valid SP value.
 	 */
-	if (!dccp_feat_sp_list_ok(feat, val, len))
+	if (!dccp_feat_is_valid_sp_val(feat, val))
 		goto confirmation_failed;
 
 	if (len = 1) {		/* peer didn't supply a preference list */
--- b/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -170,6 +170,8 @@
 	DCCPO_MIN_TX_CCID_SPECIFIC = 192,	/* from receiver to sender */
 	DCCPO_MAX_TX_CCID_SPECIFIC = 255,
 };
+/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 
 /* DCCP CCIDS */
 enum {
@@ -228,10 +230,6 @@
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
-/* maximum size of a single TLV-encoded option (sans type/len bytes) */
-#define DCCP_SINGLE_OPT_MAXLEN         253
-/* maximum number of CCID preferences that can be registered at one time */
-#define DCCP_CCID_LIST_MAX_LEN         (DCCP_SINGLE_OPT_MAXLEN - 2)
 /* maximum number of services provided on the same listening port */
 #define DCCP_SERVICE_LIST_MAX_LEN      32
 
--- b/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -15,13 +15,15 @@
 #include "dccp.h"
 
 /*
- * Known limits of feature values.
+ * Known limit values
  */
 /* Ack Ratio takes 2-byte integer values (11.3) */
 #define DCCPF_ACK_RATIO_MAX	0xFFFF
 /* Wmin2 and Wmax=2^46-1 from 7.5.2 */
 #define DCCPF_SEQ_WMIN		32
 #define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+/* Maximum number of SP values that fit in a single (Confirm) option */
+#define DCCP_FEAT_MAX_SP_VALS	(DCCP_SINGLE_OPT_MAXLEN - 2)
 
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
--- b/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -475,7 +475,7 @@
 	u8 *val;
 	int rc = 0;
 
-	if (optlen < 1 || optlen > DCCP_CCID_LIST_MAX_LEN)
+	if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
 		return -EINVAL;
 
 	val = kmalloc(optlen, GFP_KERNEL);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID
  2008-08-28 17:44                     ` Gerrit Renker
@ 2008-09-04  0:59                           ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-04  0:59 UTC (permalink / raw)
  To: Gerrit Renker, dccp, netdev

Em Wed, Sep 03, 2008 at 06:51:52AM +0200, Gerrit Renker escreveu:
> | > This provides a missing link in the code chain, as several features implicitly
> | > depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
> | > feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
> | > 
> <snip>
> | 
> | Doesn't this belongs into struct ccid_operations? Why has the core feature
> | negotiation have knowledge of any specific CCID? When people want to
> | merge CCID 4, 5, etc will we need to change net/dccp/feat.c?
> | 
> | I think that this needs thus to go to struct ccid_operations, and then the feature
> | negotiation code can just use use the ccid number to access:
> | 
> | struct ccid_operations *ccids[CCID_MAX]
> | 
> | ccids[ccid_number]->deps

> In principle I agree with you, what I am asking for is to defer this code
> optimisation until later.

Fair enough.

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 09/37] dccp: Resolve dependencies of features on choice
@ 2008-09-04  0:59                           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-04  0:59 UTC (permalink / raw)
  To: dccp

Em Wed, Sep 03, 2008 at 06:51:52AM +0200, Gerrit Renker escreveu:
> | > This provides a missing link in the code chain, as several features implicitly
> | > depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
> | > feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
> | > 
> <snip>
> | 
> | Doesn't this belongs into struct ccid_operations? Why has the core feature
> | negotiation have knowledge of any specific CCID? When people want to
> | merge CCID 4, 5, etc will we need to change net/dccp/feat.c?
> | 
> | I think that this needs thus to go to struct ccid_operations, and then the feature
> | negotiation code can just use use the ccid number to access:
> | 
> | struct ccid_operations *ccids[CCID_MAX]
> | 
> | ccids[ccid_number]->deps

> In principle I agree with you, what I am asking for is to defer this code
> optimisation until later.

Fair enough.

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
  2008-08-28 17:45                                                     ` Gerrit Renker
@ 2008-09-04  5:12                                                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-04  5:12 UTC (permalink / raw)
  To: Wei Yongjun; +Cc: dccp, netdev

>> These conditions (should) ensure that the above condition is never
>> triggered, the test is like an assert() clause.
>>   
>
> This special case it is not as you said. The packet seq as following:
>
> Endpoint A                    Endpoing B
> REQUEST        --------->
> (CHANGE L/unknow feature)
>               <---------     RESPONSE
>                              (CONFIRM R/empty unknow feature)
> ACK            ---------->
>                              call dccp_feat_activate_values()
>                              -->print DCCP_BUG("Unknown feature %u", cur->feat_num);
>
>
> After Endpoint B send REPONSE with empty CONFIRM R option, the unknow
> feature is *still remain* in the feature list. dccp_feat_insert_opts()  
> never clean up
> those features. So here we can get idx < 0. Features with is not needed  
> is clean up
> after active the feat value in dccp_feat_activate_values().
>
> int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
> {
>    ...
>    list_for_each_entry_safe(cur, next, fn_list, node)
>        if (!cur->needs_confirm)
>            dccp_feat_list_pop(cur);
>    ...
> }
>
You are right, this is an oversight.

In an earlier revision the code actually removed Confirm options
immediately, or as soon as the request socket was cloned. Here is an
early RCS revision of the patch for dccp_feat_insert_opts():

+		if (pos->state == FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+		else if (pos->needs_confirm && dreq == NULL)
+			dccp_feat_list_pop(pos);

But then there was the problem that if Confirm options are not retransmitted
for robustness, feature negotiation fails if packets are lost (e.g. the Ack
completing the initial handshake). This was first reported by Leandro, full story on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/why_retransmit_confirms
(That fix is not part of this patch set, it comes in the second part.)

But after the above "pop" had been removed, the assumption that only "clean"
options are in the feature list is no longer valid.

Modifying the above to work only for empty Confirm's would take away the
advantage of retransmission. The pop() would also not work, while your earlier
suggestion of skipping over empty Confirms does:

+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
...	
+       list_for_each_entry(cur, fn_list, node) {
+               if (cur->empty_confirm)
+                       continue;
...

This is because Confirm options are retransmitted even after activation.

Many thanks indeed.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 25/37] dccp: Feature activation handlers
@ 2008-09-04  5:12                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-04  5:12 UTC (permalink / raw)
  To: dccp

>> These conditions (should) ensure that the above condition is never
>> triggered, the test is like an assert() clause.
>>   
>
> This special case it is not as you said. The packet seq as following:
>
> Endpoint A                    Endpoing B
> REQUEST        --------->
> (CHANGE L/unknow feature)
>               <---------     RESPONSE
>                              (CONFIRM R/empty unknow feature)
> ACK            ---------->
>                              call dccp_feat_activate_values()
>                              -->print DCCP_BUG("Unknown feature %u", cur->feat_num);
>
>
> After Endpoint B send REPONSE with empty CONFIRM R option, the unknow
> feature is *still remain* in the feature list. dccp_feat_insert_opts()  
> never clean up
> those features. So here we can get idx < 0. Features with is not needed  
> is clean up
> after active the feat value in dccp_feat_activate_values().
>
> int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
> {
>    ...
>    list_for_each_entry_safe(cur, next, fn_list, node)
>        if (!cur->needs_confirm)
>            dccp_feat_list_pop(cur);
>    ...
> }
>
You are right, this is an oversight.

In an earlier revision the code actually removed Confirm options
immediately, or as soon as the request socket was cloned. Here is an
early RCS revision of the patch for dccp_feat_insert_opts():

+		if (pos->state = FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+		else if (pos->needs_confirm && dreq = NULL)
+			dccp_feat_list_pop(pos);

But then there was the problem that if Confirm options are not retransmitted
for robustness, feature negotiation fails if packets are lost (e.g. the Ack
completing the initial handshake). This was first reported by Leandro, full story on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/why_retransmit_confirms
(That fix is not part of this patch set, it comes in the second part.)

But after the above "pop" had been removed, the assumption that only "clean"
options are in the feature list is no longer valid.

Modifying the above to work only for empty Confirm's would take away the
advantage of retransmission. The pop() would also not work, while your earlier
suggestion of skipping over empty Confirms does:

+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
...	
+       list_for_each_entry(cur, fn_list, node) {
+               if (cur->empty_confirm)
+                       continue;
...

This is because Confirm options are retransmitted even after activation.

Many thanks indeed.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-04  6:15                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-04  6:15 UTC (permalink / raw)
  To: David Miller, acme, dccp, netdev

This is an update with regard to Wei's comments. I have re-synched 

	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=shortlog;h=dccp

Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
CCID 2/3/4. They could still negotiate and settle for a common CCID.

Change-Log:
-----------
	1. relaxed the requirement of checking each and every SP value in change_recv
	   to checking only the value that will actually be used/activated;
	2. fixed an error in yesterdays's update:
	   dccp_feat_is_valid_sp_val() takes an u8 value, not an u8 *pointer;
	3. added Wei's suggestion to skip over empty Confirms when activating the
	   negotiated features in dccp_feat_activate_values().

--------------------------------------------------------------------------------------------	   
List of patches that were updated:
----------------------------------
v3 [PATCH 1/1] dccp: Process incoming Change feature-negotiation options 
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=5a146b97d5e93db2df075c0d820f492bb996d0e3

[PATCH 25/37] dccp: Feature activation handlers
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=c926c6aed3e444e8c88a768f063b2de8fd6ae760

--------------------------------------------------------------------------------------------	   
Interdiff of the submitted changeset relative to yesterday's state:
--------------------------------------------------------------------------------------------
 		1 file changed, 11 insertions(+), 3 deletions(-)
--- b/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1102,8 +1102,6 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 
 	 */
 	entry = dccp_feat_list_lookup(fn, feat, local);
 	if (entry == NULL) {
-		if (!dccp_feat_sp_list_ok(feat, val, len))
-			goto unknown_feature_or_value;
 		/*
 		 * No particular preferences have been registered. We deal with
 		 * this situation by assuming that all valid values are equally
@@ -1121,6 +1119,9 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 
 			defval = dccp_feat_default_value(feat);
 			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
 				fval.sp.vec[0] = defval;
+		} else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
+			kfree(fval.sp.vec);
+			goto unknown_feature_or_value;
 		}
 
 		/* Treat unsupported CCIDs like invalid values */
@@ -1229,7 +1230,7 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 
 	 * SP value which the peer confirms, the remainder depends on @len.
 	 * Note that only the confirmed value need to be a valid SP value.
 	 */
-	if (!dccp_feat_is_valid_sp_val(feat, val))
+	if (!dccp_feat_is_valid_sp_val(feat, *val))
 		goto confirmation_failed;
 
 	if (len == 1) {		/* peer didn't supply a preference list */
@@ -1471,6 +1472,13 @@ int dccp_feat_activate_values(struct sock *sk, struct
 	};
 
 	list_for_each_entry(cur, fn_list, node) {
+		/*
+		 * An empty Confirm means that either an unknown feature type
+		 * or an invalid value was present. In the first case there is
+		 * nothing to activate, in the other the default value is used.
+		 */
+		if (cur->empty_confirm)
+			continue;
 
 		idx = dccp_feat_index(cur->feat_num);
 		if (idx < 0) {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-04  6:15                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-04  6:15 UTC (permalink / raw)
  To: dccp

This is an update with regard to Wei's comments. I have re-synched 

	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=shortlog;hÜcp

Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
CCID 2/3/4. They could still negotiate and settle for a common CCID.

Change-Log:
-----------
	1. relaxed the requirement of checking each and every SP value in change_recv
	   to checking only the value that will actually be used/activated;
	2. fixed an error in yesterdays's update:
	   dccp_feat_is_valid_sp_val() takes an u8 value, not an u8 *pointer;
	3. added Wei's suggestion to skip over empty Confirms when activating the
	   negotiated features in dccp_feat_activate_values().

--------------------------------------------------------------------------------------------	   
List of patches that were updated:
----------------------------------
v3 [PATCH 1/1] dccp: Process incoming Change feature-negotiation options 
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hZ146b97d5e93db2df075c0d820f492bb996d0e3

[PATCH 25/37] dccp: Feature activation handlers
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hÉ26c6aed3e444e8c88a768f063b2de8fd6ae760

--------------------------------------------------------------------------------------------	   
Interdiff of the submitted changeset relative to yesterday's state:
--------------------------------------------------------------------------------------------
 		1 file changed, 11 insertions(+), 3 deletions(-)
--- b/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1102,8 +1102,6 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 
 	 */
 	entry = dccp_feat_list_lookup(fn, feat, local);
 	if (entry = NULL) {
-		if (!dccp_feat_sp_list_ok(feat, val, len))
-			goto unknown_feature_or_value;
 		/*
 		 * No particular preferences have been registered. We deal with
 		 * this situation by assuming that all valid values are equally
@@ -1121,6 +1119,9 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 
 			defval = dccp_feat_default_value(feat);
 			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
 				fval.sp.vec[0] = defval;
+		} else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
+			kfree(fval.sp.vec);
+			goto unknown_feature_or_value;
 		}
 
 		/* Treat unsupported CCIDs like invalid values */
@@ -1229,7 +1230,7 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 
 	 * SP value which the peer confirms, the remainder depends on @len.
 	 * Note that only the confirmed value need to be a valid SP value.
 	 */
-	if (!dccp_feat_is_valid_sp_val(feat, val))
+	if (!dccp_feat_is_valid_sp_val(feat, *val))
 		goto confirmation_failed;
 
 	if (len = 1) {		/* peer didn't supply a preference list */
@@ -1471,6 +1472,13 @@ int dccp_feat_activate_values(struct sock *sk, struct
 	};
 
 	list_for_each_entry(cur, fn_list, node) {
+		/*
+		 * An empty Confirm means that either an unknown feature type
+		 * or an invalid value was present. In the first case there is
+		 * nothing to activate, in the other the default value is used.
+		 */
+		if (cur->empty_confirm)
+			continue;
 
 		idx = dccp_feat_index(cur->feat_num);
 		if (idx < 0) {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-09  0:32                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-09  0:32 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu, 4 Sep 2008 08:15:11 +0200

> This is an update with regard to Wei's comments. I have re-synched 
> 
> 	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
> 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=shortlog;h=dccp
> 
> Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
> CCID 2/3/4. They could still negotiate and settle for a common CCID.

I pulled and resolved all of the conflicts, but this build warning I'm
now getting from ccid3.h has got to go:

/*
 * The t_delta parameter (RFC 3448, 4.6): delays of less than %USEC_PER_MSEC are
 * rounded down to 0, since sk_reset_timer() here uses millisecond granularity.
 * Hence we can use a constant t_delta = %USEC_PER_MSEC when HZ >= 500. A coarse
 * resolution of HZ < 500 means that the error is below one timer tick (t_gran)
 * when using the constant t_delta  =  t_gran / 2  =  %USEC_PER_SEC / (2 * HZ).
 */
#if (HZ >= 500)
# define TFRC_T_DELTA		   USEC_PER_MSEC
#else
# define TFRC_T_DELTA		   (USEC_PER_SEC / (2 * HZ))
#warning Coarse CONFIG_HZ resolution -- higher value recommended for TFRC.
#endif

Don't warn about crap like this, instead convert the code over to hrtimers.

This kernel being built, even with HZ=100, can do nanosecond timers on
my systems, but that's only if you would make proper use of them.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-09  0:32                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-09  0:32 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu, 4 Sep 2008 08:15:11 +0200

> This is an update with regard to Wei's comments. I have re-synched 
> 
> 	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
> 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=shortlog;hÜcp
> 
> Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
> CCID 2/3/4. They could still negotiate and settle for a common CCID.

I pulled and resolved all of the conflicts, but this build warning I'm
now getting from ccid3.h has got to go:

/*
 * The t_delta parameter (RFC 3448, 4.6): delays of less than %USEC_PER_MSEC are
 * rounded down to 0, since sk_reset_timer() here uses millisecond granularity.
 * Hence we can use a constant t_delta = %USEC_PER_MSEC when HZ >= 500. A coarse
 * resolution of HZ < 500 means that the error is below one timer tick (t_gran)
 * when using the constant t_delta  =  t_gran / 2  =  %USEC_PER_SEC / (2 * HZ).
 */
#if (HZ >= 500)
# define TFRC_T_DELTA		   USEC_PER_MSEC
#else
# define TFRC_T_DELTA		   (USEC_PER_SEC / (2 * HZ))
#warning Coarse CONFIG_HZ resolution -- higher value recommended for TFRC.
#endif

Don't warn about crap like this, instead convert the code over to hrtimers.

This kernel being built, even with HZ\x100, can do nanosecond timers on
my systems, but that's only if you would make proper use of them.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-09  8:09                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-09  8:09 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| > This is an update with regard to Wei's comments. I have re-synched 
| > 
| > 	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
| > 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=shortlog;h=dccp
| > 
| > Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
| > CCID 2/3/4. They could still negotiate and settle for a common CCID.
| 
Sorry the above includes the whole dccp test tree, over and above the
feature negotiation. We have been waiting for Arnaldo and there was a
phase where people sent comments about this patch set, so I had not
prepared a second net-next-2.6 pull request for this patch set yet.

If you want to revert this, I will prepare a net-next-2.6 clone with
just the revised 37 patches from this set.

Otherwise some parts (as below) need to be modified.


| #if (HZ >= 500)
| # define TFRC_T_DELTA		   USEC_PER_MSEC
| #else
| # define TFRC_T_DELTA		   (USEC_PER_SEC / (2 * HZ))
| #warning Coarse CONFIG_HZ resolution -- higher value recommended for TFRC.
| #endif
| 
| Don't warn about crap like this, instead convert the code over to hrtimers.
| 
| This kernel being built, even with HZ=100, can do nanosecond timers on
| my systems, but that's only if you would make proper use of them.
| 
The present sk_timer implementation uses the algorithm from RFC 3448. I
did not want to blindly port it to hrtimer since so far the following
difficulties were in the way:

 * when using the algorithm from RFC 3448, 4.6 directly with hrtimers,
   a large burst of activity will result, especially on fast links;

 * I have doubts whether it will help: each time the precision is improved,
   more frantic high-frequency noise results in CCID-3:
   - at some time socket timestamps were suggested for better RTT measurement,
     it proved better to reduce the precision to taking timestamps within the
     DCCP module (smoother response and also includes slow receiver);
   - even with that, on Gigabit Ethernet zero-RTT samples still occur;
   - one of the above patches updates CCID-3 to track the sending rate X_recv 
     with higher frequency. There seems to be not much benefit, when comparing
     the sender plots, the amount of high-frequency noise in X_recv has
     increased after increasing the frequency of updating;

 * some people have suggested to use a timerless algorithm instead which 
   would just control the number of packets per time. This would require
   rewriting some of the infrastructure (with benefits), it would use
   hrtimers for measuring the time intervals. 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-09  8:09                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-09  8:09 UTC (permalink / raw)
  To: dccp

| > This is an update with regard to Wei's comments. I have re-synched 
| > 
| > 	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
| > 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=shortlog;hÜcp
| > 
| > Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
| > CCID 2/3/4. They could still negotiate and settle for a common CCID.
| 
Sorry the above includes the whole dccp test tree, over and above the
feature negotiation. We have been waiting for Arnaldo and there was a
phase where people sent comments about this patch set, so I had not
prepared a second net-next-2.6 pull request for this patch set yet.

If you want to revert this, I will prepare a net-next-2.6 clone with
just the revised 37 patches from this set.

Otherwise some parts (as below) need to be modified.


| #if (HZ >= 500)
| # define TFRC_T_DELTA		   USEC_PER_MSEC
| #else
| # define TFRC_T_DELTA		   (USEC_PER_SEC / (2 * HZ))
| #warning Coarse CONFIG_HZ resolution -- higher value recommended for TFRC.
| #endif
| 
| Don't warn about crap like this, instead convert the code over to hrtimers.
| 
| This kernel being built, even with HZ\x100, can do nanosecond timers on
| my systems, but that's only if you would make proper use of them.
| 
The present sk_timer implementation uses the algorithm from RFC 3448. I
did not want to blindly port it to hrtimer since so far the following
difficulties were in the way:

 * when using the algorithm from RFC 3448, 4.6 directly with hrtimers,
   a large burst of activity will result, especially on fast links;

 * I have doubts whether it will help: each time the precision is improved,
   more frantic high-frequency noise results in CCID-3:
   - at some time socket timestamps were suggested for better RTT measurement,
     it proved better to reduce the precision to taking timestamps within the
     DCCP module (smoother response and also includes slow receiver);
   - even with that, on Gigabit Ethernet zero-RTT samples still occur;
   - one of the above patches updates CCID-3 to track the sending rate X_recv 
     with higher frequency. There seems to be not much benefit, when comparing
     the sender plots, the amount of high-frequency noise in X_recv has
     increased after increasing the frequency of updating;

 * some people have suggested to use a timerless algorithm instead which 
   would just control the number of packets per time. This would require
   rewriting some of the infrastructure (with benefits), it would use
   hrtimers for measuring the time intervals. 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-09  8:57                                 ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-09  8:57 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 9 Sep 2008 10:09:11 +0200

> | > This is an update with regard to Wei's comments. I have re-synched 
> | > 
> | > 	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
> | > 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=shortlog;h=dccp
> | > 
> | > Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
> | > CCID 2/3/4. They could still negotiate and settle for a common CCID.
> | 
> Sorry the above includes the whole dccp test tree, over and above the
> feature negotiation. We have been waiting for Arnaldo and there was a
> phase where people sent comments about this patch set, so I had not
> prepared a second net-next-2.6 pull request for this patch set yet.
> 
> If you want to revert this, I will prepare a net-next-2.6 clone with
> just the revised 37 patches from this set.
> 
> Otherwise some parts (as below) need to be modified.

Just send me whatever fixup patches are needed as another pull request.

I realize your time is limited, but SO IS MINE, and this bogon GIT
tree you asked me to pull from is just one in a long line of time
consuming exercises you've put me through ever since taking over DCCP
maintainence.

And when you crap up net-next-2.6 you effect other people doing
networking work too, not just me and you.  You also effect everyone
trying to test the -next tree since net-next-2.6 gets sucked into
there every day.

You can't seem to get the whole review process right, yet it's the
most important aspect of getting changes into the tree.  It's 1,000
times more important that implementing the code in the first place.

For starters, you don't dump 30 or 40 patches on people's laps for
review.  You give them 5, maybe 10, at a time.  And you submit them
when you write them, so that you don't have to rewrite everything
after the ones that need fixups.

And once you've submitted a large chunk of changes like you did this
time, you've worn out your reviewer pool, and they'll need a long
recovery period before they can devote time to looking at this stuff
again.

> | Don't warn about crap like this, instead convert the code over to hrtimers.
> | 
> | This kernel being built, even with HZ=100, can do nanosecond timers on
> | my systems, but that's only if you would make proper use of them.
> | 
> The present sk_timer implementation uses the algorithm from RFC 3448. I
> did not want to blindly port it to hrtimer since so far the following
> difficulties were in the way:
> 
>  * when using the algorithm from RFC 3448, 4.6 directly with hrtimers,
>    a large burst of activity will result, especially on fast links;
> 
>  * I have doubts whether it will help: each time the precision is improved,
>    more frantic high-frequency noise results in CCID-3:

To me this is just pure bullshit, I'm sorry to say.

A warning gets added that barks at the person compiling this stuff
saying: "YOUR TIMER ISN'T ACCURATE ENOUGH" and now you're telling me
your concerned that hrtimers might give too much accuracy.

Which is it?

Lower limit the hrtimer interval, or make it as course as you damn
well need, anything but this pile of excuses.

HZ=100 is extremely common, and there is no reason to bark at people
about something they can do absolutely nothing about.  Who in the
world is supposed to act upon that warning?

Yet now everyone building the linux -next tree will see it if their HZ
is choosen to be low enough and we'll thus get piles of "what's this?"
queries on all the lists.

Look...

This whole process isn't going smoothly.  You are time limited, and
the place you are short changing, time wise, appears to be the whole
submission and review process.  Yet this should be your highest
priority, far and above implementing even one single line of code.

Now net-next-2.6 is crapped up with an unintentional DCCP pull.  And I
pushed it out, so I can't just revert this junk, other people use
net-next-2.6 as their development base.  So if I rebase it, I screw up
their work.

I totally trusted you, fixed up the merge errors, and figured you
really must have meant to send me all of that stuff.

This is what happens when you try to manage a huge chunk of changes that
needed review, all at once.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-09  8:57                                 ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-09  8:57 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 9 Sep 2008 10:09:11 +0200

> | > This is an update with regard to Wei's comments. I have re-synched 
> | > 
> | > 	git://eden-feed.erg.abdn.ac.uk/dccp_exp		[subtree `dccp']
> | > 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=shortlog;hÜcp
> | > 
> | > Also did some testing with a client that only supports CCID 2/3 talking to a client supporting
> | > CCID 2/3/4. They could still negotiate and settle for a common CCID.
> | 
> Sorry the above includes the whole dccp test tree, over and above the
> feature negotiation. We have been waiting for Arnaldo and there was a
> phase where people sent comments about this patch set, so I had not
> prepared a second net-next-2.6 pull request for this patch set yet.
> 
> If you want to revert this, I will prepare a net-next-2.6 clone with
> just the revised 37 patches from this set.
> 
> Otherwise some parts (as below) need to be modified.

Just send me whatever fixup patches are needed as another pull request.

I realize your time is limited, but SO IS MINE, and this bogon GIT
tree you asked me to pull from is just one in a long line of time
consuming exercises you've put me through ever since taking over DCCP
maintainence.

And when you crap up net-next-2.6 you effect other people doing
networking work too, not just me and you.  You also effect everyone
trying to test the -next tree since net-next-2.6 gets sucked into
there every day.

You can't seem to get the whole review process right, yet it's the
most important aspect of getting changes into the tree.  It's 1,000
times more important that implementing the code in the first place.

For starters, you don't dump 30 or 40 patches on people's laps for
review.  You give them 5, maybe 10, at a time.  And you submit them
when you write them, so that you don't have to rewrite everything
after the ones that need fixups.

And once you've submitted a large chunk of changes like you did this
time, you've worn out your reviewer pool, and they'll need a long
recovery period before they can devote time to looking at this stuff
again.

> | Don't warn about crap like this, instead convert the code over to hrtimers.
> | 
> | This kernel being built, even with HZ\x100, can do nanosecond timers on
> | my systems, but that's only if you would make proper use of them.
> | 
> The present sk_timer implementation uses the algorithm from RFC 3448. I
> did not want to blindly port it to hrtimer since so far the following
> difficulties were in the way:
> 
>  * when using the algorithm from RFC 3448, 4.6 directly with hrtimers,
>    a large burst of activity will result, especially on fast links;
> 
>  * I have doubts whether it will help: each time the precision is improved,
>    more frantic high-frequency noise results in CCID-3:

To me this is just pure bullshit, I'm sorry to say.

A warning gets added that barks at the person compiling this stuff
saying: "YOUR TIMER ISN'T ACCURATE ENOUGH" and now you're telling me
your concerned that hrtimers might give too much accuracy.

Which is it?

Lower limit the hrtimer interval, or make it as course as you damn
well need, anything but this pile of excuses.

HZ\x100 is extremely common, and there is no reason to bark at people
about something they can do absolutely nothing about.  Who in the
world is supposed to act upon that warning?

Yet now everyone building the linux -next tree will see it if their HZ
is choosen to be low enough and we'll thus get piles of "what's this?"
queries on all the lists.

Look...

This whole process isn't going smoothly.  You are time limited, and
the place you are short changing, time wise, appears to be the whole
submission and review process.  Yet this should be your highest
priority, far and above implementing even one single line of code.

Now net-next-2.6 is crapped up with an unintentional DCCP pull.  And I
pushed it out, so I can't just revert this junk, other people use
net-next-2.6 as their development base.  So if I rebase it, I screw up
their work.

I totally trusted you, fixed up the merge errors, and figured you
really must have meant to send me all of that stuff.

This is what happens when you try to manage a huge chunk of changes that
needed review, all at once.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-09 11:59                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-09 11:59 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

Let's keep this clean and simple. There has been a mistake here and it
needs to be fixed. It does not help to argue loudly whose fault it was.

Please consider pulling from

	git://eden-feed.erg.abdn.ac.uk/net-next-2.6	 [subtree `master']
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=summary

where I have reverted the pull and compile-tested the result. 

We can talk about the rest once you have cooled down.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-09 11:59                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-09 11:59 UTC (permalink / raw)
  To: dccp

Let's keep this clean and simple. There has been a mistake here and it
needs to be fixed. It does not help to argue loudly whose fault it was.

Please consider pulling from

	git://eden-feed.erg.abdn.ac.uk/net-next-2.6	 [subtree `master']
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=summary

where I have reverted the pull and compile-tested the result. 

We can talk about the rest once you have cooled down.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-09 12:15                                     ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-09 12:15 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 9 Sep 2008 13:59:48 +0200

> Let's keep this clean and simple. There has been a mistake here and it
> needs to be fixed. It does not help to argue loudly whose fault it was.
> 
> Please consider pulling from
> 
> 	git://eden-feed.erg.abdn.ac.uk/net-next-2.6	 [subtree `master']
> 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=summary
> 
> where I have reverted the pull and compile-tested the result. 

I hate to have a turd like this in the history, but fine I pulled this :-/

I may have to rebase net-next-2.6 after all, this is revoltingly ugly...

This is exactly what I didn't want Gerrit, a royally screwed up GIT
history because of the mistake.  It's WORSE now with the revert.
Can't you see that?  That's why I asked for fixup changesets, rather
than a revert.

I would have rather you sent me a small set of fixup patches that
cured whatever problems were in those changes.  That would have shown
the development history.

Now we're just going to have crap.  A large set of changes going in, then
one huge revert, and nobody will ever get to see exactly what happened
in between.

I've had enough.

I'd like to get the DCCP changes through someone else, please.
Someone willing to learn to use GIT properly.  Someone who understands
how important it is to keep the GIT history clean and not put a lot of
noise into the tree.  Someone who has the time to do this right and I
can trust.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-09 12:15                                     ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-09 12:15 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 9 Sep 2008 13:59:48 +0200

> Let's keep this clean and simple. There has been a mistake here and it
> needs to be fixed. It does not help to argue loudly whose fault it was.
> 
> Please consider pulling from
> 
> 	git://eden-feed.erg.abdn.ac.uk/net-next-2.6	 [subtree `master']
> 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=summary
> 
> where I have reverted the pull and compile-tested the result. 

I hate to have a turd like this in the history, but fine I pulled this :-/

I may have to rebase net-next-2.6 after all, this is revoltingly ugly...

This is exactly what I didn't want Gerrit, a royally screwed up GIT
history because of the mistake.  It's WORSE now with the revert.
Can't you see that?  That's why I asked for fixup changesets, rather
than a revert.

I would have rather you sent me a small set of fixup patches that
cured whatever problems were in those changes.  That would have shown
the development history.

Now we're just going to have crap.  A large set of changes going in, then
one huge revert, and nobody will ever get to see exactly what happened
in between.

I've had enough.

I'd like to get the DCCP changes through someone else, please.
Someone willing to learn to use GIT properly.  Someone who understands
how important it is to keep the GIT history clean and not put a lot of
noise into the tree.  Someone who has the time to do this right and I
can trust.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-10  5:01                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-10  5:01 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| > Please consider pulling from
| > 
| > 	git://eden-feed.erg.abdn.ac.uk/net-next-2.6	 [subtree `master']
| > 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=summary
| > 
| > where I have reverted the pull and compile-tested the result. 
| 
| I hate to have a turd like this in the history, but fine I pulled this :-/
| 
| I may have to rebase net-next-2.6 after all, this is revoltingly ugly...
| 
| This is exactly what I didn't want Gerrit, a royally screwed up GIT
| history because of the mistake.  It's WORSE now with the revert.
| Can't you see that?  That's why I asked for fixup changesets, rather
| than a revert.
| 
| I would have rather you sent me a small set of fixup patches that
| cured whatever problems were in those changes.  That would have shown
| the development history.
| 
| Now we're just going to have crap.  A large set of changes going in, then
| one huge revert, and nobody will ever get to see exactly what happened
| in between.
| 
| I've had enough.
| 
| I'd like to get the DCCP changes through someone else, please.
| Someone willing to learn to use GIT properly.  Someone who understands
| how important it is to keep the GIT history clean and not put a lot of
| noise into the tree.  Someone who has the time to do this right and I
| can trust.
| 
I had hoped that you would regain your senses but it does not seem so.

Not only are you lacking the courage to admit that it was your own fault
to pull a tree no one had asked you to pull, now you are trying to make 
me look foolish to cover your own mistake. 

Remember, it was you who asked for another review period, neither I nor
Arnaldo, nor anyone else had asked you to pull again.

It further did not even occur to you to check the provided gitweb link, nor
did you recognise that you had pulled about 100 instead of 37 patches. And
you seem not to have looked at the diffstats either - what has a change in
tcp_input.c got to do with a DCCP-only patch set?

Not to mention the conflicts which you silently fixed instead of looking at
their cause.

You don't check the results of your own work and now you are trying to 
lecture others about maintainership? Look at yourself.

And to top this up now you are even asking me for "fixup patches" to fix the
about 60 patches that were accidentally sucked in, only a day after giving
us a lecture on the importance of review. What you are asking for here is to
wave through 60 patches without giving people a chance at all to review them.

I am not going to send patches to fix/cover this up. Either we want people to
review patches fairly or we don't.

What you are saying here has little authority. It is just foolish vanity.
I am really sorry for you and hope that you come back to your senses soon.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-10  5:01                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-10  5:01 UTC (permalink / raw)
  To: dccp

| > Please consider pulling from
| > 
| > 	git://eden-feed.erg.abdn.ac.uk/net-next-2.6	 [subtree `master']
| > 	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=summary
| > 
| > where I have reverted the pull and compile-tested the result. 
| 
| I hate to have a turd like this in the history, but fine I pulled this :-/
| 
| I may have to rebase net-next-2.6 after all, this is revoltingly ugly...
| 
| This is exactly what I didn't want Gerrit, a royally screwed up GIT
| history because of the mistake.  It's WORSE now with the revert.
| Can't you see that?  That's why I asked for fixup changesets, rather
| than a revert.
| 
| I would have rather you sent me a small set of fixup patches that
| cured whatever problems were in those changes.  That would have shown
| the development history.
| 
| Now we're just going to have crap.  A large set of changes going in, then
| one huge revert, and nobody will ever get to see exactly what happened
| in between.
| 
| I've had enough.
| 
| I'd like to get the DCCP changes through someone else, please.
| Someone willing to learn to use GIT properly.  Someone who understands
| how important it is to keep the GIT history clean and not put a lot of
| noise into the tree.  Someone who has the time to do this right and I
| can trust.
| 
I had hoped that you would regain your senses but it does not seem so.

Not only are you lacking the courage to admit that it was your own fault
to pull a tree no one had asked you to pull, now you are trying to make 
me look foolish to cover your own mistake. 

Remember, it was you who asked for another review period, neither I nor
Arnaldo, nor anyone else had asked you to pull again.

It further did not even occur to you to check the provided gitweb link, nor
did you recognise that you had pulled about 100 instead of 37 patches. And
you seem not to have looked at the diffstats either - what has a change in
tcp_input.c got to do with a DCCP-only patch set?

Not to mention the conflicts which you silently fixed instead of looking at
their cause.

You don't check the results of your own work and now you are trying to 
lecture others about maintainership? Look at yourself.

And to top this up now you are even asking me for "fixup patches" to fix the
about 60 patches that were accidentally sucked in, only a day after giving
us a lecture on the importance of review. What you are asking for here is to
wave through 60 patches without giving people a chance at all to review them.

I am not going to send patches to fix/cover this up. Either we want people to
review patches fairly or we don't.

What you are saying here has little authority. It is just foolish vanity.
I am really sorry for you and hope that you come back to your senses soon.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-10  5:19                                         ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-10  5:19 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 10 Sep 2008 07:01:15 +0200

> Not only are you lacking the courage to admit that it was your own fault
> to pull a tree no one had asked you to pull, now you are trying to make 
> me look foolish to cover your own mistake. 

Your subject line said, and it's still being used in this thread:
"net-next-2.6 [pull-request]"

What the heck should I take that to mean exactly?

> It further did not even occur to you to check the provided gitweb link, nor
> did you recognise that you had pulled about 100 instead of 37 patches. And
> you seem not to have looked at the diffstats either - what has a change in
> tcp_input.c got to do with a DCCP-only patch set?
>
> Not to mention the conflicts which you silently fixed instead of looking at
> their cause.

I did look at the merge conflicts I fixed up, code moved from one place
to another or got handled by new helper routines which were being
called, so I picked the appropriate hunk and validated the build.

If I wasn't all that sure of the result I would have replied to you
instead saying "this tree is messed up, I'm not pulling"  And I do
that all the time.

The shorter answer is I did my best and I TRUSTED YOU to only point
a GIT URL my way that was explicitly ready.  Else, you'd say "don't
pull this" rather than have "net-next-2.6 pull request" in the subject
line.

> What you are saying here has little authority. It is just foolish vanity.

Gerrit, it's over.  The only one in vain is you.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-10  5:19                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-10  5:19 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 10 Sep 2008 07:01:15 +0200

> Not only are you lacking the courage to admit that it was your own fault
> to pull a tree no one had asked you to pull, now you are trying to make 
> me look foolish to cover your own mistake. 

Your subject line said, and it's still being used in this thread:
"net-next-2.6 [pull-request]"

What the heck should I take that to mean exactly?

> It further did not even occur to you to check the provided gitweb link, nor
> did you recognise that you had pulled about 100 instead of 37 patches. And
> you seem not to have looked at the diffstats either - what has a change in
> tcp_input.c got to do with a DCCP-only patch set?
>
> Not to mention the conflicts which you silently fixed instead of looking at
> their cause.

I did look at the merge conflicts I fixed up, code moved from one place
to another or got handled by new helper routines which were being
called, so I picked the appropriate hunk and validated the build.

If I wasn't all that sure of the result I would have replied to you
instead saying "this tree is messed up, I'm not pulling"  And I do
that all the time.

The shorter answer is I did my best and I TRUSTED YOU to only point
a GIT URL my way that was explicitly ready.  Else, you'd say "don't
pull this" rather than have "net-next-2.6 pull request" in the subject
line.

> What you are saying here has little authority. It is just foolish vanity.

Gerrit, it's over.  The only one in vain is you.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-11  5:41                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-11  5:41 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| > Not only are you lacking the courage to admit that it was your own fault
| > to pull a tree no one had asked you to pull, now you are trying to make 
| > me look foolish to cover your own mistake. 
| 
| Your subject line said, and it's still being used in this thread:
| "net-next-2.6 [pull-request]"
| 
| What the heck should I take that to mean exactly?
| 
Yes, it takes two to make a misunderstanding. And maybe it was me who
misunderstood you, or maybe vice versa. Here is my understanding - this
thread started as a pull request, after sending a call for last comments
about two weeks ago. Your first reply in this thread was to extend the
last call for comments, which went on all over last week.

Meanwhile I had contacted you and Arnaldo privately to ask what to do
with DCCP in general. I had emailed you twice, there was no reply,
instead the tree was pulled without further discussion. 

That would probably have been ok if only it had been the right tree.

Since you chose not to reply, I assumed that you were taking responsibility
for your own choices.

By saying that you trusted me in light of what happened, you seem to 
imply that all I had intended was to pull a bad trick on you.

I am not sure I want to believe this. It is not fair to ignore a private
request asking what to do with DCCP and then broadcasting around in
public "I want someone else to get the DCCP changes through".

That will only solve a part of the problem, unfortunately it is not an
insurance against mistakes.

Since you chose not to reply in private regarding what to to with DCCP,
I suggest that we continue/finish this discussion here - yes, probably
after renaming this thread :)

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-11  5:41                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-11  5:41 UTC (permalink / raw)
  To: dccp

| > Not only are you lacking the courage to admit that it was your own fault
| > to pull a tree no one had asked you to pull, now you are trying to make 
| > me look foolish to cover your own mistake. 
| 
| Your subject line said, and it's still being used in this thread:
| "net-next-2.6 [pull-request]"
| 
| What the heck should I take that to mean exactly?
| 
Yes, it takes two to make a misunderstanding. And maybe it was me who
misunderstood you, or maybe vice versa. Here is my understanding - this
thread started as a pull request, after sending a call for last comments
about two weeks ago. Your first reply in this thread was to extend the
last call for comments, which went on all over last week.

Meanwhile I had contacted you and Arnaldo privately to ask what to do
with DCCP in general. I had emailed you twice, there was no reply,
instead the tree was pulled without further discussion. 

That would probably have been ok if only it had been the right tree.

Since you chose not to reply, I assumed that you were taking responsibility
for your own choices.

By saying that you trusted me in light of what happened, you seem to 
imply that all I had intended was to pull a bad trick on you.

I am not sure I want to believe this. It is not fair to ignore a private
request asking what to do with DCCP and then broadcasting around in
public "I want someone else to get the DCCP changes through".

That will only solve a part of the problem, unfortunately it is not an
insurance against mistakes.

Since you chose not to reply in private regarding what to to with DCCP,
I suggest that we continue/finish this discussion here - yes, probably
after renaming this thread :)

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* What to do with DCCP (was:  net-next-2.6 [pull-request] [PATCH 0/37]...)
@ 2008-09-11  5:45                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-11  5:45 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

This is a reply to the earlier email, the question of what to
do with DCCP is at the end. Basically I would be ok if someone
else familiar with DCCP wanted to take over. 
What then still may cause problems is that DCCP is still a
work-in-progress, please see at end of message.

| You can't seem to get the whole review process right, yet it's the
| most important aspect of getting changes into the tree.  It's 1,000
| times more important that implementing the code in the first place.
| 
This is simply not true. For this request the review process began
a year ago, the patches have been resubmitted several times and have 
been available in a test tree which gets updated almost daily. We tested
this code ourselves extensively in the EU Satsix project. Also, the
publicly available gstreamer DCCP plugin has been using this API.

| For starters, you don't dump 30 or 40 patches on people's laps for
| review.  You give them 5, maybe 10, at a time.  And you submit them
| when you write them, so that you don't have to rewrite everything
| after the ones that need fixups.
| 
This is only possible when using huge patches and then people will complain
that the patches contain too many different things. You yourself said
something like this earlier.

I am happy to change the format, but it seems there is no way to make it
right to everyone - either I get accused of putting too much into one patch,
or I get accused of sending too many patches of a finer granularity.


| And once you've submitted a large chunk of changes like you did this
| time, you've worn out your reviewer pool, and they'll need a long
| recovery period before they can devote time to looking at this stuff
| again.
| 
Ack.


| > | Don't warn about crap like this, instead convert the code over to hrtimers.
| > | 
| > | This kernel being built, even with HZ=100, can do nanosecond timers on
| > | my systems, but that's only if you would make proper use of them.
| > | 
| > The present sk_timer implementation uses the algorithm from RFC 3448. I
| > did not want to blindly port it to hrtimer since so far the following
| > difficulties were in the way:
| > 
| >  * when using the algorithm from RFC 3448, 4.6 directly with hrtimers,
| >    a large burst of activity will result, especially on fast links;
| > 
| >  * I have doubts whether it will help: each time the precision is improved,
| >    more frantic high-frequency noise results in CCID-3:
| 
| To me this is just pure bullshit, I'm sorry to say.
| 
| A warning gets added that barks at the person compiling this stuff
| saying: "YOUR TIMER ISN'T ACCURATE ENOUGH" and now you're telling me
| your concerned that hrtimers might give too much accuracy.
| 
| Which is it?
| 
| Lower limit the hrtimer interval, or make it as course as you damn
| well need, anything but this pile of excuses.
| 
| HZ=100 is extremely common, and there is no reason to bark at people
| about something they can do absolutely nothing about.  Who in the
| world is supposed to act upon that warning?
| 
The warning is enabled only if DCCP is configured into the kernel or as
module. It is interesting to see someone else suggesting hrtimers here.
When hrtimers became available I had suggested this on dccp@vger, but
there was a lot of opposition/disagreement about it.

It is easy to make strong words. If you are really convinced that it is
so easy then without making CCID-3 oscillate, please let's see a patch.
I have laboured for 2 years on making CCID-3 less unpredictable/frantic
and doubt it is so easy.


| Yet now everyone building the linux -next tree will see it if their HZ
| is choosen to be low enough and we'll thus get piles of "what's this?"
| queries on all the lists.
| 
If it becomes a bother please feel free to forward the stuff to this inbox.


| Look...
| 
| This whole process isn't going smoothly.  You are time limited, and
| the place you are short changing, time wise, appears to be the whole
| submission and review process.  Yet this should be your highest
| priority, far and above implementing even one single line of code.
| 
You have convinced me that this `time-limited' point really is invalid.

It leads to annoyances and the wrong choices. I will stick around and
find some time until this part has been resolved. And if people want to
take longer for their review, fine. It is just that this review phase
has taken almost a year now.

It is also not possible to make the review process much easier, since
DCCP is a largely untested research protocol. Many of its features and
algorithms have only been tested in simulation, and there are lots
of little algorithms and later-added-features, all interacting with
one another. This is labour-intensive for writers and reviewers of
patches, but convenient for writers of specs, who get bugs in their
documents fixed for them at no expense.

To free your energy for more important work, one might consider doing
all of the DCCP stuff in an experimental tree and merge it back later,
once all the long-discussion issues have been resolved.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* What to do with DCCP (was:  net-next-2.6 [pull-request] [PATCH
@ 2008-09-11  5:45                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-11  5:45 UTC (permalink / raw)
  To: dccp

This is a reply to the earlier email, the question of what to
do with DCCP is at the end. Basically I would be ok if someone
else familiar with DCCP wanted to take over. 
What then still may cause problems is that DCCP is still a
work-in-progress, please see at end of message.

| You can't seem to get the whole review process right, yet it's the
| most important aspect of getting changes into the tree.  It's 1,000
| times more important that implementing the code in the first place.
| 
This is simply not true. For this request the review process began
a year ago, the patches have been resubmitted several times and have 
been available in a test tree which gets updated almost daily. We tested
this code ourselves extensively in the EU Satsix project. Also, the
publicly available gstreamer DCCP plugin has been using this API.

| For starters, you don't dump 30 or 40 patches on people's laps for
| review.  You give them 5, maybe 10, at a time.  And you submit them
| when you write them, so that you don't have to rewrite everything
| after the ones that need fixups.
| 
This is only possible when using huge patches and then people will complain
that the patches contain too many different things. You yourself said
something like this earlier.

I am happy to change the format, but it seems there is no way to make it
right to everyone - either I get accused of putting too much into one patch,
or I get accused of sending too many patches of a finer granularity.


| And once you've submitted a large chunk of changes like you did this
| time, you've worn out your reviewer pool, and they'll need a long
| recovery period before they can devote time to looking at this stuff
| again.
| 
Ack.


| > | Don't warn about crap like this, instead convert the code over to hrtimers.
| > | 
| > | This kernel being built, even with HZ\x100, can do nanosecond timers on
| > | my systems, but that's only if you would make proper use of them.
| > | 
| > The present sk_timer implementation uses the algorithm from RFC 3448. I
| > did not want to blindly port it to hrtimer since so far the following
| > difficulties were in the way:
| > 
| >  * when using the algorithm from RFC 3448, 4.6 directly with hrtimers,
| >    a large burst of activity will result, especially on fast links;
| > 
| >  * I have doubts whether it will help: each time the precision is improved,
| >    more frantic high-frequency noise results in CCID-3:
| 
| To me this is just pure bullshit, I'm sorry to say.
| 
| A warning gets added that barks at the person compiling this stuff
| saying: "YOUR TIMER ISN'T ACCURATE ENOUGH" and now you're telling me
| your concerned that hrtimers might give too much accuracy.
| 
| Which is it?
| 
| Lower limit the hrtimer interval, or make it as course as you damn
| well need, anything but this pile of excuses.
| 
| HZ\x100 is extremely common, and there is no reason to bark at people
| about something they can do absolutely nothing about.  Who in the
| world is supposed to act upon that warning?
| 
The warning is enabled only if DCCP is configured into the kernel or as
module. It is interesting to see someone else suggesting hrtimers here.
When hrtimers became available I had suggested this on dccp@vger, but
there was a lot of opposition/disagreement about it.

It is easy to make strong words. If you are really convinced that it is
so easy then without making CCID-3 oscillate, please let's see a patch.
I have laboured for 2 years on making CCID-3 less unpredictable/frantic
and doubt it is so easy.


| Yet now everyone building the linux -next tree will see it if their HZ
| is choosen to be low enough and we'll thus get piles of "what's this?"
| queries on all the lists.
| 
If it becomes a bother please feel free to forward the stuff to this inbox.


| Look...
| 
| This whole process isn't going smoothly.  You are time limited, and
| the place you are short changing, time wise, appears to be the whole
| submission and review process.  Yet this should be your highest
| priority, far and above implementing even one single line of code.
| 
You have convinced me that this `time-limited' point really is invalid.

It leads to annoyances and the wrong choices. I will stick around and
find some time until this part has been resolved. And if people want to
take longer for their review, fine. It is just that this review phase
has taken almost a year now.

It is also not possible to make the review process much easier, since
DCCP is a largely untested research protocol. Many of its features and
algorithms have only been tested in simulation, and there are lots
of little algorithms and later-added-features, all interacting with
one another. This is labour-intensive for writers and reviewers of
patches, but convenient for writers of specs, who get bugs in their
documents fixed for them at no expense.

To free your energy for more important work, one might consider doing
all of the DCCP stuff in an experimental tree and merge it back later,
once all the long-discussion issues have been resolved.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-11  5:51                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-11  5:51 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu, 11 Sep 2008 07:41:04 +0200

> Meanwhile I had contacted you and Arnaldo privately to ask what to do
> with DCCP in general. I had emailed you twice, there was no reply,
> instead the tree was pulled without further discussion. 

I simply had nothing to add to that discussion.

I don't know what I could possibly say above and beyond what Arnaldo
did.  There is nobody in the wings to take over and you don't have the
time.  The only logical conclusion is that DCCP just sits and rots
until someone suitably capable and who has the time shows up.   And,
that's exactly what Arnaldo said.

I mean, it's not like the New York Stock Exchange is going to shut
down tomorrow because we don't have a DCCP maintainer. :-)

Furthermore, you sent that email to me while I was away for 4 days
trying to enjoy myself on a little vacation.

Sorry, next time I'll stop trying to relax and instead reply to email.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-11  5:51                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-11  5:51 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu, 11 Sep 2008 07:41:04 +0200

> Meanwhile I had contacted you and Arnaldo privately to ask what to do
> with DCCP in general. I had emailed you twice, there was no reply,
> instead the tree was pulled without further discussion. 

I simply had nothing to add to that discussion.

I don't know what I could possibly say above and beyond what Arnaldo
did.  There is nobody in the wings to take over and you don't have the
time.  The only logical conclusion is that DCCP just sits and rots
until someone suitably capable and who has the time shows up.   And,
that's exactly what Arnaldo said.

I mean, it's not like the New York Stock Exchange is going to shut
down tomorrow because we don't have a DCCP maintainer. :-)

Furthermore, you sent that email to me while I was away for 4 days
trying to enjoy myself on a little vacation.

Sorry, next time I'll stop trying to relax and instead reply to email.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: What to do with DCCP
@ 2008-09-11  5:53                                     ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-11  5:53 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu, 11 Sep 2008 07:45:26 +0200

> It is easy to make strong words. If you are really convinced that it is
> so easy then without making CCID-3 oscillate, please let's see a patch.

You make the mistake that I want to spend time on DCCP hacking, I really
don't.

But as networking maintainer I do have a right to put my foot down when
something all the build testers are going to try is going to send out
a bogus warning that helps nobody with anything.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: What to do with DCCP
@ 2008-09-11  5:53                                     ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-11  5:53 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu, 11 Sep 2008 07:45:26 +0200

> It is easy to make strong words. If you are really convinced that it is
> so easy then without making CCID-3 oscillate, please let's see a patch.

You make the mistake that I want to spend time on DCCP hacking, I really
don't.

But as networking maintainer I do have a right to put my foot down when
something all the build testers are going to try is going to send out
a bogus warning that helps nobody with anything.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-11 14:02                                               ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-11 14:02 UTC (permalink / raw)
  To: David Miller; +Cc: gerrit, dccp, netdev

Em Wed, Sep 10, 2008 at 10:51:00PM -0700, David Miller escreveu:
> From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Date: Thu, 11 Sep 2008 07:41:04 +0200
> 
> > Meanwhile I had contacted you and Arnaldo privately to ask what to do
> > with DCCP in general. I had emailed you twice, there was no reply,
> > instead the tree was pulled without further discussion. 
> 
> I simply had nothing to add to that discussion.
> 
> I don't know what I could possibly say above and beyond what Arnaldo
> did.  There is nobody in the wings to take over and you don't have the
> time.  The only logical conclusion is that DCCP just sits and rots
> until someone suitably capable and who has the time shows up.   And,
> that's exactly what Arnaldo said.

I was afraid that at some point I would lose the energy or the free time
needed to get DCCP to a conclusion, if there is ever a conclusion in the
life of such a complex piece of software as is a transport protocol.
That is why I worked hard to share as much code with TCP as possible,
and I think there are still opportunities to share even more code.

But right now I think that the situation is way better than when I was
mostly alone working on it, Ian and Andrea contributed lots of code,
Gerrit came up and did lots, lots more, Leandro worked on it, Tommi as
well, there is the work that Tomasz did on policies and now Wei is
testing it and providing analisys, so its not how, say, IPv6 stayed for
a long time.

So don't worry too much, at some point things will get to a better
shape.

The time it takes for a new protocol to get in shape and used is indeed
long.
 
- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-11 14:02                                               ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-11 14:02 UTC (permalink / raw)
  To: dccp

Em Wed, Sep 10, 2008 at 10:51:00PM -0700, David Miller escreveu:
> From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Date: Thu, 11 Sep 2008 07:41:04 +0200
> 
> > Meanwhile I had contacted you and Arnaldo privately to ask what to do
> > with DCCP in general. I had emailed you twice, there was no reply,
> > instead the tree was pulled without further discussion. 
> 
> I simply had nothing to add to that discussion.
> 
> I don't know what I could possibly say above and beyond what Arnaldo
> did.  There is nobody in the wings to take over and you don't have the
> time.  The only logical conclusion is that DCCP just sits and rots
> until someone suitably capable and who has the time shows up.   And,
> that's exactly what Arnaldo said.

I was afraid that at some point I would lose the energy or the free time
needed to get DCCP to a conclusion, if there is ever a conclusion in the
life of such a complex piece of software as is a transport protocol.
That is why I worked hard to share as much code with TCP as possible,
and I think there are still opportunities to share even more code.

But right now I think that the situation is way better than when I was
mostly alone working on it, Ian and Andrea contributed lots of code,
Gerrit came up and did lots, lots more, Leandro worked on it, Tommi as
well, there is the work that Tomasz did on policies and now Wei is
testing it and providing analisys, so its not how, say, IPv6 stayed for
a long time.

So don't worry too much, at some point things will get to a better
shape.

The time it takes for a new protocol to get in shape and used is indeed
long.
 
- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-11 15:57                                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-11 15:57 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| Furthermore, you sent that email to me while I was away for 4 days
| trying to enjoy myself on a little vacation.
| 
And I think I owe you an apology for the grief that this caused. There
are indeed better ways of spending time.

With regard to keeping it up, there may be alternatives, hopefully this
thread will bring something up.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-11 15:57                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-11 15:57 UTC (permalink / raw)
  To: dccp

| Furthermore, you sent that email to me while I was away for 4 days
| trying to enjoy myself on a little vacation.
| 
And I think I owe you an apology for the grief that this caused. There
are indeed better ways of spending time.

With regard to keeping it up, there may be alternatives, hopefully this
thread will bring something up.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: What to do with DCCP
  2008-09-11  5:53                                     ` David Miller
@ 2008-09-12  5:16                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-12  5:16 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| But as networking maintainer I do have a right to put my foot down when
| something all the build testers are going to try is going to send out
| a bogus warning that helps nobody with anything.
| 
Which is entirely correct -- that part is really not suitable for
consideration in mainline. There are several such duct-tape measures
in the test tree, which will have to wait until there is enough time
to fix each of the causes and test the replaced code.

There are problems of the mainline DCCP variant which are fixed in the
test tree, but until everything has been resolved will take some time.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: What to do with DCCP
@ 2008-09-12  5:16                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-12  5:16 UTC (permalink / raw)
  To: dccp

| But as networking maintainer I do have a right to put my foot down when
| something all the build testers are going to try is going to send out
| a bogus warning that helps nobody with anything.
| 
Which is entirely correct -- that part is really not suitable for
consideration in mainline. There are several such duct-tape measures
in the test tree, which will have to wait until there is enough time
to fix each of the causes and test the replaced code.

There are problems of the mainline DCCP variant which are fixed in the
test tree, but until everything has been resolved will take some time.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-22  4:57                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  4:57 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

Hi Dave,

it has been unfortunate that there had been an error in the submission
of the DCCP feature negotiation patch set.

I would like to return to the submission of the original set of patches,
i.e. those 37 that were discussed and for which fixes had been uploaded.

The changeset provides infrastructure for doing end-to-end feature negotiation,
is self-contained, has been tested for a long while, and is free from
duct-tape fixes.  
(Just for reference - the count of `XXX'-es in the current feat.c is 15,
plus 2 FIXMEs.)

There is a benefit of using this patch set, as it will make it easier
for other people to add code (new CCIDs) to DCCP. 
Only 2 CCIDs exist so far, whose performance and scope is somewhat limited.
There is room for about 250 more CCIDs, for different and completely new
algorithms.

To plug in new CCIDs, feature negotiation at the endpoints is necessary.

The extensions that Arnaldo had suggested are also much easier to
construct with this set. With the present code I think it is nearly impossible.

If you would like to reopen review and discussion, I am willing to address
any further comments.

I have put the set of 37 patches (complete list below) onto a freshly cloned
net-next-2.6 (from today), compile-tested (it is bisectable), and uploaded to

	git://eden-feed.erg.abdn.ac.uk/net-next-2.6 	[subtree `master']

The revised changeset can be also be viewed at:
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git


Best regards	
Gerrit


List of patches in this set
---------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  
Patch #6: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #7: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #8: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #9: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

Patch #10: Provides a mechanism to then resolve CCID-dependent features. Since
           CCIDs are a server-priority feature, this is done by the server.
Patch #11: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #12: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #13: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #14: Tidies up the setsockopt interface for new additions.
Patch #15: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #16: Socket API to query the current CCID from userspace.
Patch #17: Prepares the variable-length htonl/ntohl functions for 48 bits.
           Such a length is needed by e.g. the Sequence Window feature.
Patch #18: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #19: Routine to insert feature-negotiation header options.
Patch #20: Complements #19, to add feature-negotiation options onto the skb.
Patch #21: Complements #20 and completes the insertion of featneg options.
Patch #22: Logic/algorithm to actually reconcile negotiation options.
Patch #23: Receiver support to process incoming Change L/R options. 
Patch #24: Receiver support to process incoming Confirm R/L options.
Patch #25: Handlers for activating successfully negotiated features.

Patch #26: Integration of dynamic negotiation, part I (socket setup).
Patch #27: Integration of dynamic negotiation, part II (server side).
Patch #28: Integration of dynamic negotiation, part III (client side).

Patch #29: Cleans up the older infrastructure.
Patch #30: Removes obsolete parts of the old CCID interface.
Patch #31: Removes manual intervention on NDP count (now automatic).
Patch #32: Removes Ack Vector sysctl (handled automatically now).

Patch #33: Initialisation framework for the supported features.
Patch #34: Auto-loading of CCID modules so that the modules are available
           when the negotiation is completed.
Patch #35: Adds full support for local/remote Sequence Window.
Patch #36: Initialisation and type-checking of involved sysctls.
Patch #37: A set of (useful) debugging/printing helper functions.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-22  4:57                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  4:57 UTC (permalink / raw)
  To: dccp

Hi Dave,

it has been unfortunate that there had been an error in the submission
of the DCCP feature negotiation patch set.

I would like to return to the submission of the original set of patches,
i.e. those 37 that were discussed and for which fixes had been uploaded.

The changeset provides infrastructure for doing end-to-end feature negotiation,
is self-contained, has been tested for a long while, and is free from
duct-tape fixes.  
(Just for reference - the count of `XXX'-es in the current feat.c is 15,
plus 2 FIXMEs.)

There is a benefit of using this patch set, as it will make it easier
for other people to add code (new CCIDs) to DCCP. 
Only 2 CCIDs exist so far, whose performance and scope is somewhat limited.
There is room for about 250 more CCIDs, for different and completely new
algorithms.

To plug in new CCIDs, feature negotiation at the endpoints is necessary.

The extensions that Arnaldo had suggested are also much easier to
construct with this set. With the present code I think it is nearly impossible.

If you would like to reopen review and discussion, I am willing to address
any further comments.

I have put the set of 37 patches (complete list below) onto a freshly cloned
net-next-2.6 (from today), compile-tested (it is bisectable), and uploaded to

	git://eden-feed.erg.abdn.ac.uk/net-next-2.6 	[subtree `master']

The revised changeset can be also be viewed at:
	http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git


Best regards	
Gerrit


List of patches in this set
---------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  
Patch #6: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #7: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #8: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #9: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

Patch #10: Provides a mechanism to then resolve CCID-dependent features. Since
           CCIDs are a server-priority feature, this is done by the server.
Patch #11: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #12: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #13: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #14: Tidies up the setsockopt interface for new additions.
Patch #15: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #16: Socket API to query the current CCID from userspace.
Patch #17: Prepares the variable-length htonl/ntohl functions for 48 bits.
           Such a length is needed by e.g. the Sequence Window feature.
Patch #18: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #19: Routine to insert feature-negotiation header options.
Patch #20: Complements #19, to add feature-negotiation options onto the skb.
Patch #21: Complements #20 and completes the insertion of featneg options.
Patch #22: Logic/algorithm to actually reconcile negotiation options.
Patch #23: Receiver support to process incoming Change L/R options. 
Patch #24: Receiver support to process incoming Confirm R/L options.
Patch #25: Handlers for activating successfully negotiated features.

Patch #26: Integration of dynamic negotiation, part I (socket setup).
Patch #27: Integration of dynamic negotiation, part II (server side).
Patch #28: Integration of dynamic negotiation, part III (client side).

Patch #29: Cleans up the older infrastructure.
Patch #30: Removes obsolete parts of the old CCID interface.
Patch #31: Removes manual intervention on NDP count (now automatic).
Patch #32: Removes Ack Vector sysctl (handled automatically now).

Patch #33: Initialisation framework for the supported features.
Patch #34: Auto-loading of CCID modules so that the modules are available
           when the negotiation is completed.
Patch #35: Adds full support for local/remote Sequence Window.
Patch #36: Initialisation and type-checking of involved sysctls.
Patch #37: A set of (useful) debugging/printing helper functions.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-22  5:09                           ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-22  5:09 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 22 Sep 2008 06:57:44 +0200

> I have put the set of 37 patches (complete list below) onto a freshly cloned
> net-next-2.6 (from today), compile-tested (it is bisectable), and uploaded to
> 
> 	git://eden-feed.erg.abdn.ac.uk/net-next-2.6 	[subtree `master']

Gerrit, I said it's over.  I really meant this.

I'm not taking GIT pulls from you any more.

There are two paths forward at the current point in time.

1) You submit a very small group of patches at a time to me.
   I'm talking like 5 or 6 patches at a time, maximum.

   And I'm going to give extra amounts of personal review to
   these, so it will take even more time than usual.

2) Someone else steps up to run the DCCP git stuff.

I absolutely do not trust you any more, and you're behavior and
expectations of me during that last mistake pull didn't help that
cause at all.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-22  5:09                           ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-22  5:09 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 22 Sep 2008 06:57:44 +0200

> I have put the set of 37 patches (complete list below) onto a freshly cloned
> net-next-2.6 (from today), compile-tested (it is bisectable), and uploaded to
> 
> 	git://eden-feed.erg.abdn.ac.uk/net-next-2.6 	[subtree `master']

Gerrit, I said it's over.  I really meant this.

I'm not taking GIT pulls from you any more.

There are two paths forward at the current point in time.

1) You submit a very small group of patches at a time to me.
   I'm talking like 5 or 6 patches at a time, maximum.

   And I'm going to give extra amounts of personal review to
   these, so it will take even more time than usual.

2) Someone else steps up to run the DCCP git stuff.

I absolutely do not trust you any more, and you're behavior and
expectations of me during that last mistake pull didn't help that
cause at all.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-22  6:28                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  6:28 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

| There are two paths forward at the current point in time.
| 
| 1) You submit a very small group of patches at a time to me.
|    I'm talking like 5 or 6 patches at a time, maximum.
| 
|    And I'm going to give extra amounts of personal review to
|    these, so it will take even more time than usual.
| 
Further review can never harm, so I am sure this will be good.

I have a question regarding granularity - the current granularity is
meant to be logical, but is low.
It is easy to get distracted by the details since at the end of
the day the 37 patches achieve a rewriting of feat.c in small steps.

Would you therefore be ok with me combining some of the patches or would
you prefer to review the set at its current granularity?

Thanks
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-22  6:28                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  6:28 UTC (permalink / raw)
  To: dccp

| There are two paths forward at the current point in time.
| 
| 1) You submit a very small group of patches at a time to me.
|    I'm talking like 5 or 6 patches at a time, maximum.
| 
|    And I'm going to give extra amounts of personal review to
|    these, so it will take even more time than usual.
| 
Further review can never harm, so I am sure this will be good.

I have a question regarding granularity - the current granularity is
meant to be logical, but is low.
It is easy to get distracted by the details since at the end of
the day the 37 patches achieve a rewriting of feat.c in small steps.

Would you therefore be ok with me combining some of the patches or would
you prefer to review the set at its current granularity?

Thanks
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches
  2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
@ 2008-09-22  6:58                               ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-22  6:58 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 22 Sep 2008 08:28:07 +0200

> | There are two paths forward at the current point in time.
> | 
> | 1) You submit a very small group of patches at a time to me.
> |    I'm talking like 5 or 6 patches at a time, maximum.
> | 
> |    And I'm going to give extra amounts of personal review to
> |    these, so it will take even more time than usual.
> | 
> Further review can never harm, so I am sure this will be good.
> 
> I have a question regarding granularity - the current granularity is
> meant to be logical, but is low.
> It is easy to get distracted by the details since at the end of
> the day the 37 patches achieve a rewriting of feat.c in small steps.
> 
> Would you therefore be ok with me combining some of the patches or would
> you prefer to review the set at its current granularity?

Current granularity.

So, submit about 5 pieces at a time, you can say at the beginning of
the series (in the [PATCH 0/X]: email) something like "this is phase N
in the rewriting of feat.c which will achieve X Y and Z"

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of
@ 2008-09-22  6:58                               ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-22  6:58 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 22 Sep 2008 08:28:07 +0200

> | There are two paths forward at the current point in time.
> | 
> | 1) You submit a very small group of patches at a time to me.
> |    I'm talking like 5 or 6 patches at a time, maximum.
> | 
> |    And I'm going to give extra amounts of personal review to
> |    these, so it will take even more time than usual.
> | 
> Further review can never harm, so I am sure this will be good.
> 
> I have a question regarding granularity - the current granularity is
> meant to be logical, but is low.
> It is easy to get distracted by the details since at the end of
> the day the 37 patches achieve a rewriting of feat.c in small steps.
> 
> Would you therefore be ok with me combining some of the patches or would
> you prefer to review the set at its current granularity?

Current granularity.

So, submit about 5 pieces at a time, you can say at the beginning of
the series (in the [PATCH 0/X]: email) something like "this is phase N
in the rewriting of feat.c which will achieve X Y and Z"

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
@ 2008-09-22  7:21                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

please find the first set summarised below.


This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.

List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  


The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=commitdiff;h=523d8569f1200e57d010d8ec0240b931b667ea59

Patch stats:
------------
 include/linux/dccp.h |   13 +-
 net/dccp/dccp.h      |    5 
 net/dccp/feat.c      |  277 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   61 +++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 
 net/dccp/ipv6.c      |    4 
 net/dccp/minisocks.c |    7 +
 net/dccp/proto.c     |    3 
 9 files changed, 365 insertions(+), 11 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
@ 2008-09-22  7:21                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find the first set summarised below.


This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.

List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  


The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=net-next-2.6.git;a=commitdiff;hR3d8569f1200e57d010d8ec0240b931b667ea59

Patch stats:
------------
 include/linux/dccp.h |   13 +-
 net/dccp/dccp.h      |    5 
 net/dccp/feat.c      |  277 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   61 +++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 
 net/dccp/ipv6.c      |    4 
 net/dccp/minisocks.c |    7 +
 net/dccp/proto.c     |    3 
 9 files changed, 365 insertions(+), 11 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-09-22  7:21                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   14 ++++++++++++
 net/dccp/feat.h |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,66 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @feat_num: one of %dccp_feature_numbers
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	u8                      feat_num;
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	bool			needs_mandatory:1,
+				needs_confirm:1,
+				empty_confirm:1,
+				is_local:1;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-09-22  7:21                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   14 ++++++++++++
 net/dccp/feat.h |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec = NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,66 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @feat_num: one of %dccp_feature_numbers
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	u8                      feat_num;
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	bool			needs_mandatory:1,
+				needs_confirm:1,
+				empty_confirm:1,
+				is_local:1;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
@ 2008-09-22  7:21                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,80 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	return idx < 0 ? : dccp_feat_table[idx].default_value;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +111,45 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +766,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
@ 2008-09-22  7:21                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,80 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	return idx < 0 ? : dccp_feat_table[idx].default_value;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +111,45 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type = FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new = NULL)
+		return NULL;
+
+	if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +766,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
@ 2008-09-22  7:21                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Thanks to Arnaldo for suggestions to improve the code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -150,6 +150,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 	}
 }
 
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num == feat && entry->is_local == local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval == NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
@ 2008-09-22  7:21                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: dccp

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Thanks to Arnaldo for suggestions to improve the code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -150,6 +150,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 	}
 }
 
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num = feat_num && entry->is_local = is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num = feat && entry->is_local = local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval = NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
@ 2008-09-22  7:21                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 ++++
 net/dccp/dccp.h      |    3 ++-
 net/dccp/feat.c      |   19 +++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 --
 net/dccp/ipv4.c      |    3 ++-
 net/dccp/ipv6.c      |    3 ++-
 net/dccp/minisocks.c |    7 ++++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 37 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -279,6 +279,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new == NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -95,6 +95,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type == DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
@ 2008-09-22  7:21                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 ++++
 net/dccp/dccp.h      |    3 ++-
 net/dccp/feat.c      |   19 +++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 --
 net/dccp/ipv4.c      |    3 ++-
 net/dccp/ipv6.c      |    3 ++-
 net/dccp/minisocks.c |    7 ++++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 37 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -279,6 +279,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new = NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -95,6 +95,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type = DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
@ 2008-09-22  7:21                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h  |    2 ++
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 4 files changed, 5 insertions(+), 1 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
@ 2008-09-22  7:21                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22  7:21 UTC (permalink / raw)
  To: dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h  |    2 ++
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 4 files changed, 5 insertions(+), 1 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Basic data structure for feature negotiation
  2008-09-22  7:21                                   ` Gerrit Renker
@ 2008-09-22 14:10                                     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 14:10 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev

Em Mon, Sep 22, 2008 at 09:21:53AM +0200, Gerrit Renker escreveu:
> This patch prepares for the new and extended feature-negotiation routines.
> 
> The following feature-negotiation data structures are provided:
> 	* a container for the various (SP or NN) values,
> 	* symbolic state names to track feature states,
> 	* an entry struct which holds all current information together,
> 	* elementary functions to fill in and process these structures.
> 
> Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
> that if multiple options of the same type are present, they are processed in the
> order of their appearance in the packet; which means that this order needs to be
> preserved in the local data structure (the later insertion code also respects
> this order).
> 
> The struct list_head has been chosen for the following reasons: the most
> frequent operations are
>  * add new entry at tail (when receiving Change or setting socket options);
>  * delete entry (when Confirm has been received);
>  * deep copy of entire list (cloning from listening socket onto request socket).
> 
> The NN value has been set to 64 bit, which is a currently sufficient upper limit
> (Sequence Window feature has 48 bit).
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/feat.c |   14 ++++++++++++
>  net/dccp/feat.h |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 74 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -23,6 +23,20 @@
>  
>  #define DCCP_FEAT_SP_NOAGREE (-123)
>  
> +/* copy constructor, fval must not already contain allocated memory */
> +static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
> +{
> +	fval->sp.len = len;
> +	if (fval->sp.len > 0) {
> +		fval->sp.vec = kmemdup(val, len, gfp_any());
> +		if (fval->sp.vec == NULL) {
> +			fval->sp.len = 0;
> +			return -ENOBUFS;
> +		}
> +	}
> +	return 0;
> +}
> +
>  int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
>  		     u8 *val, u8 len, gfp_t gfp)
>  {
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -14,6 +14,66 @@
>  #include <linux/types.h>
>  #include "dccp.h"
>  
> +enum dccp_feat_type {
> +	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
> +	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
> +	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
> +	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
> +	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
> +};
> +
> +enum dccp_feat_state {
> +	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
> +	FEAT_INITIALISING,	/* feature is being initialised  */
> +	FEAT_CHANGING,		/* Change sent but not confirmed yet */
> +	FEAT_UNSTABLE,		/* local modification in state CHANGING */
> +	FEAT_STABLE		/* both ends (think they) agree */
> +};
> +
> +/**
> + * dccp_feat_val  -  Container for SP or NN feature values
> + * @nn:     single NN value
> + * @sp.vec: single SP value plus optional preference list
> + * @sp.len: length of @sp.vec in bytes
> + */
> +typedef union {
> +	u64 nn;
> +	struct {
> +		u8	*vec;
> +		u8	len;
> +	}   sp;
> +} dccp_feat_val;
> +
> +/**
> + * struct feat_entry  -  Data structure to perform feature negotiation
> + * @feat_num: one of %dccp_feature_numbers
> + * @val: feature's current value (SP features may have preference list)
> + * @state: feature's current state
> + * @needs_mandatory: whether Mandatory options should be sent
> + * @needs_confirm: whether to send a Confirm instead of a Change
> + * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
> + * @is_local: feature location (1) or feature-remote (0)
> + * @node: list pointers, entries arranged in FIFO order
> + */
> +struct dccp_feat_entry {
> +	u8                      feat_num;
> +	dccp_feat_val           val;
> +	enum dccp_feat_state    state:8;
> +	bool			needs_mandatory:1,
> +				needs_confirm:1,
> +				empty_confirm:1,
> +				is_local:1;
> +
> +	struct list_head	node;
> +};

As above:

[acme@doppio ~]$ pahole -C dccp_feat_entry dccp
struct dccp_feat_entry {
	u8                    feat_num;             /*     0     1 */

	/* XXX 7 bytes hole, try to pack */

	dccp_feat_val         val;                  /*     8    16 */
	enum dccp_feat_state  state:8;              /*    24:24  4 */

	/* Bitfield combined with next fields */

	_Bool                 needs_mandatory:1;    /*    25: 7  1 */
	_Bool                 needs_confirm:1;      /*    25: 6  1 */
	_Bool                 empty_confirm:1;      /*    25: 5  1 */
	_Bool                 is_local:1;           /*    25: 4  1 */

	/* XXX 4 bits hole, try to pack */
	/* XXX 6 bytes hole, try to pack */

	struct list_head      node;                 /*    32    16 */

	/* size: 48, cachelines: 1, members: 8 */
	/* sum members: 35, holes: 2, sum holes: 13 */
	/* bit holes: 1, sum bit holes: 4 bits */
	/* last cacheline: 48 bytes */
};

In this case, unless you plan to put more stuff into this struct in the
future, using a bitfield for the bool members is a pessimization, as we
will use the same amount of memory and generate more complex code. So I
suggest:

struct dccp_feat_entry {
	dccp_feat_val         val;                  /*     0    16 */
	enum dccp_feat_state  state:8;              /*    16:24  4 */

	/* Bitfield combined with next fields */

	u8                    feat_num;             /*    17     1 */
	_Bool                 needs_mandatory;      /*    18     1 */
	_Bool                 needs_confirm;        /*    19     1 */
	_Bool                 empty_confirm;        /*    20     1 */
	_Bool                 is_local;             /*    21     1 */

	/* XXX 2 bytes hole, try to pack */

	struct list_head      node;                 /*    24    16 */

	/* size: 40, cachelines: 1, members: 8 */
	/* sum members: 38, holes: 1, sum holes: 2 */
	/* last cacheline: 40 bytes */
};

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-09-22 14:10                                     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 14:10 UTC (permalink / raw)
  To: dccp

Em Mon, Sep 22, 2008 at 09:21:53AM +0200, Gerrit Renker escreveu:
> This patch prepares for the new and extended feature-negotiation routines.
> 
> The following feature-negotiation data structures are provided:
> 	* a container for the various (SP or NN) values,
> 	* symbolic state names to track feature states,
> 	* an entry struct which holds all current information together,
> 	* elementary functions to fill in and process these structures.
> 
> Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
> that if multiple options of the same type are present, they are processed in the
> order of their appearance in the packet; which means that this order needs to be
> preserved in the local data structure (the later insertion code also respects
> this order).
> 
> The struct list_head has been chosen for the following reasons: the most
> frequent operations are
>  * add new entry at tail (when receiving Change or setting socket options);
>  * delete entry (when Confirm has been received);
>  * deep copy of entire list (cloning from listening socket onto request socket).
> 
> The NN value has been set to 64 bit, which is a currently sufficient upper limit
> (Sequence Window feature has 48 bit).
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/feat.c |   14 ++++++++++++
>  net/dccp/feat.h |   60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 74 insertions(+), 0 deletions(-)
> 
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -23,6 +23,20 @@
>  
>  #define DCCP_FEAT_SP_NOAGREE (-123)
>  
> +/* copy constructor, fval must not already contain allocated memory */
> +static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
> +{
> +	fval->sp.len = len;
> +	if (fval->sp.len > 0) {
> +		fval->sp.vec = kmemdup(val, len, gfp_any());
> +		if (fval->sp.vec = NULL) {
> +			fval->sp.len = 0;
> +			return -ENOBUFS;
> +		}
> +	}
> +	return 0;
> +}
> +
>  int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
>  		     u8 *val, u8 len, gfp_t gfp)
>  {
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -14,6 +14,66 @@
>  #include <linux/types.h>
>  #include "dccp.h"
>  
> +enum dccp_feat_type {
> +	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
> +	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
> +	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
> +	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
> +	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
> +};
> +
> +enum dccp_feat_state {
> +	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
> +	FEAT_INITIALISING,	/* feature is being initialised  */
> +	FEAT_CHANGING,		/* Change sent but not confirmed yet */
> +	FEAT_UNSTABLE,		/* local modification in state CHANGING */
> +	FEAT_STABLE		/* both ends (think they) agree */
> +};
> +
> +/**
> + * dccp_feat_val  -  Container for SP or NN feature values
> + * @nn:     single NN value
> + * @sp.vec: single SP value plus optional preference list
> + * @sp.len: length of @sp.vec in bytes
> + */
> +typedef union {
> +	u64 nn;
> +	struct {
> +		u8	*vec;
> +		u8	len;
> +	}   sp;
> +} dccp_feat_val;
> +
> +/**
> + * struct feat_entry  -  Data structure to perform feature negotiation
> + * @feat_num: one of %dccp_feature_numbers
> + * @val: feature's current value (SP features may have preference list)
> + * @state: feature's current state
> + * @needs_mandatory: whether Mandatory options should be sent
> + * @needs_confirm: whether to send a Confirm instead of a Change
> + * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
> + * @is_local: feature location (1) or feature-remote (0)
> + * @node: list pointers, entries arranged in FIFO order
> + */
> +struct dccp_feat_entry {
> +	u8                      feat_num;
> +	dccp_feat_val           val;
> +	enum dccp_feat_state    state:8;
> +	bool			needs_mandatory:1,
> +				needs_confirm:1,
> +				empty_confirm:1,
> +				is_local:1;
> +
> +	struct list_head	node;
> +};

As above:

[acme@doppio ~]$ pahole -C dccp_feat_entry dccp
struct dccp_feat_entry {
	u8                    feat_num;             /*     0     1 */

	/* XXX 7 bytes hole, try to pack */

	dccp_feat_val         val;                  /*     8    16 */
	enum dccp_feat_state  state:8;              /*    24:24  4 */

	/* Bitfield combined with next fields */

	_Bool                 needs_mandatory:1;    /*    25: 7  1 */
	_Bool                 needs_confirm:1;      /*    25: 6  1 */
	_Bool                 empty_confirm:1;      /*    25: 5  1 */
	_Bool                 is_local:1;           /*    25: 4  1 */

	/* XXX 4 bits hole, try to pack */
	/* XXX 6 bytes hole, try to pack */

	struct list_head      node;                 /*    32    16 */

	/* size: 48, cachelines: 1, members: 8 */
	/* sum members: 35, holes: 2, sum holes: 13 */
	/* bit holes: 1, sum bit holes: 4 bits */
	/* last cacheline: 48 bytes */
};

In this case, unless you plan to put more stuff into this struct in the
future, using a bitfield for the bool members is a pessimization, as we
will use the same amount of memory and generate more complex code. So I
suggest:

struct dccp_feat_entry {
	dccp_feat_val         val;                  /*     0    16 */
	enum dccp_feat_state  state:8;              /*    16:24  4 */

	/* Bitfield combined with next fields */

	u8                    feat_num;             /*    17     1 */
	_Bool                 needs_mandatory;      /*    18     1 */
	_Bool                 needs_confirm;        /*    19     1 */
	_Bool                 empty_confirm;        /*    20     1 */
	_Bool                 is_local;             /*    21     1 */

	/* XXX 2 bytes hole, try to pack */

	struct list_head      node;                 /*    24    16 */

	/* size: 40, cachelines: 1, members: 8 */
	/* sum members: 38, holes: 1, sum holes: 2 */
	/* last cacheline: 40 bytes */
};

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-22 14:21                                       ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 14:21 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev

Em Mon, Sep 22, 2008 at 09:21:54AM +0200, Gerrit Renker escreveu:
> A lookup table for feature-negotiation information, extracted from RFC 4340/42,
> is provided by this patch. All currently known features can be found in this
> table, along with their feature location, their default value, and type.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    9 ++--
>  net/dccp/feat.c      |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 120 insertions(+), 4 deletions(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
>  
> +
> +static int dccp_feat_default_value(u8 feat_num)
> +{
> +	int idx = dccp_feat_index(feat_num);
> +
> +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> +}

[acme@doppio ~]$ cat dd.c
#include <stdio.h>

int main(void)
{
	int idx = -2;

	printf("%d\n", idx < 0 ? : 10);
	printf("%d\n", idx < 0 ? idx : 10);
	return 0;
}
[acme@doppio ~]$ ./dd
1
-2
[acme@doppio ~]$

Which one do you want? The boolean result as the value to be returned or
the index if it is < 0?

I tried to check on the other 4 patches on this series to check if usage
clarified if it was correct, but there is no use of
dccp_feat_default_value() on this 5 patches, perhaps it could be
deferred to when it actually gets used?

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-22 14:21                                       ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 14:21 UTC (permalink / raw)
  To: dccp

Em Mon, Sep 22, 2008 at 09:21:54AM +0200, Gerrit Renker escreveu:
> A lookup table for feature-negotiation information, extracted from RFC 4340/42,
> is provided by this patch. All currently known features can be found in this
> table, along with their feature location, their default value, and type.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    9 ++--
>  net/dccp/feat.c      |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 120 insertions(+), 4 deletions(-)
> 
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
>  
> +
> +static int dccp_feat_default_value(u8 feat_num)
> +{
> +	int idx = dccp_feat_index(feat_num);
> +
> +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> +}

[acme@doppio ~]$ cat dd.c
#include <stdio.h>

int main(void)
{
	int idx = -2;

	printf("%d\n", idx < 0 ? : 10);
	printf("%d\n", idx < 0 ? idx : 10);
	return 0;
}
[acme@doppio ~]$ ./dd
1
-2
[acme@doppio ~]$

Which one do you want? The boolean result as the value to be returned or
the index if it is < 0?

I tried to check on the other 4 patches on this series to check if usage
clarified if it was correct, but there is no use of
dccp_feat_default_value() on this 5 patches, perhaps it could be
deferred to when it actually gets used?

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-22 15:45                                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22 15:45 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, davem, dccp, netdev

| > --- a/include/linux/dccp.h
| > +++ b/include/linux/dccp.h
| >  
| > +
| > +static int dccp_feat_default_value(u8 feat_num)
| > +{
| > +	int idx = dccp_feat_index(feat_num);
| > +
| > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
| > +}
| 
| [acme@doppio ~]$ cat dd.c
| #include <stdio.h>
| 
| int main(void)
| {
| 	int idx = -2;
| 
| 	printf("%d\n", idx < 0 ? : 10);
| 	printf("%d\n", idx < 0 ? idx : 10);
| 	return 0;
| }
| [acme@doppio ~]$ ./dd
| 1
| -2
| [acme@doppio ~]$
| 
| Which one do you want? The boolean result as the value to be returned or
| the index if it is < 0?
| 
It is the first value. The test is only there to avoid accessing the
array with an invalid index, which would happen if an unknown `feat_num'
is passed - as for unknown features there is no default value.

| I tried to check on the other 4 patches on this series to check if usage
| clarified if it was correct, but there is no use of
| dccp_feat_default_value() on this 5 patches, perhaps it could be
| deferred to when it actually gets used?
| 
Yes thanks, while I have ensured that all patches are bisectable, a few
functions may be declared where the logical fit was better. I will place
it where it is first used, in the patch entitled "dccp: Registration
routines for changing feature values"

I am waiting before resubmitting - please take a look at patches 3-5 as well.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-22 15:45                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-22 15:45 UTC (permalink / raw)
  To: dccp

| > --- a/include/linux/dccp.h
| > +++ b/include/linux/dccp.h
| >  
| > +
| > +static int dccp_feat_default_value(u8 feat_num)
| > +{
| > +	int idx = dccp_feat_index(feat_num);
| > +
| > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
| > +}
| 
| [acme@doppio ~]$ cat dd.c
| #include <stdio.h>
| 
| int main(void)
| {
| 	int idx = -2;
| 
| 	printf("%d\n", idx < 0 ? : 10);
| 	printf("%d\n", idx < 0 ? idx : 10);
| 	return 0;
| }
| [acme@doppio ~]$ ./dd
| 1
| -2
| [acme@doppio ~]$
| 
| Which one do you want? The boolean result as the value to be returned or
| the index if it is < 0?
| 
It is the first value. The test is only there to avoid accessing the
array with an invalid index, which would happen if an unknown `feat_num'
is passed - as for unknown features there is no default value.

| I tried to check on the other 4 patches on this series to check if usage
| clarified if it was correct, but there is no use of
| dccp_feat_default_value() on this 5 patches, perhaps it could be
| deferred to when it actually gets used?
| 
Yes thanks, while I have ensured that all patches are bisectable, a few
functions may be declared where the logical fit was better. I will place
it where it is first used, in the patch entitled "dccp: Registration
routines for changing feature values"

I am waiting before resubmitting - please take a look at patches 3-5 as well.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-22 16:49                                           ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 16:49 UTC (permalink / raw)
  To: Gerrit Renker, Arnaldo Carvalho de Melo, davem, dccp, netdev

Em Mon, Sep 22, 2008 at 05:45:54PM +0200, Gerrit Renker escreveu:
> | > --- a/include/linux/dccp.h
> | > +++ b/include/linux/dccp.h
> | >  
> | > +
> | > +static int dccp_feat_default_value(u8 feat_num)
> | > +{
> | > +	int idx = dccp_feat_index(feat_num);
> | > +
> | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> | > +}
> | 
> | [acme@doppio ~]$ cat dd.c
> | #include <stdio.h>
> | 
> | int main(void)
> | {
> | 	int idx = -2;
> | 
> | 	printf("%d\n", idx < 0 ? : 10);
> | 	printf("%d\n", idx < 0 ? idx : 10);
> | 	return 0;
> | }
> | [acme@doppio ~]$ ./dd
> | 1
> | -2
> | [acme@doppio ~]$
> | 
> | Which one do you want? The boolean result as the value to be returned or
> | the index if it is < 0?
> | 
> It is the first value. The test is only there to avoid accessing the
> array with an invalid index, which would happen if an unknown `feat_num'
> is passed - as for unknown features there is no default value.
> 
> | I tried to check on the other 4 patches on this series to check if usage
> | clarified if it was correct, but there is no use of
> | dccp_feat_default_value() on this 5 patches, perhaps it could be
> | deferred to when it actually gets used?
> | 
> Yes thanks, while I have ensured that all patches are bisectable, a few
> functions may be declared where the logical fit was better. I will place
> it where it is first used, in the patch entitled "dccp: Registration
> routines for changing feature values"
> 
> I am waiting before resubmitting - please take a look at patches 3-5 as well.

I looked at the other patches, should be OK.

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-22 16:49                                           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 16:49 UTC (permalink / raw)
  To: dccp

Em Mon, Sep 22, 2008 at 05:45:54PM +0200, Gerrit Renker escreveu:
> | > --- a/include/linux/dccp.h
> | > +++ b/include/linux/dccp.h
> | >  
> | > +
> | > +static int dccp_feat_default_value(u8 feat_num)
> | > +{
> | > +	int idx = dccp_feat_index(feat_num);
> | > +
> | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> | > +}
> | 
> | [acme@doppio ~]$ cat dd.c
> | #include <stdio.h>
> | 
> | int main(void)
> | {
> | 	int idx = -2;
> | 
> | 	printf("%d\n", idx < 0 ? : 10);
> | 	printf("%d\n", idx < 0 ? idx : 10);
> | 	return 0;
> | }
> | [acme@doppio ~]$ ./dd
> | 1
> | -2
> | [acme@doppio ~]$
> | 
> | Which one do you want? The boolean result as the value to be returned or
> | the index if it is < 0?
> | 
> It is the first value. The test is only there to avoid accessing the
> array with an invalid index, which would happen if an unknown `feat_num'
> is passed - as for unknown features there is no default value.
> 
> | I tried to check on the other 4 patches on this series to check if usage
> | clarified if it was correct, but there is no use of
> | dccp_feat_default_value() on this 5 patches, perhaps it could be
> | deferred to when it actually gets used?
> | 
> Yes thanks, while I have ensured that all patches are bisectable, a few
> functions may be declared where the logical fit was better. I will place
> it where it is first used, in the patch entitled "dccp: Registration
> routines for changing feature values"
> 
> I am waiting before resubmitting - please take a look at patches 3-5 as well.

I looked at the other patches, should be OK.

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-22 17:00                                           ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 17:00 UTC (permalink / raw)
  To: Gerrit Renker, davem, dccp, netdev

Em Mon, Sep 22, 2008 at 05:45:54PM +0200, Gerrit Renker escreveu:
> | > --- a/include/linux/dccp.h
> | > +++ b/include/linux/dccp.h
> | >  
> | > +
> | > +static int dccp_feat_default_value(u8 feat_num)
> | > +{
> | > +	int idx = dccp_feat_index(feat_num);
> | > +
> | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> | > +}
> | 
> | [acme@doppio ~]$ cat dd.c
> | #include <stdio.h>
> | 
> | int main(void)
> | {
> | 	int idx = -2;
> | 
> | 	printf("%d\n", idx < 0 ? : 10);
> | 	printf("%d\n", idx < 0 ? idx : 10);
> | 	return 0;
> | }
> | [acme@doppio ~]$ ./dd
> | 1
> | -2
> | [acme@doppio ~]$
> | 
> | Which one do you want? The boolean result as the value to be returned or
> | the index if it is < 0?
> | 
> It is the first value. The test is only there to avoid accessing the
> array with an invalid index, which would happen if an unknown `feat_num'
> is passed - as for unknown features there is no default value.

The above explanation would be good to have as a comment, as it was not
so obvious from a first sight. I think that even having it explicit
would be clearer:

return idx < 0 ? 1 : dccp_feat_table[idx].default_value;

But then, if an unknown feat num is passed shouldn't the code bailout in
some other fashion than returning the result of a boolean expression and
not accessing the defaults table?

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-22 17:00                                           ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-22 17:00 UTC (permalink / raw)
  To: dccp

Em Mon, Sep 22, 2008 at 05:45:54PM +0200, Gerrit Renker escreveu:
> | > --- a/include/linux/dccp.h
> | > +++ b/include/linux/dccp.h
> | >  
> | > +
> | > +static int dccp_feat_default_value(u8 feat_num)
> | > +{
> | > +	int idx = dccp_feat_index(feat_num);
> | > +
> | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> | > +}
> | 
> | [acme@doppio ~]$ cat dd.c
> | #include <stdio.h>
> | 
> | int main(void)
> | {
> | 	int idx = -2;
> | 
> | 	printf("%d\n", idx < 0 ? : 10);
> | 	printf("%d\n", idx < 0 ? idx : 10);
> | 	return 0;
> | }
> | [acme@doppio ~]$ ./dd
> | 1
> | -2
> | [acme@doppio ~]$
> | 
> | Which one do you want? The boolean result as the value to be returned or
> | the index if it is < 0?
> | 
> It is the first value. The test is only there to avoid accessing the
> array with an invalid index, which would happen if an unknown `feat_num'
> is passed - as for unknown features there is no default value.

The above explanation would be good to have as a comment, as it was not
so obvious from a first sight. I think that even having it explicit
would be clearer:

return idx < 0 ? 1 : dccp_feat_table[idx].default_value;

But then, if an unknown feat num is passed shouldn't the code bailout in
some other fashion than returning the result of a boolean expression and
not accessing the defaults table?

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-23  3:20                                           ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-23  3:20 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 22 Sep 2008 17:45:54 +0200

> I am waiting before resubmitting - please take a look at patches 3-5 as well.

This stuff looks good enough to apply when you give me the resubmission
including Arnaldo's feedback.

Thanks.


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-23  3:20                                           ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-09-23  3:20 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 22 Sep 2008 17:45:54 +0200

> I am waiting before resubmitting - please take a look at patches 3-5 as well.

This stuff looks good enough to apply when you give me the resubmission
including Arnaldo's feedback.

Thanks.


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-24  4:41                                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-24  4:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, davem, dccp, netdev

| > | > --- a/include/linux/dccp.h
| > | > +++ b/include/linux/dccp.h
| > | >  
| > | > +
| > | > +static int dccp_feat_default_value(u8 feat_num)
| > | > +{
| > | > +	int idx = dccp_feat_index(feat_num);
| > | > +
| > | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
| > | > +}
<snip>
| > | 
| > It is the first value. The test is only there to avoid accessing the
| > array with an invalid index, which would happen if an unknown `feat_num'
| > is passed - as for unknown features there is no default value.
| 
| The above explanation would be good to have as a comment, as it was not
| so obvious from a first sight. I think that even having it explicit
| would be clearer:
| 
| return idx < 0 ? 1 : dccp_feat_table[idx].default_value;
| 
| But then, if an unknown feat num is passed shouldn't the code bailout in
| some other fashion than returning the result of a boolean expression and
| not accessing the defaults table?
| 
Yes thank you. It is necessary to check this, since only in the current
state of code the use of the function is consistent.  If the code gets
changed later on then there will be no warning.

I have worked on this function yesterday evening with regard to above
feedback. If you could either check again when the patch is submitted
later, or have a look at the online version in the test tree on
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=b0708121bfeb309db88e1b3a97cf851069bcafe1


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-24  4:41                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-24  4:41 UTC (permalink / raw)
  To: dccp

| > | > --- a/include/linux/dccp.h
| > | > +++ b/include/linux/dccp.h
| > | >  
| > | > +
| > | > +static int dccp_feat_default_value(u8 feat_num)
| > | > +{
| > | > +	int idx = dccp_feat_index(feat_num);
| > | > +
| > | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
| > | > +}
<snip>
| > | 
| > It is the first value. The test is only there to avoid accessing the
| > array with an invalid index, which would happen if an unknown `feat_num'
| > is passed - as for unknown features there is no default value.
| 
| The above explanation would be good to have as a comment, as it was not
| so obvious from a first sight. I think that even having it explicit
| would be clearer:
| 
| return idx < 0 ? 1 : dccp_feat_table[idx].default_value;
| 
| But then, if an unknown feat num is passed shouldn't the code bailout in
| some other fashion than returning the result of a boolean expression and
| not accessing the defaults table?
| 
Yes thank you. It is necessary to check this, since only in the current
state of code the use of the function is consistent.  If the code gets
changed later on then there will be no warning.

I have worked on this function yesterday evening with regard to above
feedback. If you could either check again when the patch is submitted
later, or have a look at the online version in the test tree on
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;h°708121bfeb309db88e1b3a97cf851069bcafe1


^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
@ 2008-09-24  5:18                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-24  5:18 UTC (permalink / raw)
  To: David Miller; +Cc: acme, dccp, netdev

This is the first revised patch, the second follows subsequently.

Changes relative to v1: 
migrated function `dccp_default_value' moved to where it is first used 

>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Implement lookup table for feature-negotiation information

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this 
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  108 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+), 4 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,73 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +104,45 @@ static int dccp_feat_clone_sp_val(dccp_f
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +759,8 @@ const char *dccp_feat_name(const u8 feat
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-24  5:18                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-24  5:18 UTC (permalink / raw)
  To: dccp

This is the first revised patch, the second follows subsequently.

Changes relative to v1: 
migrated function `dccp_default_value' moved to where it is first used 

>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Implement lookup table for feature-negotiation information

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this 
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  108 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+), 4 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,73 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +104,45 @@ static int dccp_feat_clone_sp_val(dccp_f
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type = FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new = NULL)
+		return NULL;
+
+	if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +759,8 @@ const char *dccp_feat_name(const u8 feat
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-09-24  5:23                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-24  5:23 UTC (permalink / raw)
  To: David Miller, acme, dccp, netdev

This is the second/other revised patch for this set [v2 of 1/5].

Changes relative to v1: copied Arnaldos suggested layout and updated the
struct documentation accordingly. Compile-tested the result.

>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Basic data structure for feature negotiation

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most 
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo who streamlined the field layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c |   14 ++++++++++++
 net/dccp/feat.h |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-09-24  5:23                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-09-24  5:23 UTC (permalink / raw)
  To: dccp

This is the second/other revised patch for this set [v2 of 1/5].

Changes relative to v1: copied Arnaldos suggested layout and updated the
struct documentation accordingly. Compile-tested the result.

>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
dccp: Basic data structure for feature negotiation

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most 
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo who streamlined the field layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c |   14 ++++++++++++
 net/dccp/feat.h |   61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec = NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-09-24 13:58                                               ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-24 13:58 UTC (permalink / raw)
  To: Gerrit Renker, davem, dccp, netdev

Em Wed, Sep 24, 2008 at 06:41:20AM +0200, Gerrit Renker escreveu:
> | > | > --- a/include/linux/dccp.h
> | > | > +++ b/include/linux/dccp.h
> | > | >  
> | > | > +
> | > | > +static int dccp_feat_default_value(u8 feat_num)
> | > | > +{
> | > | > +	int idx = dccp_feat_index(feat_num);
> | > | > +
> | > | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> | > | > +}
> <snip>
> | > | 
> | > It is the first value. The test is only there to avoid accessing the
> | > array with an invalid index, which would happen if an unknown `feat_num'
> | > is passed - as for unknown features there is no default value.
> | 
> | The above explanation would be good to have as a comment, as it was not
> | so obvious from a first sight. I think that even having it explicit
> | would be clearer:
> | 
> | return idx < 0 ? 1 : dccp_feat_table[idx].default_value;
> | 
> | But then, if an unknown feat num is passed shouldn't the code bailout in
> | some other fashion than returning the result of a boolean expression and
> | not accessing the defaults table?
> | 
> Yes thank you. It is necessary to check this, since only in the current
> state of code the use of the function is consistent.  If the code gets
> changed later on then there will be no warning.
> 
> I have worked on this function yesterday evening with regard to above
> feedback. If you could either check again when the patch is submitted
> later, or have a look at the online version in the test tree on
> http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=b0708121bfeb309db88e1b3a97cf851069bcafe1

Looks ok now, thanks.

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-24 13:58                                               ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-24 13:58 UTC (permalink / raw)
  To: dccp

Em Wed, Sep 24, 2008 at 06:41:20AM +0200, Gerrit Renker escreveu:
> | > | > --- a/include/linux/dccp.h
> | > | > +++ b/include/linux/dccp.h
> | > | >  
> | > | > +
> | > | > +static int dccp_feat_default_value(u8 feat_num)
> | > | > +{
> | > | > +	int idx = dccp_feat_index(feat_num);
> | > | > +
> | > | > +	return idx < 0 ? : dccp_feat_table[idx].default_value;
> | > | > +}
> <snip>
> | > | 
> | > It is the first value. The test is only there to avoid accessing the
> | > array with an invalid index, which would happen if an unknown `feat_num'
> | > is passed - as for unknown features there is no default value.
> | 
> | The above explanation would be good to have as a comment, as it was not
> | so obvious from a first sight. I think that even having it explicit
> | would be clearer:
> | 
> | return idx < 0 ? 1 : dccp_feat_table[idx].default_value;
> | 
> | But then, if an unknown feat num is passed shouldn't the code bailout in
> | some other fashion than returning the result of a boolean expression and
> | not accessing the defaults table?
> | 
> Yes thank you. It is necessary to check this, since only in the current
> state of code the use of the function is consistent.  If the code gets
> changed later on then there will be no warning.
> 
> I have worked on this function yesterday evening with regard to above
> feedback. If you could either check again when the patch is submitted
> later, or have a look at the online version in the test tree on
> http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;h∞708121bfeb309db88e1b3a97cf851069bcafe1

Looks ok now, thanks.

- Arnaldo
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 1/5] dccp: Basic data structure for feature negotiation
  2008-09-24  5:23                                               ` Gerrit Renker
@ 2008-09-24 13:59                                                 ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-24 13:59 UTC (permalink / raw)
  To: Gerrit Renker, David Miller, dccp, netdev

Em Wed, Sep 24, 2008 at 07:23:05AM +0200, Gerrit Renker escreveu:
> This is the second/other revised patch for this set [v2 of 1/5].
> 
> Changes relative to v1: copied Arnaldos suggested layout and updated the
> struct documentation accordingly. Compile-tested the result.
> 
> >>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> dccp: Basic data structure for feature negotiation
> 
> This patch prepares for the new and extended feature-negotiation routines.
> 
> The following feature-negotiation data structures are provided:
> 	* a container for the various (SP or NN) values,
> 	* symbolic state names to track feature states,
> 	* an entry struct which holds all current information together,
> 	* elementary functions to fill in and process these structures.
> 
> Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
> that if multiple options of the same type are present, they are processed in the
> order of their appearance in the packet; which means that this order needs to be
> preserved in the local data structure (the later insertion code also respects
> this order).
> 
> The struct list_head has been chosen for the following reasons: the most 
> frequent operations are
>  * add new entry at tail (when receiving Change or setting socket options);
>  * delete entry (when Confirm has been received);
>  * deep copy of entire list (cloning from listening socket onto request socket).
> 
> The NN value has been set to 64 bit, which is a currently sufficient upper limit
> (Sequence Window feature has 48 bit).
> 
> Thanks to Arnaldo who streamlined the field layout of the entry struct.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 1/5] dccp: Basic data structure for feature
@ 2008-09-24 13:59                                                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-24 13:59 UTC (permalink / raw)
  To: dccp

Em Wed, Sep 24, 2008 at 07:23:05AM +0200, Gerrit Renker escreveu:
> This is the second/other revised patch for this set [v2 of 1/5].
> 
> Changes relative to v1: copied Arnaldos suggested layout and updated the
> struct documentation accordingly. Compile-tested the result.
> 
> >>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> dccp: Basic data structure for feature negotiation
> 
> This patch prepares for the new and extended feature-negotiation routines.
> 
> The following feature-negotiation data structures are provided:
> 	* a container for the various (SP or NN) values,
> 	* symbolic state names to track feature states,
> 	* an entry struct which holds all current information together,
> 	* elementary functions to fill in and process these structures.
> 
> Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
> that if multiple options of the same type are present, they are processed in the
> order of their appearance in the packet; which means that this order needs to be
> preserved in the local data structure (the later insertion code also respects
> this order).
> 
> The struct list_head has been chosen for the following reasons: the most 
> frequent operations are
>  * add new entry at tail (when receiving Change or setting socket options);
>  * delete entry (when Confirm has been received);
>  * deep copy of entire list (cloning from listening socket onto request socket).
> 
> The NN value has been set to 64 bit, which is a currently sufficient upper limit
> (Sequence Window feature has 48 bit).
> 
> Thanks to Arnaldo who streamlined the field layout of the entry struct.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-24  5:18                                             ` v2 [PATCH 2/5] dccp: Implement lookup table for Gerrit Renker
@ 2008-09-24 14:01                                               ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-24 14:01 UTC (permalink / raw)
  To: Gerrit Renker, David Miller, dccp, netdev

Em Wed, Sep 24, 2008 at 07:18:23AM +0200, Gerrit Renker escreveu:
> This is the first revised patch, the second follows subsequently.
> 
> Changes relative to v1: 
> migrated function `dccp_default_value' moved to where it is first used 
> 
> >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> dccp: Implement lookup table for feature-negotiation information
> 
> A lookup table for feature-negotiation information, extracted from RFC 4340/42,
> is provided by this patch. All currently known features can be found in this 
> table, along with their feature location, their default value, and type.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Lets make progress, in the future lets try and remove hardcoded specific CCID
tests.

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 2/5] dccp: Implement lookup table for
@ 2008-09-24 14:01                                               ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-09-24 14:01 UTC (permalink / raw)
  To: dccp

Em Wed, Sep 24, 2008 at 07:18:23AM +0200, Gerrit Renker escreveu:
> This is the first revised patch, the second follows subsequently.
> 
> Changes relative to v1: 
> migrated function `dccp_default_value' moved to where it is first used 
> 
> >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Patch v2 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
> dccp: Implement lookup table for feature-negotiation information
> 
> A lookup table for feature-negotiation information, extracted from RFC 4340/42,
> is provided by this patch. All currently known features can be found in this 
> table, along with their feature location, their default value, and type.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Lets make progress, in the future lets try and remove hardcoded specific CCID
tests.

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/5] dccp: First part of feature-negotiation patch set
@ 2008-10-02  5:05                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-02  5:05 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, David Miller, dccp, netdev

Hi Dave,

how shall we remain regarding this patch set, will you be
indicating when there is time enough to look at the next
part, or would it be easier to make this periodical (e.g.
one small set per each week / two weeks)?

Would you like me to re-send [3/5]...[5/5] as they are not on
http://patchwork.ozlabs.org/project/netdev/list/

Best regards
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/5] dccp: First part of feature-negotiation patch set
@ 2008-10-02  5:05                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-02  5:05 UTC (permalink / raw)
  To: dccp

Hi Dave,

how shall we remain regarding this patch set, will you be
indicating when there is time enough to look at the next
part, or would it be easier to make this periodical (e.g.
one small set per each week / two weeks)?

Would you like me to re-send [3/5]...[5/5] as they are not on
http://patchwork.ozlabs.org/project/netdev/list/

Best regards
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 0/5] dccp: First part of feature-negotiation patch set
  2008-10-02  5:05                                                   ` Gerrit Renker
@ 2008-10-02 19:52                                                     ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-02 19:52 UTC (permalink / raw)
  To: gerrit; +Cc: acme, dccp, netdev


Please resend all 5 patches, that's what I've waiting
for you to do.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 0/5] dccp: First part of feature-negotiation patch set
@ 2008-10-02 19:52                                                     ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-02 19:52 UTC (permalink / raw)
  To: dccp


Please resend all 5 patches, that's what I've waiting
for you to do.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
@ 2008-10-04  9:13                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Please find below the revised patch set, addressing earlier review.


Changes relative to revision 1
------------------------------
 * [1/5] streamlined field layout reducing the size per each entry;
 * [2/5] migration of function 'dccp_default_value' to a later in the set
         where it is first used.


Commit summary
--------------
This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.


List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  


Patch stats:
------------
 include/linux/dccp.h |   13 +-
 net/dccp/dccp.h      |    5 
 net/dccp/feat.c      |  270 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   62 +++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 
 net/dccp/ipv6.c      |    4 
 net/dccp/minisocks.c |    7 +
 net/dccp/proto.c     |    3 
 9 files changed, 359 insertions(+), 11 deletions(-)

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=3136a0e06ba53fa4be7114c3e8148c96cc8cf6b1


^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
@ 2008-10-04  9:13                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: dccp

Please find below the revised patch set, addressing earlier review.


Changes relative to revision 1
------------------------------
 * [1/5] streamlined field layout reducing the size per each entry;
 * [2/5] migration of function 'dccp_default_value' to a later in the set
         where it is first used.


Commit summary
--------------
This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.


List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  


Patch stats:
------------
 include/linux/dccp.h |   13 +-
 net/dccp/dccp.h      |    5 
 net/dccp/feat.c      |  270 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   62 +++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 
 net/dccp/ipv6.c      |    4 
 net/dccp/minisocks.c |    7 +
 net/dccp/proto.c     |    3 
 9 files changed, 359 insertions(+), 11 deletions(-)

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;h136a0e06ba53fa4be7114c3e8148c96cc8cf6b1

--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
  2008-09-22  7:21                                   ` Gerrit Renker
@ 2008-10-04  9:13                                                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo, who contributed the streamlined layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.c |   14 ++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-10-04  9:13                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo, who contributed the streamlined layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.c |   14 ++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,20 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec = NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-10-04  9:13                                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,73 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +104,45 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +759,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
@ 2008-10-04  9:13                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/dccp.h |    9 ++--
 net/dccp/feat.c      |  108 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,73 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -37,6 +104,45 @@ static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 	return 0;
 }
 
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type = FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new = NULL)
+		return NULL;
+
+	if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -653,6 +759,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
  2008-09-22  7:21                                       ` Gerrit Renker
@ 2008-10-04  9:13                                                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Thanks to Arnaldo for suggestions to improve the code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -143,6 +143,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 	}
 }
 
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num == feat && entry->is_local == local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval == NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
@ 2008-10-04  9:13                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: dccp

This adds list fields and list management functions for the new feature
negotiation implementation. The new code is kept in parallel to the old
code, until removed at the end of the patch set.

Thanks to Arnaldo for suggestions to improve the code.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |  129 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 129 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -143,6 +143,135 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 	}
 }
 
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num = feat_num && entry->is_local = is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
+
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num = feat && entry->is_local = local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval = NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
  2008-09-22  7:21                                         ` Gerrit Renker
@ 2008-10-04  9:13                                                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 ++++
 net/dccp/dccp.h      |    3 ++-
 net/dccp/feat.c      |   19 +++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 --
 net/dccp/ipv4.c      |    3 ++-
 net/dccp/ipv6.c      |    3 ++-
 net/dccp/minisocks.c |    7 ++++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 37 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -272,6 +272,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new == NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -96,6 +96,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type == DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
@ 2008-10-04  9:13                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 ++++
 net/dccp/dccp.h      |    3 ++-
 net/dccp/feat.c      |   19 +++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 --
 net/dccp/ipv4.c      |    3 ++-
 net/dccp/ipv6.c      |    3 ++-
 net/dccp/minisocks.c |    7 ++++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 37 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -272,6 +272,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new = NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -96,6 +96,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type = DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
  2008-09-22  7:21                                           ` Gerrit Renker
@ 2008-10-04  9:13                                                                 ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h  |    2 ++
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 4 files changed, 5 insertions(+), 1 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
@ 2008-10-04  9:13                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-04  9:13 UTC (permalink / raw)
  To: dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h  |    2 ++
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 4 files changed, 5 insertions(+), 1 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
  2008-10-04  9:13                                                       ` Gerrit Renker
@ 2008-10-05 16:13                                                         ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-05 16:13 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  4 Oct 2008 11:13:21 +0200

> Please find below the revised patch set, addressing earlier review.

After patch 1:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:28: warning: ‘dccp_feat_clone_sp_val’ defined but not used

After patch 2:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:118: warning: ‘dccp_feat_clone_entry’ defined but not used
net/dccp/feat.c:139: warning: ‘dccp_feat_entry_destructor’ defined but not used

After patch 3:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:118: warning: ‘dccp_feat_clone_entry’ defined but not used
net/dccp/feat.c:157: warning: ‘dccp_feat_list_lookup’ defined but not used
net/dccp/feat.c:208: warning: ‘dccp_feat_push_change’ defined but not used
net/dccp/feat.c:255: warning: ‘dccp_push_empty_confirm’ defined but not used

After patch 4:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:157: warning: ‘dccp_feat_list_lookup’ defined but not used
net/dccp/feat.c:208: warning: ‘dccp_feat_push_change’ defined but not used
net/dccp/feat.c:255: warning: ‘dccp_push_empty_confirm’ defined but not used

And patch 5 makes no modifications to feat.c so things don't improve.

This can't happen.

You have to split up your patches more intelligently, such that they
are fully bisectable and at each patch point there are no new warnings
or known bugs added.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying
@ 2008-10-05 16:13                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-05 16:13 UTC (permalink / raw)
  To: dccp

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 1498 bytes --]

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  4 Oct 2008 11:13:21 +0200

> Please find below the revised patch set, addressing earlier review.

After patch 1:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:28: warning: ‘dccp_feat_clone_sp_val’ defined but not used

After patch 2:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:118: warning: ‘dccp_feat_clone_entry’ defined but not used
net/dccp/feat.c:139: warning: ‘dccp_feat_entry_destructor’ defined but not used

After patch 3:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:118: warning: ‘dccp_feat_clone_entry’ defined but not used
net/dccp/feat.c:157: warning: ‘dccp_feat_list_lookup’ defined but not used
net/dccp/feat.c:208: warning: ‘dccp_feat_push_change’ defined but not used
net/dccp/feat.c:255: warning: ‘dccp_push_empty_confirm’ defined but not used

After patch 4:

  CC [M]  net/dccp/feat.o
net/dccp/feat.c:157: warning: ‘dccp_feat_list_lookup’ defined but not used
net/dccp/feat.c:208: warning: ‘dccp_feat_push_change’ defined but not used
net/dccp/feat.c:255: warning: ‘dccp_push_empty_confirm’ defined but not used

And patch 5 makes no modifications to feat.c so things don't improve.

This can't happen.

You have to split up your patches more intelligently, such that they
are fully bisectable and at each patch point there are no new warnings
or known bugs added.
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·qÊÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
  2008-10-04  9:13                                                       ` Gerrit Renker
@ 2008-10-06  4:14                                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-06  4:14 UTC (permalink / raw)
  To: David Miller; +Cc: dccp, netdev

| You have to split up your patches more intelligently, such that they
| are fully bisectable and at each patch point there are no new warnings
| or known bugs added.
| 
OK will do. I understand that this means resubmitting the full set.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying
@ 2008-10-06  4:14                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-06  4:14 UTC (permalink / raw)
  To: dccp

| You have to split up your patches more intelligently, such that they
| are fully bisectable and at each patch point there are no new warnings
| or known bugs added.
| 
OK will do. I understand that this means resubmitting the full set.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
@ 2008-10-11  7:31                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

Hi Dave,

please find below the revised patch set.

Thank you for taking the time to look through.

If we could keep this set going on as a low-key background process, that
would be great. I found the pace not only more reviewer-friendly, but also
more submitter-friendly, so it is in fact a good choice.

Regards
Gerrit


Changes relative to revision 2
------------------------------
 * reordered patches to eliminate build warnings (reducing patch sizes); 
 * in addition, sparse-build warnings were also eliminated;
 * all patches again verified to compile without build errors.


Changes relative to revision 1
------------------------------
 * [1/5] streamlined field layout reducing the size per each entry;
 * [2/5] migration of function 'dccp_default_value' to a later in the set
         where it is first used.


Commit summary
--------------
This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.


List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=6370e843d9977eff8f2a1bbb18020d5fbc36b202

Patch stats:
------------
 include/linux/dccp.h |   13 ++-
 net/dccp/dccp.h      |    5 +
 net/dccp/feat.c      |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   62 ++++++++++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 -
 net/dccp/ipv6.c      |    4 -
 net/dccp/minisocks.c |    7 +-
 net/dccp/proto.c     |    3 
 9 files changed, 256 insertions(+), 11 deletions(-)


^ permalink raw reply	[flat|nested] 484+ messages in thread

* v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data
@ 2008-10-11  7:31                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find below the revised patch set.

Thank you for taking the time to look through.

If we could keep this set going on as a low-key background process, that
would be great. I found the pace not only more reviewer-friendly, but also
more submitter-friendly, so it is in fact a good choice.

Regards
Gerrit


Changes relative to revision 2
------------------------------
 * reordered patches to eliminate build warnings (reducing patch sizes); 
 * in addition, sparse-build warnings were also eliminated;
 * all patches again verified to compile without build errors.


Changes relative to revision 1
------------------------------
 * [1/5] streamlined field layout reducing the size per each entry;
 * [2/5] migration of function 'dccp_default_value' to a later in the set
         where it is first used.


Commit summary
--------------
This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.


List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;hc70e843d9977eff8f2a1bbb18020d5fbc36b202

Patch stats:
------------
 include/linux/dccp.h |   13 ++-
 net/dccp/dccp.h      |    5 +
 net/dccp/feat.c      |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   62 ++++++++++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 -
 net/dccp/ipv6.c      |    4 -
 net/dccp/minisocks.c |    7 +-
 net/dccp/proto.c     |    3 
 9 files changed, 256 insertions(+), 11 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
  2008-09-22  7:21                                   ` Gerrit Renker
@ 2008-10-11  7:31                                                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo, who contributed the streamlined layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-10-11  7:31                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo, who contributed the streamlined layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-10-11  7:31                                                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/dccp.h |    9 +++++----
 net/dccp/feat.c      |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,43 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -639,6 +676,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation
@ 2008-10-11  7:31                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/dccp.h |    9 +++++----
 net/dccp/feat.c      |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,43 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -639,6 +676,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
  2008-09-22  7:21                                       ` Gerrit Renker
@ 2008-10-11  7:31                                                                 ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This adds list initial fields and list management functions for the new
feature negotiation implementation.

Thanks to Arnaldo for suggestions and improvements.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -441,6 +441,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -60,6 +60,79 @@ static const struct {
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
@ 2008-10-11  7:31                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: dccp

This adds list initial fields and list management functions for the new
feature negotiation implementation.

Thanks to Arnaldo for suggestions and improvements.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -441,6 +441,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -60,6 +60,79 @@ static const struct {
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
  2008-09-22  7:21                                         ` Gerrit Renker
@ 2008-10-11  7:31                                                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +++
 net/dccp/dccp.h      |    3 +-
 net/dccp/feat.c      |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 -
 net/dccp/ipv4.c      |    3 +-
 net/dccp/ipv6.c      |    3 +-
 net/dccp/minisocks.c |    7 +++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 73 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num)
 	return dccp_feat_table[idx].reconciliation;
 }
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
 	if (unlikely(val == NULL))
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 	memset(val, 0, sizeof(*val));
 }
 
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
 static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 {
 	if (entry != NULL) {
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new == NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -96,6 +96,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type == DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
@ 2008-10-11  7:31                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:31 UTC (permalink / raw)
  To: dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +++
 net/dccp/dccp.h      |    3 +-
 net/dccp/feat.c      |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 -
 net/dccp/ipv4.c      |    3 +-
 net/dccp/ipv6.c      |    3 +-
 net/dccp/minisocks.c |    7 +++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 73 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num)
 	return dccp_feat_table[idx].reconciliation;
 }
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec = NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
 	if (unlikely(val = NULL))
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 	memset(val, 0, sizeof(*val));
 }
 
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type = FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new = NULL)
+		return NULL;
+
+	if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
 static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 {
 	if (entry != NULL) {
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new = NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -96,6 +96,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type = DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
  2008-09-22  7:21                                           ` Gerrit Renker
@ 2008-10-11  7:32                                                                     ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:32 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 3 files changed, 3 insertions(+), 1 deletions(-)

--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
@ 2008-10-11  7:32                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-11  7:32 UTC (permalink / raw)
  To: dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 3 files changed, 3 insertions(+), 1 deletions(-)

--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
  2008-10-11  7:31                                                           ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data Gerrit Renker
@ 2008-10-11 18:07                                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-11 18:07 UTC (permalink / raw)
  To: gerrit; +Cc: netdev, dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 11 Oct 2008 09:31:13 +0200

> Thank you for taking the time to look through.
> 
> If we could keep this set going on as a low-key background process, that
> would be great. I found the pace not only more reviewer-friendly, but also
> more submitter-friendly, so it is in fact a good choice.

Well, just FYI at this point, networking is closed for the 2.6.28
merge window.

So all of this stuff will have to wait until 2.6.29 and I'm won't be
creating a net-next-2.6 tree for 2.6.29 for at least a few weeks while
people should be fixing bugs in 2.6.28.

So all of this screwing around caused all of the pending DCCP work to
miss the 2.6.28 merge window.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying
@ 2008-10-11 18:07                                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-11 18:07 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 11 Oct 2008 09:31:13 +0200

> Thank you for taking the time to look through.
> 
> If we could keep this set going on as a low-key background process, that
> would be great. I found the pace not only more reviewer-friendly, but also
> more submitter-friendly, so it is in fact a good choice.

Well, just FYI at this point, networking is closed for the 2.6.28
merge window.

So all of this stuff will have to wait until 2.6.29 and I'm won't be
creating a net-next-2.6 tree for 2.6.29 for at least a few weeks while
people should be fixing bugs in 2.6.28.

So all of this screwing around caused all of the pending DCCP work to
miss the 2.6.28 merge window.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
  2008-10-11  7:31                                                           ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data Gerrit Renker
@ 2008-10-13 14:58                                                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-13 14:58 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, dccp

| > Thank you for taking the time to look through.
| > 
| > If we could keep this set going on as a low-key background process, that
| > would be great. I found the pace not only more reviewer-friendly, but also
| > more submitter-friendly, so it is in fact a good choice.
| 
| Well, just FYI at this point, networking is closed for the 2.6.28
| merge window.
| 
| So all of this stuff will have to wait until 2.6.29 and I'm won't be
| creating a net-next-2.6 tree for 2.6.29 for at least a few weeks while
| people should be fixing bugs in 2.6.28.
| 
The merge window is not a problem - as said, this can wait. 

When it would be okay to send the next instalment for review?

Do you want to wait with this until 2.6.29 - can you please indicate a time frame.

Thanks
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying
@ 2008-10-13 14:58                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-10-13 14:58 UTC (permalink / raw)
  To: dccp

| > Thank you for taking the time to look through.
| > 
| > If we could keep this set going on as a low-key background process, that
| > would be great. I found the pace not only more reviewer-friendly, but also
| > more submitter-friendly, so it is in fact a good choice.
| 
| Well, just FYI at this point, networking is closed for the 2.6.28
| merge window.
| 
| So all of this stuff will have to wait until 2.6.29 and I'm won't be
| creating a net-next-2.6 tree for 2.6.29 for at least a few weeks while
| people should be fixing bugs in 2.6.28.
| 
The merge window is not a problem - as said, this can wait. 

When it would be okay to send the next instalment for review?

Do you want to wait with this until 2.6.29 - can you please indicate a time frame.

Thanks
Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
  2008-10-11  7:31                                                           ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data Gerrit Renker
@ 2008-10-13 18:50                                                                 ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-13 18:50 UTC (permalink / raw)
  To: gerrit; +Cc: netdev, dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 13 Oct 2008 16:58:14 +0200

> When it would be okay to send the next instalment for review?
> 
> Do you want to wait with this until 2.6.29 - can you please indicate a time frame.

I should be openning up net-next-2.6 for 2.6.29 bound submissions in
about 2 weeks.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying
@ 2008-10-13 18:50                                                                 ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-10-13 18:50 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Mon, 13 Oct 2008 16:58:14 +0200

> When it would be okay to send the next instalment for review?
> 
> Do you want to wait with this until 2.6.29 - can you please indicate a time frame.

I should be openning up net-next-2.6 for 2.6.29 bound submissions in
about 2 weeks.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
@ 2008-11-05  6:51                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:51 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

Hi Dave,

as requested circa two weeks ago, I am now resending the first chunk of the
feature-negotiation patch set.

These patches are identical to the earlier submission.

Can you please let me know when it would be okay to submit the next
instalment of this series.

Gerrit


Changes relative to revision 2
------------------------------
 * reordered patches to eliminate build warnings (reducing patch sizes); 
 * in addition, sparse-build warnings were also eliminated;
 * all patches again verified to compile without build errors.


Changes relative to revision 1
------------------------------
 * [1/5] streamlined field layout reducing the size per each entry;
 * [2/5] migration of function 'dccp_default_value' to a later in the set
         where it is first used.


Commit summary
--------------
This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.


List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=228d610abf614d981cceabab3c27c1d3837e43ca

Patch stats:
------------
 include/linux/dccp.h |   13 ++-
 net/dccp/dccp.h      |    5 +
 net/dccp/feat.c      |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   62 ++++++++++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 -
 net/dccp/ipv6.c      |    4 -
 net/dccp/minisocks.c |    7 +-
 net/dccp/proto.c     |    3 
 9 files changed, 256 insertions(+), 11 deletions(-)


^ permalink raw reply	[flat|nested] 484+ messages in thread

* v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I -
@ 2008-11-05  6:51                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:51 UTC (permalink / raw)
  To: dccp

Hi Dave,

as requested circa two weeks ago, I am now resending the first chunk of the
feature-negotiation patch set.

These patches are identical to the earlier submission.

Can you please let me know when it would be okay to submit the next
instalment of this series.

Gerrit


Changes relative to revision 2
------------------------------
 * reordered patches to eliminate build warnings (reducing patch sizes); 
 * in addition, sparse-build warnings were also eliminated;
 * all patches again verified to compile without build errors.


Changes relative to revision 1
------------------------------
 * [1/5] streamlined field layout reducing the size per each entry;
 * [2/5] migration of function 'dccp_default_value' to a later in the set
         where it is first used.


Commit summary
--------------
This is the first set of the feature negotiation patches. These provide a 
self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup. Within these blocks, this is the first,
self-contained, set and its purpose is to provide
 (a) the underlying datastructures
 (b) initialisation and cleanup routines for the new datastructures.


List of patches in this set:
----------------------------
Patch #1: Provides the basic datastructure for feature negotiation. It gets 
          around the problem that feature-negotiation values have no uniform
	  type - they can be 48-bit numbers, single characters, 2-byte integers
	  or a list of unsigned chars.
Patch #2: Provides a lookup-table for the different negotiable features.
Patch #3: Adds list management for the list keeping the negotiation-options.
Patch #4: Initialisation routines (for request sockets and normal sockets).
Patch #5: Analogous to #4, this provides the cleanup routines.	  

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;h"8d610abf614d981cceabab3c27c1d3837e43ca

Patch stats:
------------
 include/linux/dccp.h |   13 ++-
 net/dccp/dccp.h      |    5 +
 net/dccp/feat.c      |  167 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |   62 ++++++++++++++++++
 net/dccp/input.c     |    2 
 net/dccp/ipv4.c      |    4 -
 net/dccp/ipv6.c      |    4 -
 net/dccp/minisocks.c |    7 +-
 net/dccp/proto.c     |    3 
 9 files changed, 256 insertions(+), 11 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information
  2008-09-22  7:21                                     ` Gerrit Renker
@ 2008-11-05  6:52                                                                 ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:52 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/dccp.h |    9 +++++----
 net/dccp/feat.c      |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,43 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -639,6 +676,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Implement lookup table for feature-negotiation
@ 2008-11-05  6:52                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:52 UTC (permalink / raw)
  To: dccp

A lookup table for feature-negotiation information, extracted from RFC 4340/42,
is provided by this patch. All currently known features can be found in this
table, along with their feature location, their default value, and type.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 include/linux/dccp.h |    9 +++++----
 net/dccp/feat.c      |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+), 4 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -176,19 +176,20 @@ enum {
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
-enum {
+enum dccp_feature_numbers {
 	DCCPF_RESERVED = 0,
 	DCCPF_CCID = 1,
-	DCCPF_SHORT_SEQNOS = 2,		/* XXX: not yet implemented */
+	DCCPF_SHORT_SEQNOS = 2,
 	DCCPF_SEQUENCE_WINDOW = 3,
-	DCCPF_ECN_INCAPABLE = 4,	/* XXX: not yet implemented */
+	DCCPF_ECN_INCAPABLE = 4,
 	DCCPF_ACK_RATIO = 5,
 	DCCPF_SEND_ACK_VECTOR = 6,
 	DCCPF_SEND_NDP_COUNT = 7,
 	DCCPF_MIN_CSUM_COVER = 8,
-	DCCPF_DATA_CHECKSUM = 9,	/* XXX: not yet implemented */
+	DCCPF_DATA_CHECKSUM = 9,
 	/* 10-127 reserved */
 	DCCPF_MIN_CCID_SPECIFIC = 128,
+	DCCPF_SEND_LEV_RATE = 192,	/* RFC 4342, sec. 8.4 */
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -23,6 +23,43 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+static const struct {
+	u8			feat_num;		/* DCCPF_xxx */
+	enum dccp_feat_type	rxtx;			/* RX or TX  */
+	enum dccp_feat_type	reconciliation;		/* SP or NN  */
+	u8			default_value;		/* as in 6.4 */
+/*
+ *    Lookup table for location and type of features (from RFC 4340/4342)
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | Feature                  | Location | Reconc. | Initial |  Section  |
+ *  |                          | RX | TX  | SP | NN |  Value  | Reference |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ *  | DCCPF_CCID               |    |  X  | X  |    |   2     | 10        |
+ *  | DCCPF_SHORT_SEQNOS       |    |  X  | X  |    |   0     |  7.6.1    |
+ *  | DCCPF_SEQUENCE_WINDOW    |    |  X  |    | X  | 100     |  7.5.2    |
+ *  | DCCPF_ECN_INCAPABLE      | X  |     | X  |    |   0     | 12.1      |
+ *  | DCCPF_ACK_RATIO          |    |  X  |    | X  |   2     | 11.3      |
+ *  | DCCPF_SEND_ACK_VECTOR    | X  |     | X  |    |   0     | 11.5      |
+ *  | DCCPF_SEND_NDP_COUNT     |    |  X  | X  |    |   0     |  7.7.2    |
+ *  | DCCPF_MIN_CSUM_COVER     | X  |     | X  |    |   0     |  9.2.1    |
+ *  | DCCPF_DATA_CHECKSUM      | X  |     | X  |    |   0     |  9.3.1    |
+ *  | DCCPF_SEND_LEV_RATE      | X  |     | X  |    |   0     | 4342/8.4  |
+ *  +--------------------------+----+-----+----+----+---------+-----------+
+ */
+} dccp_feat_table[] = {
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+};
+#define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -639,6 +676,8 @@ const char *dccp_feat_name(const u8 feat)
 	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
 		return feature_names[DCCPF_RESERVED];
 
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
 	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
 		return "CCID-specific";
 


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
  2008-09-22  7:21                                       ` Gerrit Renker
@ 2008-11-05  6:53                                                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:53 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This adds list initial fields and list management functions for the new
feature negotiation implementation.

Thanks to Arnaldo for suggestions and improvements.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -441,6 +441,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -60,6 +60,79 @@ static const struct {
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val == NULL))
+		return;
+	if (dccp_feat_type(feat_num) == FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: List management for new feature negotiation
@ 2008-11-05  6:53                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:53 UTC (permalink / raw)
  To: dccp

This adds list initial fields and list management functions for the new
feature negotiation implementation.

Thanks to Arnaldo for suggestions and improvements.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -441,6 +441,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern void dccp_feat_list_purge(struct list_head *fn_list);
+
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
 extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*);
 extern int dccp_insert_option_elapsed_time(struct sock *sk,
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -60,6 +60,79 @@ static const struct {
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
+/**
+ * dccp_feat_index  -  Hash function to map feature number into array position
+ * Returns consecutive array index or -1 if the feature is not understood.
+ */
+static int dccp_feat_index(u8 feat_num)
+{
+	/* The first 9 entries are occupied by the types from RFC 4340, 6.4 */
+	if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM)
+		return feat_num - 1;
+
+	/*
+	 * Other features: add cases for new feature types here after adding
+	 * them to the above table.
+	 */
+	switch (feat_num) {
+	case DCCPF_SEND_LEV_RATE:
+			return DCCP_FEAT_SUPPORTED_MAX - 1;
+	}
+	return -1;
+}
+
+static u8 dccp_feat_type(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+
+	if (idx < 0)
+		return FEAT_UNKNOWN;
+	return dccp_feat_table[idx].reconciliation;
+}
+
+static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
+{
+	if (unlikely(val = NULL))
+		return;
+	if (dccp_feat_type(feat_num) = FEAT_SP)
+		kfree(val->sp.vec);
+	memset(val, 0, sizeof(*val));
+}
+
+static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
+{
+	if (entry != NULL) {
+		dccp_feat_val_destructor(entry->feat_num, &entry->val);
+		kfree(entry);
+	}
+}
+
+/*
+ * List management functions
+ *
+ * Feature negotiation lists rely on and maintain the following invariants:
+ * - each feat_num in the list is known, i.e. we know its type and default value
+ * - each feat_num/is_local combination is unique (old entries are overwritten)
+ * - SP values are always freshly allocated
+ * - list is sorted in increasing order of feature number (faster lookup)
+ */
+
+static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
+{
+	list_del(&entry->node);
+	dccp_feat_entry_destructor(entry);
+}
+
+void dccp_feat_list_purge(struct list_head *fn_list)
+{
+	struct dccp_feat_entry *entry, *next;
+
+	list_for_each_entry_safe(entry, next, fn_list, node)
+		dccp_feat_entry_destructor(entry);
+	INIT_LIST_HEAD(fn_list);
+}
+EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
  2008-09-22  7:21                                         ` Gerrit Renker
@ 2008-11-05  6:53                                                                     ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:53 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +++
 net/dccp/dccp.h      |    3 +-
 net/dccp/feat.c      |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 -
 net/dccp/ipv4.c      |    3 +-
 net/dccp/ipv6.c      |    3 +-
 net/dccp/minisocks.c |    7 +++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 73 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num)
 	return dccp_feat_table[idx].reconciliation;
 }
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec == NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
 	if (unlikely(val == NULL))
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 	memset(val, 0, sizeof(*val));
 }
 
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type == FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new == NULL)
+		return NULL;
+
+	if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
 static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 {
 	if (entry != NULL) {
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new == NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -96,6 +96,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type == DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req == NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Per-socket initialisation of feature negotiation
@ 2008-11-05  6:53                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:53 UTC (permalink / raw)
  To: dccp

This provides feature-negotiation initialisation for both DCCP sockets and
DCCP request_sockets, to support feature negotiation during connection setup.

It also resolves a FIXME regarding the congestion control initialisation.

Thanks to Wei Yongjun for help with the IPv6 side of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +++
 net/dccp/dccp.h      |    3 +-
 net/dccp/feat.c      |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/feat.h      |    1 +
 net/dccp/input.c     |    2 -
 net/dccp/ipv4.c      |    3 +-
 net/dccp/ipv6.c      |    3 +-
 net/dccp/minisocks.c |    7 +++++-
 net/dccp/proto.c     |    1 +
 9 files changed, 73 insertions(+), 6 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -412,6 +412,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk);
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
  * @dreq_isr: initial sequence number received on the Request
  * @dreq_service: service code present on the Request (there is just one)
+ * @dreq_featneg: feature negotiation options for this connection
  * The following two fields are analogous to the ones in dccp_sock:
  * @dreq_timestamp_echo: last received timestamp to echo (13.1)
  * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo
@@ -421,6 +422,7 @@ struct dccp_request_sock {
 	__u64			 dreq_iss;
 	__u64			 dreq_isr;
 	__be32			 dreq_service;
+	struct list_head	 dreq_featneg;
 	__u32			 dreq_timestamp_echo;
 	__u32			 dreq_timestamp_time;
 };
@@ -498,6 +500,7 @@ struct dccp_ackvec;
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
  * @dccps_minisock - associated minisock (accessed via dccp_msk)
+ * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
  * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection)
@@ -535,6 +538,7 @@ struct dccp_sock {
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
+	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
 	struct ccid			*dccps_hc_tx_ccid;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -252,7 +252,8 @@ extern const char *dccp_state_name(const int state);
 extern void dccp_set_state(struct sock *sk, const int state);
 extern void dccp_done(struct sock *sk);
 
-extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb);
+extern int  dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp,
+			    struct sk_buff const *skb);
 
 extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -90,6 +90,20 @@ static u8 dccp_feat_type(u8 feat_num)
 	return dccp_feat_table[idx].reconciliation;
 }
 
+/* copy constructor, fval must not already contain allocated memory */
+static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
+{
+	fval->sp.len = len;
+	if (fval->sp.len > 0) {
+		fval->sp.vec = kmemdup(val, len, gfp_any());
+		if (fval->sp.vec = NULL) {
+			fval->sp.len = 0;
+			return -ENOBUFS;
+		}
+	}
+	return 0;
+}
+
 static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 {
 	if (unlikely(val = NULL))
@@ -99,6 +113,28 @@ static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val)
 	memset(val, 0, sizeof(*val));
 }
 
+static struct dccp_feat_entry *
+	      dccp_feat_clone_entry(struct dccp_feat_entry const *original)
+{
+	struct dccp_feat_entry *new;
+	u8 type = dccp_feat_type(original->feat_num);
+
+	if (type = FEAT_UNKNOWN)
+		return NULL;
+
+	new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any());
+	if (new = NULL)
+		return NULL;
+
+	if (type = FEAT_SP && dccp_feat_clone_sp_val(&new->val,
+						      original->val.sp.vec,
+						      original->val.sp.len)) {
+		kfree(new);
+		return NULL;
+	}
+	return new;
+}
+
 static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
 {
 	if (entry != NULL) {
@@ -133,6 +169,25 @@ void dccp_feat_list_purge(struct list_head *fn_list)
 }
 EXPORT_SYMBOL_GPL(dccp_feat_list_purge);
 
+/* generate @to as full clone of @from - @to must not contain any nodes */
+int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
+{
+	struct dccp_feat_entry *entry, *new;
+
+	INIT_LIST_HEAD(to);
+	list_for_each_entry(entry, from, node) {
+		new = dccp_feat_clone_entry(entry);
+		if (new = NULL)
+			goto cloning_failed;
+		list_add_tail(&new->node, to);
+	}
+	return 0;
+
+cloning_failed:
+	dccp_feat_list_purge(to);
+	return -ENOMEM;
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -96,6 +96,7 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
+extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct dccp_minisock *dmsk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -590,8 +590,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 			if (inet_csk(sk)->icsk_af_ops->conn_request(sk,
 								    skb) < 0)
 				return 1;
-
-			/* FIXME: do congestion control initialization */
 			goto discard;
 		}
 		if (dh->dccph_type = DCCP_PKT_RESET)
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -595,7 +595,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -424,7 +424,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (req = NULL)
 		goto drop;
 
-	dccp_reqsk_init(req, skb);
+	if (dccp_reqsk_init(req, dccp_sk(sk), skb))
+		goto drop_and_free;
 
 	dreq = dccp_rsk(req);
 	if (dccp_parse_options(sk, dreq, skb))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -125,6 +125,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newdp->dccps_timestamp_time = dreq->dreq_timestamp_time;
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
+		INIT_LIST_HEAD(&newdp->dccps_featneg);
 		if (dccp_feat_clone(sk, newsk))
 			goto out_free;
 
@@ -304,7 +305,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack);
 
-void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
+int dccp_reqsk_init(struct request_sock *req,
+		    struct dccp_sock const *dp, struct sk_buff const *skb)
 {
 	struct dccp_request_sock *dreq = dccp_rsk(req);
 
@@ -312,6 +314,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb)
 	inet_rsk(req)->acked	  = 0;
 	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
+
+	/* inherit feature negotiation options from listening socket */
+	return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_reqsk_init);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -193,6 +193,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 
 	dccp_init_xmit_timers(sk);
 
+	INIT_LIST_HEAD(&dp->dccps_featneg);
 	/*
 	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
 	 * the listening (master) sock get CCID control blocks, which is not


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
  2008-09-22  7:21                                           ` Gerrit Renker
@ 2008-11-05  6:54                                                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:54 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 3 files changed, 3 insertions(+), 1 deletions(-)

--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Cleanup routines for feature negotiation
@ 2008-11-05  6:54                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  6:54 UTC (permalink / raw)
  To: dccp

This inserts the required de-allocation routines for memory allocated by
feature negotiation in the socket destructors, replacing dccp_feat_clean()
in one instance.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ipv4.c  |    1 +
 net/dccp/ipv6.c  |    1 +
 net/dccp/proto.c |    2 +-
 3 files changed, 3 insertions(+), 1 deletions(-)

--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -545,6 +545,7 @@ out:
 
 static void dccp_v4_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	kfree(inet_rsk(req)->opt);
 }
 
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -302,6 +302,7 @@ done:
 
 static void dccp_v6_reqsk_destructor(struct request_sock *req)
 {
+	dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
 	if (inet6_rsk(req)->pktopts != NULL)
 		kfree_skb(inet6_rsk(req)->pktopts);
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -268,7 +268,7 @@ void dccp_destroy_sock(struct sock *sk)
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
 	/* clean up feature negotiation state */
-	dccp_feat_clean(dmsk);
+	dccp_feat_list_purge(&dp->dccps_featneg);
 }
 
 EXPORT_SYMBOL_GPL(dccp_destroy_sock);


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
  2008-09-22  7:21                                   ` Gerrit Renker
@ 2008-11-05  7:03                                                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  7:03 UTC (permalink / raw)
  To: David S. Miller, netdev, dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo, who contributed the streamlined layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Basic data structure for feature negotiation
@ 2008-11-05  7:03                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-05  7:03 UTC (permalink / raw)
  To: dccp

This patch prepares for the new and extended feature-negotiation routines.

The following feature-negotiation data structures are provided:
	* a container for the various (SP or NN) values,
	* symbolic state names to track feature states,
	* an entry struct which holds all current information together,
	* elementary functions to fill in and process these structures.

Entry structs are arranged as FIFO for the following reason: RFC 4340 specifies
that if multiple options of the same type are present, they are processed in the
order of their appearance in the packet; which means that this order needs to be
preserved in the local data structure (the later insertion code also respects
this order).

The struct list_head has been chosen for the following reasons: the most
frequent operations are
 * add new entry at tail (when receiving Change or setting socket options);
 * delete entry (when Confirm has been received);
 * deep copy of entire list (cloning from listening socket onto request socket).

The NN value has been set to 64 bit, which is a currently sufficient upper limit
(Sequence Window feature has 48 bit).

Thanks to Arnaldo, who contributed the streamlined layout of the entry struct.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 61 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,67 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+enum dccp_feat_type {
+	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
+	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
+	FEAT_SP      = 4,	/* server-priority reconciliation (6.3.1) */
+	FEAT_NN	     = 8,	/* non-negotiable reconciliation (6.3.2)  */
+	FEAT_UNKNOWN = 0xFF	/* not understood or invalid feature	  */
+};
+
+enum dccp_feat_state {
+	FEAT_DEFAULT = 0,	/* using default values from 6.4 */
+	FEAT_INITIALISING,	/* feature is being initialised  */
+	FEAT_CHANGING,		/* Change sent but not confirmed yet */
+	FEAT_UNSTABLE,		/* local modification in state CHANGING */
+	FEAT_STABLE		/* both ends (think they) agree */
+};
+
+/**
+ * dccp_feat_val  -  Container for SP or NN feature values
+ * @nn:     single NN value
+ * @sp.vec: single SP value plus optional preference list
+ * @sp.len: length of @sp.vec in bytes
+ */
+typedef union {
+	u64 nn;
+	struct {
+		u8	*vec;
+		u8	len;
+	}   sp;
+} dccp_feat_val;
+
+/**
+ * struct feat_entry  -  Data structure to perform feature negotiation
+ * @val: feature's current value (SP features may have preference list)
+ * @state: feature's current state
+ * @feat_num: one of %dccp_feature_numbers
+ * @needs_mandatory: whether Mandatory options should be sent
+ * @needs_confirm: whether to send a Confirm instead of a Change
+ * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm)
+ * @is_local: feature location (1) or feature-remote (0)
+ * @node: list pointers, entries arranged in FIFO order
+ */
+struct dccp_feat_entry {
+	dccp_feat_val           val;
+	enum dccp_feat_state    state:8;
+	u8                      feat_num;
+
+	bool			needs_mandatory,
+				needs_confirm,
+				empty_confirm,
+				is_local;
+
+	struct list_head	node;
+};
+
+static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
+{
+	if (entry->needs_confirm)
+		return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R;
+	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures
  2008-11-05  6:51                                                             ` v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - Gerrit Renker
@ 2008-11-05  7:56                                                               ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-05  7:56 UTC (permalink / raw)
  To: gerrit; +Cc: netdev, dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 5 Nov 2008 07:51:46 +0100

> as requested circa two weeks ago, I am now resending the first chunk of the
> feature-negotiation patch set.

All applied, thanks.

> Can you please let me know when it would be okay to submit the next
> instalment of this series.

Now is fine.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I -
@ 2008-11-05  7:56                                                               ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-05  7:56 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 5 Nov 2008 07:51:46 +0100

> as requested circa two weeks ago, I am now resending the first chunk of the
> feature-negotiation patch set.

All applied, thanks.

> Can you please let me know when it would be okay to submit the next
> instalment of this series.

Now is fine.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I (basis)
@ 2008-11-06  5:40                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

please find via the following 4 emails the remaining patches for
the first set part of the feature-negotiation patch set.

I have checked each individually to compile cleanly.

Best regards
Gerrit


Commit summary
--------------
The set concludes the first set of the feature negotiation patches to provide
a self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

Within these blocks, this is the second set and its purpose is to conclude
the base implementation, preparing for the (15) core patches in the second set.


List of patches in this set:
----------------------------
Patch #1: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #2: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #3: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #4: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=822761d3e69a1f7f8b994d1d7efd7771351e0195


Patch stats:
------------
 Documentation/networking/dccp.txt |    4 
 include/linux/dccp.h              |    1 
 net/dccp/ccid.c                   |   48 +++++
 net/dccp/ccid.h                   |    5 
 net/dccp/ccids/ccid2.c            |    6 
 net/dccp/dccp.h                   |    1 
 net/dccp/feat.c                   |  306 +++++++++++++++++++++++++++++++++-----
 net/dccp/feat.h                   |   25 ++-
 net/dccp/options.c                |   18 --
 net/dccp/output.c                 |    4 
 net/dccp/proto.c                  |    7 
 net/dccp/timer.c                  |   12 -
 12 files changed, 368 insertions(+), 69 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I (basis)
@ 2008-11-06  5:40                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find via the following 4 emails the remaining patches for
the first set part of the feature-negotiation patch set.

I have checked each individually to compile cleanly.

Best regards
Gerrit


Commit summary
--------------
The set concludes the first set of the feature negotiation patches to provide
a self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

Within these blocks, this is the second set and its purpose is to conclude
the base implementation, preparing for the (15) core patches in the second set.


List of patches in this set:
----------------------------
Patch #1: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #2: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #3: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #4: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;h‚2761d3e69a1f7f8b994d1d7efd7771351e0195


Patch stats:
------------
 Documentation/networking/dccp.txt |    4 
 include/linux/dccp.h              |    1 
 net/dccp/ccid.c                   |   48 +++++
 net/dccp/ccid.h                   |    5 
 net/dccp/ccids/ccid2.c            |    6 
 net/dccp/dccp.h                   |    1 
 net/dccp/feat.c                   |  306 +++++++++++++++++++++++++++++++++-----
 net/dccp/feat.h                   |   25 ++-
 net/dccp/options.c                |   18 --
 net/dccp/output.c                 |    4 
 net/dccp/proto.c                  |    7 
 net/dccp/timer.c                  |   12 -
 12 files changed, 368 insertions(+), 69 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase
@ 2008-11-06  5:40                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch limits feature-negotiation to the connnection-setup phase:

 1. Although it is theoretically possible to perform feature negotiation at any
    time (and RFC 4340 supports this), in practice this is prohibitively complex,
    as it requires to put traffic on hold for each new negotiation.
 2. As a byproduct of restricting feature negotiation to connection setup, the
    feature-negotiation retransmit timer is no longer required. This part is now
    mapped onto the protocol-level retransmission.
    Details indicating why timers are no longer needed can be found on
    http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
	                                      implementation_notes.html

This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |   19 ++++++++-----------
 net/dccp/options.c |   18 ------------------
 net/dccp/timer.c   |   12 ------------
 3 files changed, 8 insertions(+), 41 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -6,6 +6,8 @@
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  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.
@@ -652,6 +654,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 {
 	int rc;
 
+	/* Ignore Change requests other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* figure out if it's SP or NN feature */
@@ -701,6 +706,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 	int found = 0;
 	int all_confirmed = 1;
 
+	/* Ignore Confirm options other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* locate our change request */
@@ -735,17 +743,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			all_confirmed = 0;
 	}
 
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
 	if (!found)
 		dccp_pr_debug("%s(%d, ...) never requested\n",
 			      dccp_feat_typename(type), feature);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 
 static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct dccp_opt_pend *opt, *next;
 	int change = 0;
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 		}
 	}
 
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
 	return 0;
 }
 
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head == NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state == DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase
@ 2008-11-06  5:40                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: dccp

This patch limits feature-negotiation to the connnection-setup phase:

 1. Although it is theoretically possible to perform feature negotiation at any
    time (and RFC 4340 supports this), in practice this is prohibitively complex,
    as it requires to put traffic on hold for each new negotiation.
 2. As a byproduct of restricting feature negotiation to connection setup, the
    feature-negotiation retransmit timer is no longer required. This part is now
    mapped onto the protocol-level retransmission.
    Details indicating why timers are no longer needed can be found on
    http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
	                                      implementation_notes.html

This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |   19 ++++++++-----------
 net/dccp/options.c |   18 ------------------
 net/dccp/timer.c   |   12 ------------
 3 files changed, 8 insertions(+), 41 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -6,6 +6,8 @@
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  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.
@@ -652,6 +654,9 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 {
 	int rc;
 
+	/* Ignore Change requests other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* figure out if it's SP or NN feature */
@@ -701,6 +706,9 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 	int found = 0;
 	int all_confirmed = 1;
 
+	/* Ignore Confirm options other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* locate our change request */
@@ -735,17 +743,6 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			all_confirmed = 0;
 	}
 
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
 	if (!found)
 		dccp_pr_debug("%s(%d, ...) never requested\n",
 			      dccp_feat_typename(type), feature);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 
 static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct dccp_opt_pend *opt, *next;
 	int change = 0;
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 		}
 	}
 
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
 	return 0;
 }
 
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head = NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state = DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk)
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/4] dccp: Registration routines for changing feature values
@ 2008-11-06  5:40                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.

These are internal-only routines and therefore start with `__feat_register'.

It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccids/ccid2.c |    6 +-
 net/dccp/feat.c        |  123 +++++++++++++++++++++++++++++++++++++++---------
 net/dccp/feat.h        |   25 +++++++++-
 net/dccp/proto.c       |    2 +-
 4 files changed, 128 insertions(+), 28 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,15 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+/*
+ * Known limit values
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
 	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
@@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
 	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
 }
 
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -96,6 +119,6 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_init(struct sock *sk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -300,6 +300,95 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list == NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -836,42 +925,30 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
-{
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
-
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
-	}
-	return rc;
-}
-
-int dccp_feat_init(struct dccp_minisock *dmsk)
+int dccp_feat_init(struct sock *sk)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
+				&dmsk->dccpms_tx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
+				&dmsk->dccpms_rx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dmsk->dccpms_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
+		int rc = dccp_feat_init(sk);
 
 		if (rc)
 			return rc;
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val == dp->dccps_l_ack_ratio)
 		return;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/4] dccp: Registration routines for changing feature values
@ 2008-11-06  5:40                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: dccp

Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.

These are internal-only routines and therefore start with `__feat_register'.

It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccids/ccid2.c |    6 +-
 net/dccp/feat.c        |  123 +++++++++++++++++++++++++++++++++++++++---------
 net/dccp/feat.h        |   25 +++++++++-
 net/dccp/proto.c       |    2 +-
 4 files changed, 128 insertions(+), 28 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,15 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+/*
+ * Known limit values
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin2 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
 	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
@@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
 	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
 }
 
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -96,6 +119,6 @@ extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_init(struct sock *sk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -300,6 +300,95 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val = DCCPC_CCID2 || val = DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list = NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) = 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -836,42 +925,30 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
-{
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
-
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
-	}
-	return rc;
-}
-
-int dccp_feat_init(struct dccp_minisock *dmsk)
+int dccp_feat_init(struct sock *sk)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
+				&dmsk->dccpms_tx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
+				&dmsk->dccpms_rx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dmsk->dccpms_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
+		int rc = dccp_feat_init(sk);
 
 		if (rc)
 			return rc;
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val = dp->dccps_l_ack_ratio)
 		return;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/4] dccp: Query supported CCIDs
@ 2008-11-06  5:40                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This provides a data structure to record which CCIDs are locally supported
and three accessor functions:
 - a test function for internal use which is used to validate CCID requests
   made by the user;
 - a copy function so that the list can be used for feature-negotiation;
 - documented getsockopt() support so that the user can query capabilities.

The data structure is a table which is filled in at compile-time with the
list of available CCIDs (which in turn depends on the Kconfig choices).

Using the copy function for cloning the list of supported CCIDs is useful for
feature negotiation, since the negotiation is now with the full list of available
CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
will not fail if the peer requests to use CCID3 instead of CCID2.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    4 +++
 include/linux/dccp.h              |    1 +
 net/dccp/ccid.c                   |   48 +++++++++++++++++++++++++++++++++++++
 net/dccp/ccid.h                   |    5 ++++
 net/dccp/feat.c                   |    4 +++
 net/dccp/proto.c                  |    2 +
 6 files changed, 64 insertions(+), 0 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const struct ccid *ccid)
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] == builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array == NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -383,6 +383,10 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
 		return -EINVAL;
 
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
 	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
 		return -ENOMEM;
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/4] dccp: Query supported CCIDs
@ 2008-11-06  5:40                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: dccp

This provides a data structure to record which CCIDs are locally supported
and three accessor functions:
 - a test function for internal use which is used to validate CCID requests
   made by the user;
 - a copy function so that the list can be used for feature-negotiation;
 - documented getsockopt() support so that the user can query capabilities.

The data structure is a table which is filled in at compile-time with the
list of available CCIDs (which in turn depends on the Kconfig choices).

Using the copy function for cloning the list of supported CCIDs is useful for
feature negotiation, since the negotiation is now with the full list of available
CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
will not fail if the peer requests to use CCID3 instead of CCID2.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    4 +++
 include/linux/dccp.h              |    1 +
 net/dccp/ccid.c                   |   48 +++++++++++++++++++++++++++++++++++++
 net/dccp/ccid.h                   |    5 ++++
 net/dccp/feat.c                   |    4 +++
 net/dccp/proto.c                  |    2 +
 6 files changed, 64 insertions(+), 0 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const struct ccid *ccid)
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab)
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] = builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array = NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -383,6 +383,10 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
 		return -EINVAL;
 
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat = DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
 	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
 		return -ENOMEM;
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
@ 2008-11-06  5:40                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This provides a missing link in the code chain, as several features implicitly
depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).

For Send Ack Vector, the situation is as follows:
 * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
   endpoints which use CCID2 to disable Ack Vector features such a connection;

 * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
   with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);

 * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
   negotiable. However, this implies that the code negotiating the use of Ack
   Vectors also supports it (i.e. is able to supply and to either parse or
   ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
   Vector support), the use of Ack Vectors is here disabled, with a comment
   in the source code.

An analogous consideration arises for the Send Loss Event Rate feature,
since the CCID-3 implementation does not support the loss interval options
of RFC 4342. To make such use explicit, corresponding feature-negotiation
options are inserted which signal the use of the loss event rate option,
as it is used by the CCID3 code.

Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.

The patch implements this as a function which is called after the user has
made all other registrations for changing default values of features.

The table is variable-length, the reserved (and hence for feature-negotiation
invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
is used to mark the end of the table.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |    4 +
 net/dccp/proto.c  |    3 +
 4 files changed, 168 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -441,6 +441,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table == NULL);
+
+	for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
+	return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
@ 2008-11-06  5:40                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-06  5:40 UTC (permalink / raw)
  To: dccp

This provides a missing link in the code chain, as several features implicitly
depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).

For Send Ack Vector, the situation is as follows:
 * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
   endpoints which use CCID2 to disable Ack Vector features such a connection;

 * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
   with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);

 * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
   negotiable. However, this implies that the code negotiating the use of Ack
   Vectors also supports it (i.e. is able to supply and to either parse or
   ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
   Vector support), the use of Ack Vectors is here disabled, with a comment
   in the source code.

An analogous consideration arises for the Send Loss Event Rate feature,
since the CCID-3 implementation does not support the loss interval options
of RFC 4342. To make such use explicit, corresponding feature-negotiation
options are inserted which signal the use of the loss event rate option,
as it is used by the CCID3 code.

Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.

The patch implements this as a function which is called after the user has
made all other registrations for changing default values of features.

The table is variable-length, the reserved (and hence for feature-negotiation
invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
is used to mark the end of the table.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |  160 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |    4 +
 net/dccp/proto.c  |    3 +
 4 files changed, 168 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -441,6 +441,166 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table = NULL);
+
+	for (i = 0; rc = 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) = FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
+	return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num = DCCPF_CCID && entry->val.sp.len = 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog)
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase
  2008-11-06  5:40                                                                   ` Gerrit Renker
@ 2008-11-10 21:15                                                                     ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:15 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:11 +0100

> This patch limits feature-negotiation to the connnection-setup phase:
> 
>  1. Although it is theoretically possible to perform feature negotiation at any
>     time (and RFC 4340 supports this), in practice this is prohibitively complex,
>     as it requires to put traffic on hold for each new negotiation.
>  2. As a byproduct of restricting feature negotiation to connection setup, the
>     feature-negotiation retransmit timer is no longer required. This part is now
>     mapped onto the protocol-level retransmission.
>     Details indicating why timers are no longer needed can be found on
>     http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
> 	                                      implementation_notes.html
> 
> This patch disables anytime negotiation, subsequent patches work out full
> feature negotiation support for connection setup.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/4] dccp: Limit feature negotiation to connection
@ 2008-11-10 21:15                                                                     ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:15 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:11 +0100

> This patch limits feature-negotiation to the connnection-setup phase:
> 
>  1. Although it is theoretically possible to perform feature negotiation at any
>     time (and RFC 4340 supports this), in practice this is prohibitively complex,
>     as it requires to put traffic on hold for each new negotiation.
>  2. As a byproduct of restricting feature negotiation to connection setup, the
>     feature-negotiation retransmit timer is no longer required. This part is now
>     mapped onto the protocol-level retransmission.
>     Details indicating why timers are no longer needed can be found on
>     http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
> 	                                      implementation_notes.html
> 
> This patch disables anytime negotiation, subsequent patches work out full
> feature negotiation support for connection setup.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/4] dccp: Registration routines for changing feature values
  2008-11-06  5:40                                                                     ` Gerrit Renker
@ 2008-11-10 21:16                                                                       ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:16 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:12 +0100

> Two registration routines, for SP and NN features, are provided by this patch,
> replacing a previous routine which was used for both feature types.
> 
> These are internal-only routines and therefore start with `__feat_register'.
> 
> It further exports the known limits of Sequence Window and Ack Ratio as symbolic
> constants.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/4] dccp: Registration routines for changing feature
@ 2008-11-10 21:16                                                                       ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:16 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:12 +0100

> Two registration routines, for SP and NN features, are provided by this patch,
> replacing a previous routine which was used for both feature types.
> 
> These are internal-only routines and therefore start with `__feat_register'.
> 
> It further exports the known limits of Sequence Window and Ack Ratio as symbolic
> constants.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 3/4] dccp: Query supported CCIDs
  2008-11-06  5:40                                                                       ` Gerrit Renker
@ 2008-11-10 21:16                                                                         ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:16 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:13 +0100

> This provides a data structure to record which CCIDs are locally supported
> and three accessor functions:
>  - a test function for internal use which is used to validate CCID requests
>    made by the user;
>  - a copy function so that the list can be used for feature-negotiation;
>  - documented getsockopt() support so that the user can query capabilities.
> 
> The data structure is a table which is filled in at compile-time with the
> list of available CCIDs (which in turn depends on the Kconfig choices).
> 
> Using the copy function for cloning the list of supported CCIDs is useful for
> feature negotiation, since the negotiation is now with the full list of available
> CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
> will not fail if the peer requests to use CCID3 instead of CCID2.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 3/4] dccp: Query supported CCIDs
@ 2008-11-10 21:16                                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:16 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:13 +0100

> This provides a data structure to record which CCIDs are locally supported
> and three accessor functions:
>  - a test function for internal use which is used to validate CCID requests
>    made by the user;
>  - a copy function so that the list can be used for feature-negotiation;
>  - documented getsockopt() support so that the user can query capabilities.
> 
> The data structure is a table which is filled in at compile-time with the
> list of available CCIDs (which in turn depends on the Kconfig choices).
> 
> Using the copy function for cloning the list of supported CCIDs is useful for
> feature negotiation, since the negotiation is now with the full list of available
> CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation
> will not fail if the peer requests to use CCID3 instead of CCID2.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
  2008-11-06  5:40                                                                         ` Gerrit Renker
@ 2008-11-10 21:17                                                                           ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:17 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:14 +0100

> This provides a missing link in the code chain, as several features implicitly
> depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
> feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
> 
> For Send Ack Vector, the situation is as follows:
>  * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
>    endpoints which use CCID2 to disable Ack Vector features such a connection;
> 
>  * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
>    with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);
> 
>  * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
>    negotiable. However, this implies that the code negotiating the use of Ack
>    Vectors also supports it (i.e. is able to supply and to either parse or
>    ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
>    Vector support), the use of Ack Vectors is here disabled, with a comment
>    in the source code.
> 
> An analogous consideration arises for the Send Loss Event Rate feature,
> since the CCID-3 implementation does not support the loss interval options
> of RFC 4342. To make such use explicit, corresponding feature-negotiation
> options are inserted which signal the use of the loss event rate option,
> as it is used by the CCID3 code.
> 
> Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.
> 
> The patch implements this as a function which is called after the user has
> made all other registrations for changing default values of features.
> 
> The table is variable-length, the reserved (and hence for feature-negotiation
> invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
> is used to mark the end of the table.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Also applied, thanks.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/4] dccp: Resolve dependencies of features on choice
@ 2008-11-10 21:17                                                                           ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:17 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Thu,  6 Nov 2008 06:40:14 +0100

> This provides a missing link in the code chain, as several features implicitly
> depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
> feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).
> 
> For Send Ack Vector, the situation is as follows:
>  * since CCID2 mandates the use of Ack Vectors, there is no point in allowing
>    endpoints which use CCID2 to disable Ack Vector features such a connection;
> 
>  * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
>    with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);
> 
>  * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
>    negotiable. However, this implies that the code negotiating the use of Ack
>    Vectors also supports it (i.e. is able to supply and to either parse or
>    ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
>    Vector support), the use of Ack Vectors is here disabled, with a comment
>    in the source code.
> 
> An analogous consideration arises for the Send Loss Event Rate feature,
> since the CCID-3 implementation does not support the loss interval options
> of RFC 4342. To make such use explicit, corresponding feature-negotiation
> options are inserted which signal the use of the loss event rate option,
> as it is used by the CCID3 code.
> 
> Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.
> 
> The patch implements this as a function which is called after the user has
> made all other registrations for changing default values of features.
> 
> The table is variable-length, the reserved (and hence for feature-negotiation
> invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
> is used to mark the end of the table.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Also applied, thanks.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
  2008-11-06  5:40                                                                         ` Gerrit Renker
@ 2008-11-10 21:20                                                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:20 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev


Nevermind, I'm reverting all 4 patches.

Send me something which actually compiles next time:

net/dccp/feat.c: In function ‘__feat_register_nn’:
net/dccp/feat.c:252: error: implicit declaration of function ‘dccp_feat_default_value’
net/dccp/feat.c:255: error: implicit declaration of function ‘dccp_feat_push_change’
make[2]: *** [net/dccp/feat.o] Error 1
make[2]: *** Waiting for unfinished jobs....

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/4] dccp: Resolve dependencies of features on choice
@ 2008-11-10 21:20                                                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-10 21:20 UTC (permalink / raw)
  To: dccp

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 536 bytes --]


Nevermind, I'm reverting all 4 patches.

Send me something which actually compiles next time:

net/dccp/feat.c: In function ‘__feat_register_nn’:
net/dccp/feat.c:252: error: implicit declaration of function ‘dccp_feat_default_value’
net/dccp/feat.c:255: error: implicit declaration of function ‘dccp_feat_push_change’
make[2]: *** [net/dccp/feat.o] Error 1
make[2]: *** Waiting for unfinished jobs....
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·qÊÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
  2008-11-06  5:40                                                                         ` Gerrit Renker
@ 2008-11-12  6:14                                                                               ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:14 UTC (permalink / raw)
  To: David Miller; +Cc: dccp, netdev

David, -
| Send me something which actually compiles next time:
| 
| net/dccp/feat.c: In function ???__feat_register_nn???:
| net/dccp/feat.c:252: error: implicit declaration of function ???dccp_feat_default_value???
| net/dccp/feat.c:255: error: implicit declaration of function ???dccp_feat_push_change???
| make[2]: *** [net/dccp/feat.o] Error 1
| make[2]: *** Waiting for unfinished jobs....
| 
Apologies. This was a resubmitted set and patch 2/4, after diff-ing each
of the patches, was found to still have the old format. The set had been
changed to avoid build warnings about dependencies throughout, this
patch unfortunately had the old format.

When resubmitting next I will make sure to only use fresh copies for
each, no matter if it is the same patch. 

Will re-send the 4 from the up-to-date local copies, these are known to
compile without errors/warnings. 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/4] dccp: Resolve dependencies of features on choice
@ 2008-11-12  6:14                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:14 UTC (permalink / raw)
  To: dccp

David, -
| Send me something which actually compiles next time:
| 
| net/dccp/feat.c: In function ???__feat_register_nn???:
| net/dccp/feat.c:252: error: implicit declaration of function ???dccp_feat_default_value???
| net/dccp/feat.c:255: error: implicit declaration of function ???dccp_feat_push_change???
| make[2]: *** [net/dccp/feat.o] Error 1
| make[2]: *** Waiting for unfinished jobs....
| 
Apologies. This was a resubmitted set and patch 2/4, after diff-ing each
of the patches, was found to still have the old format. The set had been
changed to avoid build warnings about dependencies throughout, this
patch unfortunately had the old format.

When resubmitting next I will make sure to only use fresh copies for
each, no matter if it is the same patch. 

Will re-send the 4 from the up-to-date local copies, these are known to
compile without errors/warnings. 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I (basis)
@ 2008-11-12  6:36                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:36 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

please find attached the correct set of 4 patches, taken from up-to-date
copies. Text below (URL) also updated.

Gerrit


Changes relative to revision-01
-------------------------------
Patch 2/4 in the first revision was in an outdated format which lead to 
several hunks missing. This set contains the correct/up-to-date versions.
For reference, an inter-diff to the previous set is below.


Commit summary
--------------
The set concludes the first set of the feature negotiation patches to provide
a self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

Within these blocks, this is the second set and its purpose is to conclude
the base implementation, preparing for the (15) core patches in the second set.


List of patches in this set:
----------------------------
Patch #1: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #2: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #3: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #4: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=287242dd8caa65415c219e3163a8b6744067508f


Patch stats:
------------
 Documentation/networking/dccp.txt |    4 
 include/linux/dccp.h              |    1 
 net/dccp/ccid.c                   |   48 ++++
 net/dccp/ccid.h                   |    5 
 net/dccp/ccids/ccid2.c            |    6 
 net/dccp/dccp.h                   |    1 
 net/dccp/feat.c                   |  375 ++++++++++++++++++++++++++++++++++----
 net/dccp/feat.h                   |   25 ++
 net/dccp/options.c                |   18 -
 net/dccp/output.c                 |    4 
 net/dccp/proto.c                  |    7 
 net/dccp/timer.c                  |   12 -
 12 files changed, 437 insertions(+), 69 deletions(-)



		------------------------------------
		Appendix: Inter-diff to previous set
		------------------------------------

 --- a/net/dccp/feat.c
 +++ b/net/dccp/feat.c
 @@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
  	return dccp_feat_table[idx].reconciliation;
  }
  
 +static int dccp_feat_default_value(u8 feat_num)
 +{
 +	int idx = dccp_feat_index(feat_num);
 +	/*
 +	 * There are no default values for unknown features, so encountering a
 +	 * negative index here indicates a serious problem somewhere else.
 +	 */
 +	DCCP_BUG_ON(idx < 0);
 +
 +	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 +}
 +
  /* copy constructor, fval must not already contain allocated memory */
  static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
  {
 @@ -155,6 +167,63 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
   * - list is sorted in increasing order of feature number (faster lookup)
   */
  
 +/**
 + * dccp_feat_entry_new  -  Central list update routine (called by all others)
 + * @head:  list to add to
 + * @feat:  feature number
 + * @local: whether the local (1) or remote feature with number @feat is meant
 + * This is the only constructor and serves to ensure the above invariants.
 + */
 +static struct dccp_feat_entry *
 +	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
 +{
 +	struct dccp_feat_entry *entry;
 +
 +	list_for_each_entry(entry, head, node)
 +		if (entry->feat_num == feat && entry->is_local == local) {
 +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
 +			return entry;
 +		} else if (entry->feat_num > feat) {
 +			head = &entry->node;
 +			break;
 +		}
 +
 +	entry = kmalloc(sizeof(*entry), gfp_any());
 +	if (entry != NULL) {
 +		entry->feat_num = feat;
 +		entry->is_local = local;
 +		list_add_tail(&entry->node, head);
 +	}
 +	return entry;
 +}
 +
 +/**
 + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
 + * @fn_list: feature-negotiation list to update
 + * @feat: one of %dccp_feature_numbers
 + * @local: whether local (1) or remote (0) @feat_num is meant
 + * @needs_mandatory: whether to use Mandatory feature negotiation options
 + * @fval: pointer to NN/SP value to be inserted (will be copied)
 + */
 +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
 +				 u8 mandatory, dccp_feat_val *fval)
 +{
 +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
 +
 +	if (new == NULL)
 +		return -ENOMEM;
 +
 +	new->feat_num	     = feat;
 +	new->is_local	     = local;
 +	new->state	     = FEAT_INITIALISING;
 +	new->needs_confirm   = 0;
 +	new->empty_confirm   = 0;
 +	new->val	     = *fval;
 +	new->needs_mandatory = mandatory;
 +
 +	return 0;
 +}
 +
  static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
  {
  	list_del(&entry->node);
 
--- 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I
@ 2008-11-12  6:36                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:36 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find attached the correct set of 4 patches, taken from up-to-date
copies. Text below (URL) also updated.

Gerrit


Changes relative to revision-01
-------------------------------
Patch 2/4 in the first revision was in an outdated format which lead to 
several hunks missing. This set contains the correct/up-to-date versions.
For reference, an inter-diff to the previous set is below.


Commit summary
--------------
The set concludes the first set of the feature negotiation patches to provide
a self-contained feature negotiation API for the DCCP protocol (RFC 4340-2).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

Within these blocks, this is the second set and its purpose is to conclude
the base implementation, preparing for the (15) core patches in the second set.


List of patches in this set:
----------------------------
Patch #1: Changes the existing policy to allow anytime changes as that lead
          to unpredictable results.
Patch #2: Adds registration routines. These form part of the user interface
          and are later used by the socket API to set individual preferences.
Patch #3: CCIDs are a negotiable feature. This patch adds support to query the
          supported CCIDs, so as to advertise only the locally supported ones.
Patch #4: The choice of CCID in turn creates new feature dependencies. The patch
          adds automatic tracking of such dependencies to avoid later failure.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;h(7242dd8caa65415c219e3163a8b6744067508f


Patch stats:
------------
 Documentation/networking/dccp.txt |    4 
 include/linux/dccp.h              |    1 
 net/dccp/ccid.c                   |   48 ++++
 net/dccp/ccid.h                   |    5 
 net/dccp/ccids/ccid2.c            |    6 
 net/dccp/dccp.h                   |    1 
 net/dccp/feat.c                   |  375 ++++++++++++++++++++++++++++++++++----
 net/dccp/feat.h                   |   25 ++
 net/dccp/options.c                |   18 -
 net/dccp/output.c                 |    4 
 net/dccp/proto.c                  |    7 
 net/dccp/timer.c                  |   12 -
 12 files changed, 437 insertions(+), 69 deletions(-)



		------------------------------------
		Appendix: Inter-diff to previous set
		------------------------------------

 --- a/net/dccp/feat.c
 +++ b/net/dccp/feat.c
 @@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
  	return dccp_feat_table[idx].reconciliation;
  }
  
 +static int dccp_feat_default_value(u8 feat_num)
 +{
 +	int idx = dccp_feat_index(feat_num);
 +	/*
 +	 * There are no default values for unknown features, so encountering a
 +	 * negative index here indicates a serious problem somewhere else.
 +	 */
 +	DCCP_BUG_ON(idx < 0);
 +
 +	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 +}
 +
  /* copy constructor, fval must not already contain allocated memory */
  static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
  {
 @@ -155,6 +167,63 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
   * - list is sorted in increasing order of feature number (faster lookup)
   */
  
 +/**
 + * dccp_feat_entry_new  -  Central list update routine (called by all others)
 + * @head:  list to add to
 + * @feat:  feature number
 + * @local: whether the local (1) or remote feature with number @feat is meant
 + * This is the only constructor and serves to ensure the above invariants.
 + */
 +static struct dccp_feat_entry *
 +	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
 +{
 +	struct dccp_feat_entry *entry;
 +
 +	list_for_each_entry(entry, head, node)
 +		if (entry->feat_num = feat && entry->is_local = local) {
 +			dccp_feat_val_destructor(entry->feat_num, &entry->val);
 +			return entry;
 +		} else if (entry->feat_num > feat) {
 +			head = &entry->node;
 +			break;
 +		}
 +
 +	entry = kmalloc(sizeof(*entry), gfp_any());
 +	if (entry != NULL) {
 +		entry->feat_num = feat;
 +		entry->is_local = local;
 +		list_add_tail(&entry->node, head);
 +	}
 +	return entry;
 +}
 +
 +/**
 + * dccp_feat_push_change  -  Add/overwrite a Change option in the list
 + * @fn_list: feature-negotiation list to update
 + * @feat: one of %dccp_feature_numbers
 + * @local: whether local (1) or remote (0) @feat_num is meant
 + * @needs_mandatory: whether to use Mandatory feature negotiation options
 + * @fval: pointer to NN/SP value to be inserted (will be copied)
 + */
 +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
 +				 u8 mandatory, dccp_feat_val *fval)
 +{
 +	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
 +
 +	if (new = NULL)
 +		return -ENOMEM;
 +
 +	new->feat_num	     = feat;
 +	new->is_local	     = local;
 +	new->state	     = FEAT_INITIALISING;
 +	new->needs_confirm   = 0;
 +	new->empty_confirm   = 0;
 +	new->val	     = *fval;
 +	new->needs_mandatory = mandatory;
 +
 +	return 0;
 +}
 +
  static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
  {
  	list_del(&entry->node);
 
--- 
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase
@ 2008-11-12  6:37                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

dccp: Limit feature negotiation to connection setup phase

This patch limits feature (capability) negotation to the connection setup phase:

 1. Although it is theoretically possible to perform feature negotiation at any
    time (and RFC 4340 supports this), in practice this is prohibitively complex,
    as it requires to put traffic on hold for each new negotiation.
 2. As a byproduct of restricting feature negotiation to connection setup, the
    feature-negotiation retransmit timer is no longer required. This part is now
    mapped onto the protocol-level retransmission.
    Details indicating why timers are no longer needed can be found on
    http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
	                                      implementation_notes.html

This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |   19 ++++++++-----------
 net/dccp/options.c |   18 ------------------
 net/dccp/timer.c   |   12 ------------
 3 files changed, 8 insertions(+), 41 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -6,6 +6,8 @@
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  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.
@@ -542,6 +544,9 @@ int dccp_feat_change_recv(struct sock *s
 {
 	int rc;
 
+	/* Ignore Change requests other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* figure out if it's SP or NN feature */
@@ -591,6 +596,9 @@ int dccp_feat_confirm_recv(struct sock *
 	int found = 0;
 	int all_confirmed = 1;
 
+	/* Ignore Confirm options other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* locate our change request */
@@ -625,17 +633,6 @@ int dccp_feat_confirm_recv(struct sock *
 			all_confirmed = 0;
 	}
 
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
 	if (!found)
 		dccp_pr_debug("%s(%d, ...) never requested\n",
 			      dccp_feat_typename(type), feature);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct s
 
 static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct dccp_opt_pend *opt, *next;
 	int change = 0;
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(stru
 		}
 	}
 
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
 	return 0;
 }
 
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head == NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state == DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup
@ 2008-11-12  6:37                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: dccp

dccp: Limit feature negotiation to connection setup phase

This patch limits feature (capability) negotation to the connection setup phase:

 1. Although it is theoretically possible to perform feature negotiation at any
    time (and RFC 4340 supports this), in practice this is prohibitively complex,
    as it requires to put traffic on hold for each new negotiation.
 2. As a byproduct of restricting feature negotiation to connection setup, the
    feature-negotiation retransmit timer is no longer required. This part is now
    mapped onto the protocol-level retransmission.
    Details indicating why timers are no longer needed can be found on
    http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
	                                      implementation_notes.html

This patch disables anytime negotiation, subsequent patches work out full
feature negotiation support for connection setup.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.c    |   19 ++++++++-----------
 net/dccp/options.c |   18 ------------------
 net/dccp/timer.c   |   12 ------------
 3 files changed, 8 insertions(+), 41 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -6,6 +6,8 @@
  *
  *  ASSUMPTIONS
  *  -----------
+ *  o Feature negotiation is coordinated with connection setup (as in TCP), wild
+ *    changes of parameters of an established connection are not supported.
  *  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.
@@ -542,6 +544,9 @@ int dccp_feat_change_recv(struct sock *s
 {
 	int rc;
 
+	/* Ignore Change requests other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* figure out if it's SP or NN feature */
@@ -591,6 +596,9 @@ int dccp_feat_confirm_recv(struct sock *
 	int found = 0;
 	int all_confirmed = 1;
 
+	/* Ignore Confirm options other than during connection setup */
+	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
+		return 0;
 	dccp_feat_debug(type, feature, *val);
 
 	/* locate our change request */
@@ -625,17 +633,6 @@ int dccp_feat_confirm_recv(struct sock *
 			all_confirmed = 0;
 	}
 
-	/* fix re-transmit timer */
-	/* XXX gotta make sure that no option negotiation occurs during
-	 * connection shutdown.  Consider that the CLOSEREQ is sent and timer is
-	 * on.  if all options are confirmed it might kill timer which should
-	 * remain alive until close is received.
-	 */
-	if (all_confirmed) {
-		dccp_pr_debug("clear feat negotiation timer %p\n", sk);
-		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
-	}
-
 	if (!found)
 		dccp_pr_debug("%s(%d, ...) never requested\n",
 			      dccp_feat_typename(type), feature);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -489,7 +489,6 @@ static int dccp_insert_feat_opt(struct s
 
 static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct dccp_opt_pend *opt, *next;
 	int change = 0;
@@ -530,23 +529,6 @@ static int dccp_insert_options_feat(stru
 		}
 	}
 
-	/* Retransmit timer.
-	 * If this is the master listening sock, we don't set a timer on it.  It
-	 * should be fine because if the dude doesn't receive our RESPONSE
-	 * [which will contain the CHANGE] he will send another REQUEST which
-	 * will "retrnasmit" the change.
-	 */
-	if (change && dp->dccps_role != DCCP_ROLE_LISTEN) {
-		dccp_pr_debug("reset feat negotiation timer %p\n", sk);
-
-		/* XXX don't reset the timer on re-transmissions.  I.e. reset it
-		 * only when sending new stuff i guess.  Currently the timer
-		 * never backs off because on re-transmission it just resets it!
-		 */
-		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
-					  inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
-	}
-
 	return 0;
 }
 
--- a/net/dccp/timer.c
+++ b/net/dccp/timer.c
@@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct
 {
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	/* retransmit timer is used for feature negotiation throughout
-	 * connection.  In this case, no packet is re-transmitted, but rather an
-	 * ack is generated and pending changes are placed into its options.
-	 */
-	if (sk->sk_send_head = NULL) {
-		dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk);
-		if (sk->sk_state = DCCP_OPEN)
-			dccp_send_ack(sk);
-		goto backoff;
-	}
-
 	/*
 	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
 	 * sent, no need to retransmit, this sock is dead.
@@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct
 		return;
 	}
 
-backoff:
 	icsk->icsk_backoff++;
 
 	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 2/4] dccp: Registration routines for changing feature values
@ 2008-11-12  6:37                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

dccp: Registration routines for changing feature values

Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.

These are internal-only routines and therefore start with `__feat_register'.

It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccids/ccid2.c |    6 -
 net/dccp/feat.c        |  192 +++++++++++++++++++++++++++++++++++++++++++------
 net/dccp/feat.h        |   25 ++++++
 net/dccp/proto.c       |    2 
 4 files changed, 197 insertions(+), 28 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,15 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+/*
+ * Known limit values
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
 	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
@@ -75,6 +84,20 @@ static inline u8 dccp_feat_genopt(struct
 	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
 }
 
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -97,6 +120,6 @@ extern int  dccp_feat_confirm_recv(struc
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_init(struct sock *sk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
 	return dccp_feat_table[idx].reconciliation;
 }
 
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+	/*
+	 * There are no default values for unknown features, so encountering a
+	 * negative index here indicates a serious problem somewhere else.
+	 */
+	DCCP_BUG_ON(idx < 0);
+
+	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -155,6 +167,63 @@ static void dccp_feat_entry_destructor(s
  * - list is sorted in increasing order of feature number (faster lookup)
  */
 
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num == feat && entry->is_local == local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
 static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
 {
 	list_del(&entry->node);
@@ -190,6 +259,95 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val == DCCPC_CCID2 || val == DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list == NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -726,42 +884,30 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
-{
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
-
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
-	}
-	return rc;
-}
-
-int dccp_feat_init(struct dccp_minisock *dmsk)
+int dccp_feat_init(struct sock *sk)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
+				&dmsk->dccpms_tx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
+				&dmsk->dccpms_rx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dmsk->dccpms_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, cons
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
+		int rc = dccp_feat_init(sk);
 
 		if (rc)
 			return rc;
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(str
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val == dp->dccps_l_ack_ratio)
 		return;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 2/4] dccp: Registration routines for changing feature
@ 2008-11-12  6:37                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: dccp

dccp: Registration routines for changing feature values

Two registration routines, for SP and NN features, are provided by this patch,
replacing a previous routine which was used for both feature types.

These are internal-only routines and therefore start with `__feat_register'.

It further exports the known limits of Sequence Window and Ack Ratio as symbolic
constants.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccids/ccid2.c |    6 -
 net/dccp/feat.c        |  192 +++++++++++++++++++++++++++++++++++++++++++------
 net/dccp/feat.h        |   25 ++++++
 net/dccp/proto.c       |    2 
 4 files changed, 197 insertions(+), 28 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -14,6 +14,15 @@
 #include <linux/types.h>
 #include "dccp.h"
 
+/*
+ * Known limit values
+ */
+/* Ack Ratio takes 2-byte integer values (11.3) */
+#define DCCPF_ACK_RATIO_MAX	0xFFFF
+/* Wmin2 and Wmax=2^46-1 from 7.5.2 */
+#define DCCPF_SEQ_WMIN		32
+#define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
 	FEAT_AT_TX   = 2,	/* located at TX side of half-connection  */
@@ -75,6 +84,20 @@ static inline u8 dccp_feat_genopt(struct
 	return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
 }
 
+/**
+ * struct ccid_dependency  -  Track changes resulting from choosing a CCID
+ * @dependent_feat: one of %dccp_feature_numbers
+ * @is_local: local (1) or remote (0) @dependent_feat
+ * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
+ * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
+ */
+struct ccid_dependency {
+	u8	dependent_feat;
+	bool	is_local:1,
+		is_mandatory:1;
+	u8	val;
+};
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -97,6 +120,6 @@ extern int  dccp_feat_confirm_recv(struc
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct dccp_minisock *dmsk);
+extern int  dccp_feat_init(struct sock *sk);
 
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
 	return dccp_feat_table[idx].reconciliation;
 }
 
+static int dccp_feat_default_value(u8 feat_num)
+{
+	int idx = dccp_feat_index(feat_num);
+	/*
+	 * There are no default values for unknown features, so encountering a
+	 * negative index here indicates a serious problem somewhere else.
+	 */
+	DCCP_BUG_ON(idx < 0);
+
+	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -155,6 +167,63 @@ static void dccp_feat_entry_destructor(s
  * - list is sorted in increasing order of feature number (faster lookup)
  */
 
+/**
+ * dccp_feat_entry_new  -  Central list update routine (called by all others)
+ * @head:  list to add to
+ * @feat:  feature number
+ * @local: whether the local (1) or remote feature with number @feat is meant
+ * This is the only constructor and serves to ensure the above invariants.
+ */
+static struct dccp_feat_entry *
+	      dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, head, node)
+		if (entry->feat_num = feat && entry->is_local = local) {
+			dccp_feat_val_destructor(entry->feat_num, &entry->val);
+			return entry;
+		} else if (entry->feat_num > feat) {
+			head = &entry->node;
+			break;
+		}
+
+	entry = kmalloc(sizeof(*entry), gfp_any());
+	if (entry != NULL) {
+		entry->feat_num = feat;
+		entry->is_local = local;
+		list_add_tail(&entry->node, head);
+	}
+	return entry;
+}
+
+/**
+ * dccp_feat_push_change  -  Add/overwrite a Change option in the list
+ * @fn_list: feature-negotiation list to update
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is meant
+ * @needs_mandatory: whether to use Mandatory feature negotiation options
+ * @fval: pointer to NN/SP value to be inserted (will be copied)
+ */
+static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
+				 u8 mandatory, dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return -ENOMEM;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_INITIALISING;
+	new->needs_confirm   = 0;
+	new->empty_confirm   = 0;
+	new->val	     = *fval;
+	new->needs_mandatory = mandatory;
+
+	return 0;
+}
+
 static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
 {
 	list_del(&entry->node);
@@ -190,6 +259,95 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
+{
+	switch (feat_num) {
+	case DCCPF_ACK_RATIO:
+		return val <= DCCPF_ACK_RATIO_MAX;
+	case DCCPF_SEQUENCE_WINDOW:
+		return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
+	}
+	return 0;	/* feature unknown - so we can't tell */
+}
+
+/* check that SP values are within the ranges defined in RFC 4340 */
+static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
+{
+	switch (feat_num) {
+	case DCCPF_CCID:
+		return val = DCCPC_CCID2 || val = DCCPC_CCID3;
+	/* Type-check Boolean feature values: */
+	case DCCPF_SHORT_SEQNOS:
+	case DCCPF_ECN_INCAPABLE:
+	case DCCPF_SEND_ACK_VECTOR:
+	case DCCPF_SEND_NDP_COUNT:
+	case DCCPF_DATA_CHECKSUM:
+	case DCCPF_SEND_LEV_RATE:
+		return val < 2;
+	case DCCPF_MIN_CSUM_COVER:
+		return val < 16;
+	}
+	return 0;			/* feature unknown */
+}
+
+static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
+{
+	if (sp_list = NULL || sp_len < 1)
+		return 0;
+	while (sp_len--)
+		if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
+			return 0;
+	return 1;
+}
+
+/**
+ * __feat_register_nn  -  Register new NN value on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an NN feature from %dccp_feature_numbers
+ * @mandatory: use Mandatory option if 1
+ * @nn_val: value to register (restricted to 4 bytes)
+ * Note that NN features are local by definition (RFC 4340, 6.3.2).
+ */
+static int __feat_register_nn(struct list_head *fn, u8 feat,
+			      u8 mandatory, u64 nn_val)
+{
+	dccp_feat_val fval = { .nn = nn_val };
+
+	if (dccp_feat_type(feat) != FEAT_NN ||
+	    !dccp_feat_is_valid_nn_val(feat, nn_val))
+		return -EINVAL;
+
+	/* Don't bother with default values, they will be activated anyway. */
+	if (nn_val - (u64)dccp_feat_default_value(feat) = 0)
+		return 0;
+
+	return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
+}
+
+/**
+ * __feat_register_sp  -  Register new SP value/list on socket
+ * @fn: feature-negotiation list to register with
+ * @feat: an SP feature from %dccp_feature_numbers
+ * @is_local: whether the local (1) or the remote (0) @feat is meant
+ * @mandatory: use Mandatory option if 1
+ * @sp_val: SP value followed by optional preference list
+ * @sp_len: length of @sp_val in bytes
+ */
+static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
+			      u8 mandatory, u8 const *sp_val, u8 sp_len)
+{
+	dccp_feat_val fval;
+
+	if (dccp_feat_type(feat) != FEAT_SP ||
+	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
+		return -EINVAL;
+
+	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
+		return -ENOMEM;
+
+	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
+}
+
 int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
 		     u8 *val, u8 len, gfp_t gfp)
 {
@@ -726,42 +884,30 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
-static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
-			    u8 *val, u8 len)
-{
-	int rc = -ENOMEM;
-	u8 *copy = kmemdup(val, len, GFP_KERNEL);
-
-	if (copy != NULL) {
-		rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
-		if (rc)
-			kfree(copy);
-	}
-	return rc;
-}
-
-int dccp_feat_init(struct dccp_minisock *dmsk)
+int dccp_feat_init(struct sock *sk)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_minisock *dmsk = dccp_msk(sk);
 	int rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
+	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
+	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
 	/* CCID L */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
-			      &dmsk->dccpms_tx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
+				&dmsk->dccpms_tx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* CCID R */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
-			      &dmsk->dccpms_rx_ccid, 1);
+	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
+				&dmsk->dccpms_rx_ccid, 1);
 	if (rc)
 		goto out;
 
 	/* Ack ratio */
-	rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
-			      &dmsk->dccpms_ack_ratio, 1);
+	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
+				dmsk->dccpms_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, cons
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(dmsk);
+		int rc = dccp_feat_init(sk);
 
 		if (rc)
 			return rc;
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -25,7 +25,7 @@
 /*
  * This implementation should follow RFC 4341
  */
-
+#include "../feat.h"
 #include "../ccid.h"
 #include "../dccp.h"
 #include "ccid2.h"
@@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(str
 		DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio);
 		val = max_ratio;
 	}
-	if (val > 0xFFFF)		/* RFC 4340, 11.3 */
-		val = 0xFFFF;
+	if (val > DCCPF_ACK_RATIO_MAX)
+		val = DCCPF_ACK_RATIO_MAX;
 
 	if (val = dp->dccps_l_ack_ratio)
 		return;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 3/4] dccp: Query supported CCIDs
@ 2008-11-12  6:37                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

dccp: Query supported CCIDs

This provides a data structure to record which CCIDs are locally supported
and three accessor functions:
 - a test function for internal use which is used to validate CCID requests
   made by the user;
 - a copy function so that the list can be used for feature-negotiation;   
 - documented getsockopt() support so that the user can query capabilities.

The data structure is a table which is filled in at compile-time with the
list of available CCIDs (which in turn depends on the Kconfig choices).

Using the copy function for cloning the list of supported CCIDs is useful for
feature negotiation, since the negotiation is now with the full list of available
CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation 
will not fail if the peer requests to use CCID3 instead of CCID2. 

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    4 +++
 include/linux/dccp.h              |    1 
 net/dccp/ccid.c                   |   48 ++++++++++++++++++++++++++++++++++++++
 net/dccp/ccid.h                   |    5 +++
 net/dccp/feat.c                   |    4 +++
 net/dccp/proto.c                  |    2 +
 6 files changed, 64 insertions(+)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct soc
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const stru
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -342,6 +342,10 @@ static int __feat_register_sp(struct lis
 	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
 		return -EINVAL;
 
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
 	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
 		return -ENOMEM;
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(stru
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] == builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array == NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 3/4] dccp: Query supported CCIDs
@ 2008-11-12  6:37                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: dccp

dccp: Query supported CCIDs

This provides a data structure to record which CCIDs are locally supported
and three accessor functions:
 - a test function for internal use which is used to validate CCID requests
   made by the user;
 - a copy function so that the list can be used for feature-negotiation;   
 - documented getsockopt() support so that the user can query capabilities.

The data structure is a table which is filled in at compile-time with the
list of available CCIDs (which in turn depends on the Kconfig choices).

Using the copy function for cloning the list of supported CCIDs is useful for
feature negotiation, since the negotiation is now with the full list of available
CCIDs (e.g. {2, 3}) instead of the default value {2}. This means negotiation 
will not fail if the peer requests to use CCID3 instead of CCID2. 

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    4 +++
 include/linux/dccp.h              |    1 
 net/dccp/ccid.c                   |   48 ++++++++++++++++++++++++++++++++++++++
 net/dccp/ccid.h                   |    5 +++
 net/dccp/feat.c                   |    4 +++
 net/dccp/proto.c                  |    2 +
 6 files changed, 64 insertions(+)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -57,6 +57,10 @@ can be set before calling bind().
 DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet
 size (application payload size) in bytes, see RFC 4340, section 14.
 
+DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
+supported by the endpoint (see include/linux/dccp.h for symbolic constants).
+The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -209,6 +209,7 @@ struct dccp_so_feat {
 #define DCCP_SOCKOPT_SERVER_TIMEWAIT	6
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
+#define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -649,6 +649,8 @@ static int do_dccp_getsockopt(struct soc
 	case DCCP_SOCKOPT_GET_CUR_MPS:
 		val = dp->dccps_mss_cache;
 		break;
+	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
+		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -103,6 +103,11 @@ static inline void *ccid_priv(const stru
 	return (void *)ccid->ccid_priv;
 }
 
+extern bool ccid_support_check(u8 const *ccid_array, u8 array_len);
+extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
+extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+					  char __user *, int __user *);
+
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -342,6 +342,10 @@ static int __feat_register_sp(struct lis
 	    !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
 		return -EINVAL;
 
+	/* Avoid negotiating alien CCIDs by only advertising supported ones */
+	if (feat = DCCPF_CCID && !ccid_support_check(sp_val, sp_len))
+		return -EOPNOTSUPP;
+
 	if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
 		return -ENOMEM;
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -13,6 +13,13 @@
 
 #include "ccid.h"
 
+static u8 builtin_ccids[] = {
+	DCCPC_CCID2,		/* CCID2 is supported by default */
+#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
+	DCCPC_CCID3,
+#endif
+};
+
 static struct ccid_operations *ccids[CCID_MAX];
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 static atomic_t ccids_lockct = ATOMIC_INIT(0);
@@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(stru
 	}
 }
 
+/* check that up to @array_len members in @ccid_array are supported */
+bool ccid_support_check(u8 const *ccid_array, u8 array_len)
+{
+	u8 i, j, found;
+
+	for (i = 0, found = 0; i < array_len; i++, found = 0) {
+		for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++)
+			found = (ccid_array[i] = builtin_ccids[j]);
+		if (!found)
+			return false;
+	}
+	return true;
+}
+
+/**
+ * ccid_get_builtin_ccids  -  Provide copy of `builtin' CCID array
+ * @ccid_array: pointer to copy into
+ * @array_len: value to return length into
+ * This function allocates memory - caller must see that it is freed after use.
+ */
+int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len)
+{
+	*ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any());
+	if (*ccid_array = NULL)
+		return -ENOBUFS;
+	*array_len = ARRAY_SIZE(builtin_ccids);
+	return 0;
+}
+
+int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
+				    char __user *optval, int __user *optlen)
+{
+	if (len < sizeof(builtin_ccids))
+		return -EINVAL;
+
+	if (put_user(sizeof(builtin_ccids), optlen) ||
+	    copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids)))
+		return -EFAULT;
+	return 0;
+}
+
 int ccid_register(struct ccid_operations *ccid_ops)
 {
 	int err = -ENOBUFS;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
@ 2008-11-12  6:37                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

dccp: Resolve dependencies of features on choice of CCID

This provides a missing link in the code chain, as several features implicitly
depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).

For Send Ack Vector, the situation is as follows:
 * since CCID2 mandates the use of Ack Vectors, there is no point in allowing 
   endpoints which use CCID2 to disable Ack Vector features such a connection;

 * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
   with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);

 * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
   negotiable. However, this implies that the code negotiating the use of Ack
   Vectors also supports it (i.e. is able to supply and to either parse or
   ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
   Vector support), the use of Ack Vectors is here disabled, with a comment
   in the source code.

An analogous consideration arises for the Send Loss Event Rate feature,
since the CCID-3 implementation does not support the loss interval options
of RFC 4342. To make such use explicit, corresponding feature-negotiation
options are inserted which signal the use of the loss event rate option,
as it is used by the CCID3 code.

Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.

The patch implements this as a function which is called after the user has
made all other registrations for changing default values of features.

The table is variable-length, the reserved (and hence for feature-negotiation
invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
is used to mark the end of the table.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 
 net/dccp/feat.c   |  160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |    4 +
 net/dccp/proto.c  |    3 +
 4 files changed, 168 insertions(+)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -400,6 +400,166 @@ int dccp_feat_change(struct dccp_minisoc
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table == NULL);
+
+	for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
+	return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(stru
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of
@ 2008-11-12  6:37                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-12  6:37 UTC (permalink / raw)
  To: dccp

dccp: Resolve dependencies of features on choice of CCID

This provides a missing link in the code chain, as several features implicitly
depend and/or rely on the choice of CCID. Most notably, this is the Send Ack Vector
feature, but also Ack Ratio and Send Loss Event Rate (also taken care of).

For Send Ack Vector, the situation is as follows:
 * since CCID2 mandates the use of Ack Vectors, there is no point in allowing 
   endpoints which use CCID2 to disable Ack Vector features such a connection;

 * a peer with a TX CCID of CCID2 will always expect Ack Vectors, and a peer
   with a RX CCID of CCID2 must always send Ack Vectors (RFC 4341, sec. 4);

 * for all other CCIDs, the use of (Send) Ack Vector is optional and thus
   negotiable. However, this implies that the code negotiating the use of Ack
   Vectors also supports it (i.e. is able to supply and to either parse or
   ignore received Ack Vectors). Since this is not the case (CCID-3 has no Ack
   Vector support), the use of Ack Vectors is here disabled, with a comment
   in the source code.

An analogous consideration arises for the Send Loss Event Rate feature,
since the CCID-3 implementation does not support the loss interval options
of RFC 4342. To make such use explicit, corresponding feature-negotiation
options are inserted which signal the use of the loss event rate option,
as it is used by the CCID3 code.

Lastly, the values of the Ack Ratio feature are matched to the choice of CCID.

The patch implements this as a function which is called after the user has
made all other registrations for changing default values of features.

The table is variable-length, the reserved (and hence for feature-negotiation
invalid, confirmed by considering section 19.4 of RFC 4340) feature number `0'
is used to mark the end of the table.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 
 net/dccp/feat.c   |  160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |    4 +
 net/dccp/proto.c  |    3 +
 4 files changed, 168 insertions(+)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -442,6 +442,7 @@ static inline int dccp_ack_pending(const
 	       inet_csk_ack_scheduled(sk);
 }
 
+extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -400,6 +400,166 @@ int dccp_feat_change(struct dccp_minisoc
 
 EXPORT_SYMBOL_GPL(dccp_feat_change);
 
+/*
+ *	Tracking features whose value depend on the choice of CCID
+ *
+ * This is designed with an extension in mind so that a list walk could be done
+ * before activating any features. However, the existing framework was found to
+ * work satisfactorily up until now, the automatic verification is left open.
+ * When adding new CCIDs, add a corresponding dependency table here.
+ */
+static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local)
+{
+	static const struct ccid_dependency ccid2_dependencies[2][2] = {
+		/*
+		 * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX
+		 * feature and Send Ack Vector is an RX feature, `is_local'
+		 * needs to be reversed.
+		 */
+		{	/* Dependencies of the receiver-side (remote) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		},
+		{	/* Dependencies of the sender-side (local) CCID2 */
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	static const struct ccid_dependency ccid3_dependencies[2][5] = {
+		{	/*
+			 * Dependencies of the receiver-side CCID3
+			 */
+			{	/* locally disable Ack Vectors */
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* see below why Send Loss Event Rate is on */
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= true,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* NDP Count is needed as per RFC 4342, 6.1.1 */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 },
+		},
+		{	/*
+			 * CCID3 at the TX side: we request that the HC-receiver
+			 * will not send Ack Vectors (they will be ignored, so
+			 * Mandatory is not set); we enable Send Loss Event Rate
+			 * (Mandatory since the implementation does not support
+			 * the Loss Intervals option of RFC 4342, 8.6).
+			 * The last two options are for peer's information only.
+			*/
+			{
+				.dependent_feat	= DCCPF_SEND_ACK_VECTOR,
+				.is_local	= false,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{
+				.dependent_feat	= DCCPF_SEND_LEV_RATE,
+				.is_local	= false,
+				.is_mandatory	= true,
+				.val		= 1
+			},
+			{	/* this CCID does not support Ack Ratio */
+				.dependent_feat	= DCCPF_ACK_RATIO,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 0
+			},
+			{	/* tell receiver we are sending NDP counts */
+				.dependent_feat	= DCCPF_SEND_NDP_COUNT,
+				.is_local	= true,
+				.is_mandatory	= false,
+				.val		= 1
+			},
+			{ 0, 0, 0, 0 }
+		}
+	};
+	switch (ccid) {
+	case DCCPC_CCID2:
+		return ccid2_dependencies[is_local];
+	case DCCPC_CCID3:
+		return ccid3_dependencies[is_local];
+	default:
+		return NULL;
+	}
+}
+
+/**
+ * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID
+ * @fn: feature-negotiation list to update
+ * @id: CCID number to track
+ * @is_local: whether TX CCID (1) or RX CCID (0) is meant
+ * This function needs to be called after registering all other features.
+ */
+static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local)
+{
+	const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local);
+	int i, rc = (table = NULL);
+
+	for (i = 0; rc = 0 && table[i].dependent_feat != DCCPF_RESERVED; i++)
+		if (dccp_feat_type(table[i].dependent_feat) = FEAT_SP)
+			rc = __feat_register_sp(fn, table[i].dependent_feat,
+						    table[i].is_local,
+						    table[i].is_mandatory,
+						    &table[i].val, 1);
+		else
+			rc = __feat_register_nn(fn, table[i].dependent_feat,
+						    table[i].is_mandatory,
+						    table[i].val);
+	return rc;
+}
+
+/**
+ * dccp_feat_finalise_settings  -  Finalise settings before starting negotiation
+ * @dp: client or listening socket (settings will be inherited)
+ * This is called after all registrations (socket initialisation, sysctls, and
+ * sockopt calls), and before sending the first packet containing Change options
+ * (ie. client-Request or server-Response), to ensure internal consistency.
+ */
+int dccp_feat_finalise_settings(struct dccp_sock *dp)
+{
+	struct list_head *fn = &dp->dccps_featneg;
+	struct dccp_feat_entry *entry;
+	int i = 2, ccids[2] = { -1, -1 };
+
+	/*
+	 * Propagating CCIDs:
+	 * 1) not useful to propagate CCID settings if this host advertises more
+	 *    than one CCID: the choice of CCID  may still change - if this is
+	 *    the client, or if this is the server and the client sends
+	 *    singleton CCID values.
+	 * 2) since is that propagate_ccid changes the list, we defer changing
+	 *    the sorted list until after the traversal.
+	 */
+	list_for_each_entry(entry, fn, node)
+		if (entry->feat_num = DCCPF_CCID && entry->val.sp.len = 1)
+			ccids[entry->is_local] = entry->val.sp.vec[0];
+	while (i--)
+		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
+			return -1;
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -469,6 +469,10 @@ int dccp_connect(struct sock *sk)
 	struct sk_buff *skb;
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
+	/* do not connect if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dccp_sk(sk)))
+		return -EPROTO;
+
 	dccp_connect_init(sk);
 
 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -278,6 +278,9 @@ static inline int dccp_listen_start(stru
 	struct dccp_sock *dp = dccp_sk(sk);
 
 	dp->dccps_role = DCCP_ROLE_LISTEN;
+	/* do not start to listen if feature negotiation setup fails */
+	if (dccp_feat_finalise_settings(dp))
+		return -EPROTO;
 	return inet_csk_listen_start(sk, backlog);
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase
  2008-11-12  6:37                                                                     ` v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup Gerrit Renker
@ 2008-11-12  8:49                                                                       ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:09 +0100

> dccp: Limit feature negotiation to connection setup phase

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 1/4] dccp: Limit feature negotiation to connection
@ 2008-11-12  8:49                                                                       ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:09 +0100

> dccp: Limit feature negotiation to connection setup phase

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 2/4] dccp: Registration routines for changing feature values
  2008-11-12  6:37                                                                       ` v2 [PATCH 2/4] dccp: Registration routines for changing feature Gerrit Renker
@ 2008-11-12  8:49                                                                         ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:22 +0100

> dccp: Registration routines for changing feature values

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 2/4] dccp: Registration routines for changing
@ 2008-11-12  8:49                                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:22 +0100

> dccp: Registration routines for changing feature values

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 3/4] dccp: Query supported CCIDs
  2008-11-12  6:37                                                                         ` Gerrit Renker
@ 2008-11-12  8:49                                                                           ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:34 +0100

> dccp: Query supported CCIDs

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 3/4] dccp: Query supported CCIDs
@ 2008-11-12  8:49                                                                           ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:34 +0100

> dccp: Query supported CCIDs

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID
  2008-11-12  6:37                                                                           ` v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of Gerrit Renker
@ 2008-11-12  8:49                                                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:45 +0100

> dccp: Resolve dependencies of features on choice of CCID

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: v2 [PATCH 4/4] dccp: Resolve dependencies of features on
@ 2008-11-12  8:49                                                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-12  8:49 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Wed, 12 Nov 2008 07:37:45 +0100

> dccp: Resolve dependencies of features on choice of CCID

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/5] dccp: Feature negotiation - begin of Part II (core)
@ 2008-11-15 12:11                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

I would like to continue with the patches in the Core set, the second
out of three blocks. If the time of submission is inconvenient, please
let me know, I will then resubmit later.

Patches have been compile-tested with sparse checking enabled.

Gerrit


Commit summary:
---------------
The set begins the second set (out of three) of the feature negotiation patches,
to provide a self-contained feature negotiation API for the DCCP protocol.

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

Within these blocks, this set introduces the first parts of a new API to 
communicate feature-negotiation changes via socket options.


List of patches in this set:
----------------------------
Patch #1: Provides a mechanism to resolve CCID-dependent features. Since
          CCIDs are a server-priority feature, this is done by the server.
Patch #2: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #3: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #4: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #5: Tidies up the setsockopt interface for new additions.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=1a2c162f1f3fee8965ef4ea3f509cd5a88be6c4f


Patch stats:
------------
 Documentation/networking/dccp.txt |    3 
 include/linux/dccp.h              |   13 ---
 net/dccp/dccp.h                   |    2 
 net/dccp/feat.c                   |  109 ++++++++++++++++++--------------
 net/dccp/feat.h                   |    5 -
 net/dccp/minisocks.c              |    1 
 net/dccp/options.c                |    1 
 net/dccp/output.c                 |   13 ++-
 net/dccp/proto.c                  |  129 +++++++++++++++-----------------------
 net/dccp/sysctl.c                 |    7 --
 10 files changed, 133 insertions(+), 150 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/5] dccp: Feature negotiation - begin of Part II (core)
@ 2008-11-15 12:11                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: dccp

Hi Dave,

I would like to continue with the patches in the Core set, the second
out of three blocks. If the time of submission is inconvenient, please
let me know, I will then resubmit later.

Patches have been compile-tested with sparse checking enabled.

Gerrit


Commit summary:
---------------
The set begins the second set (out of three) of the feature negotiation patches,
to provide a self-contained feature negotiation API for the DCCP protocol.

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

Within these blocks, this set introduces the first parts of a new API to 
communicate feature-negotiation changes via socket options.


List of patches in this set:
----------------------------
Patch #1: Provides a mechanism to resolve CCID-dependent features. Since
          CCIDs are a server-priority feature, this is done by the server.
Patch #2: Deprecates old featneg API, as it was dangerous/clumsy.
Patch #3: Support to negotiate checksum-coverage values (as in UDP-Lite).
Patch #4: Deprecates Ack Ratio sysctl, to enable automatic updating.
Patch #5: Tidies up the setsockopt interface for new additions.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;h\x1a2c162f1f3fee8965ef4ea3f509cd5a88be6c4f


Patch stats:
------------
 Documentation/networking/dccp.txt |    3 
 include/linux/dccp.h              |   13 ---
 net/dccp/dccp.h                   |    2 
 net/dccp/feat.c                   |  109 ++++++++++++++++++--------------
 net/dccp/feat.h                   |    5 -
 net/dccp/minisocks.c              |    1 
 net/dccp/options.c                |    1 
 net/dccp/output.c                 |   13 ++-
 net/dccp/proto.c                  |  129 +++++++++++++++-----------------------
 net/dccp/sysctl.c                 |    7 --
 10 files changed, 133 insertions(+), 150 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
@ 2008-11-15 12:11                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This adds a hook to resolve features whose value depends on the choice of
CCID. It is done at the server since it can only be done after the CCID
values have been negotiated; i.e. the client will add its CCID preference
list on the Change options sent in the Request, which will be reconciled
with the local preference list of the server.

The concept is documented on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
				implementation_notes.html#ccid_dependencies

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |   37 +++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |   13 +++++++++----
 3 files changed, 47 insertions(+), 4 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 }
 
 extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
+extern int  dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -166,6 +166,18 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
  * - SP values are always freshly allocated
  * - list is sorted in increasing order of feature number (faster lookup)
  */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num == feat_num && entry->is_local == is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
 
 /**
  * dccp_feat_entry_new  -  Central list update routine (called by all others)
@@ -560,6 +572,31 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	return 0;
 }
 
+/**
+ * dccp_feat_server_ccid_dependencies  -  Resolve CCID-dependent features
+ * It is the server which resolves the dependencies once the CCID has been
+ * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
+ */
+int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
+{
+	struct list_head *fn = &dreq->dreq_featneg;
+	struct dccp_feat_entry *entry;
+	u8 is_local, ccid;
+
+	for (is_local = 0; is_local <= 1; is_local++) {
+		entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
+
+		if (entry != NULL && !entry->empty_confirm)
+			ccid = entry->val.sp.vec[0];
+		else
+			ccid = dccp_feat_default_value(DCCPF_CCID);
+
+		if (dccp_feat_propagate_ccid(fn, ccid, is_local))
+			return -1;
+	}
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -339,10 +339,12 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
 
-	if (dccp_insert_options_rsk(dreq, skb)) {
-		kfree_skb(skb);
-		return NULL;
-	}
+	/* Resolve feature dependencies resulting from choice of CCID */
+	if (dccp_feat_server_ccid_dependencies(dreq))
+		goto response_failed;
+
+	if (dccp_insert_options_rsk(dreq, skb))
+		goto response_failed;
 
 	/* Build and checksum header */
 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
@@ -363,6 +365,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	inet_rsk(req)->acked = 1;
 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 	return skb;
+response_failed:
+	kfree_skb(skb);
+	return NULL;
 }
 
 EXPORT_SYMBOL_GPL(dccp_make_response);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
@ 2008-11-15 12:11                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: dccp

This adds a hook to resolve features whose value depends on the choice of
CCID. It is done at the server since it can only be done after the CCID
values have been negotiated; i.e. the client will add its CCID preference
list on the Change options sent in the Request, which will be reconciled
with the local preference list of the server.

The concept is documented on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
				implementation_notes.html#ccid_dependencies

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h   |    1 +
 net/dccp/feat.c   |   37 +++++++++++++++++++++++++++++++++++++
 net/dccp/output.c |   13 +++++++++----
 3 files changed, 47 insertions(+), 4 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 }
 
 extern int  dccp_feat_finalise_settings(struct dccp_sock *dp);
+extern int  dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -166,6 +166,18 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
  * - SP values are always freshly allocated
  * - list is sorted in increasing order of feature number (faster lookup)
  */
+static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list,
+						     u8 feat_num, bool is_local)
+{
+	struct dccp_feat_entry *entry;
+
+	list_for_each_entry(entry, fn_list, node)
+		if (entry->feat_num = feat_num && entry->is_local = is_local)
+			return entry;
+		else if (entry->feat_num > feat_num)
+			break;
+	return NULL;
+}
 
 /**
  * dccp_feat_entry_new  -  Central list update routine (called by all others)
@@ -560,6 +572,31 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	return 0;
 }
 
+/**
+ * dccp_feat_server_ccid_dependencies  -  Resolve CCID-dependent features
+ * It is the server which resolves the dependencies once the CCID has been
+ * fully negotiated. If no CCID has been negotiated, it uses the default CCID.
+ */
+int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
+{
+	struct list_head *fn = &dreq->dreq_featneg;
+	struct dccp_feat_entry *entry;
+	u8 is_local, ccid;
+
+	for (is_local = 0; is_local <= 1; is_local++) {
+		entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local);
+
+		if (entry != NULL && !entry->empty_confirm)
+			ccid = entry->val.sp.vec[0];
+		else
+			ccid = dccp_feat_default_value(DCCPF_CCID);
+
+		if (dccp_feat_propagate_ccid(fn, ccid, is_local))
+			return -1;
+	}
+	return 0;
+}
+
 static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -339,10 +339,12 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
 
-	if (dccp_insert_options_rsk(dreq, skb)) {
-		kfree_skb(skb);
-		return NULL;
-	}
+	/* Resolve feature dependencies resulting from choice of CCID */
+	if (dccp_feat_server_ccid_dependencies(dreq))
+		goto response_failed;
+
+	if (dccp_insert_options_rsk(dreq, skb))
+		goto response_failed;
 
 	/* Build and checksum header */
 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
@@ -363,6 +365,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
 	inet_rsk(req)->acked = 1;
 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
 	return skb;
+response_failed:
+	kfree_skb(skb);
+	return NULL;
 }
 
 EXPORT_SYMBOL_GPL(dccp_make_response);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Deprecate old setsockopt framework
@ 2008-11-15 12:11                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

The previous setsockopt interface, which passed socket options via struct
dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
ugly code since the old approach did not distinguish between NN and SP values.

This patch removes the old setsockopt interface and replaces it with two new
functions to register NN/SP values for feature negotiation. 
These are essentially wrappers around the internal __feat_register functions,
with checking added to avoid

 * wrong usage (type);
 * changing values while the connection is in progress.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 include/linux/dccp.h |    7 -----
 net/dccp/feat.c      |   72 ++++++++++++++++++-------------------------------
 net/dccp/feat.h      |    5 ++-
 net/dccp/proto.c     |   53 +-----------------------------------
 4 files changed, 32 insertions(+), 105 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -193,13 +193,6 @@ enum dccp_feature_numbers {
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
-/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
-struct dccp_so_feat {
-	__u8 dccpsf_feat;
-	__u8 __user *dccpsf_val;
-	__u8 dccpsf_len;
-};
-
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE	1 /* XXX deprecated, without effect */
 #define DCCP_SOCKOPT_SERVICE		2
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -364,53 +364,35 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
 }
 
-int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-		     u8 *val, u8 len, gfp_t gfp)
-{
-	struct dccp_opt_pend *opt;
-
-	dccp_feat_debug(type, feature, *val);
-
-	if (len > 3) {
-		DCCP_WARN("invalid length %d\n", len);
+/**
+ * dccp_feat_register_sp  -  Register requests to change SP feature values
+ * @sk: client or listening socket
+ * @feat: one of %dccp_feature_numbers
+ * @is_local: whether the local (1) or remote (0) @feat is meant
+ * @list: array of preferred values, in descending order of preference
+ * @len: length of @list in bytes
+ */
+int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+			  u8 const *list, u8 len)
+{	 /* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_SP)
 		return -EINVAL;
-	}
-	/* XXX add further sanity checks */
-
-	/* check if that feature is already being negotiated */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* ok we found a negotiation for this option already */
-		if (opt->dccpop_feat == feature && opt->dccpop_type == type) {
-			dccp_pr_debug("Replacing old\n");
-			/* replace */
-			BUG_ON(opt->dccpop_val == NULL);
-			kfree(opt->dccpop_val);
-			opt->dccpop_val	 = val;
-			opt->dccpop_len	 = len;
-			opt->dccpop_conf = 0;
-			return 0;
-		}
-	}
-
-	/* negotiation for a new feature */
-	opt = kmalloc(sizeof(*opt), gfp);
-	if (opt == NULL)
-		return -ENOMEM;
-
-	opt->dccpop_type = type;
-	opt->dccpop_feat = feature;
-	opt->dccpop_len	 = len;
-	opt->dccpop_val	 = val;
-	opt->dccpop_conf = 0;
-	opt->dccpop_sc	 = NULL;
-
-	BUG_ON(opt->dccpop_val == NULL);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
-	return 0;
+	return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
+				  0, list, len);
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_change);
+/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
+int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
+{
+	/* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_NN)
+		return -EINVAL;
+	return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
+}
 
 /*
  *	Tracking features whose value depend on the choice of CCID
@@ -1108,7 +1090,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dmsk->dccpms_ack_ratio);
+				dp->dccps_l_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -111,8 +111,9 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
-extern int  dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-			     u8 *val, u8 len, gfp_t gfp);
+extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+				  u8 const *list, u8 len);
+extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
 				  u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,44 +470,6 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
-/* byte 1 is feature.  the rest is the preference list */
-static int dccp_setsockopt_change(struct sock *sk, int type,
-				  struct dccp_so_feat __user *optval)
-{
-	struct dccp_so_feat opt;
-	u8 *val;
-	int rc;
-
-	if (copy_from_user(&opt, optval, sizeof(opt)))
-		return -EFAULT;
-	/*
-	 * rfc4340: 6.1. Change Options
-	 */
-	if (opt.dccpsf_len < 1)
-		return -EINVAL;
-
-	val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
-	if (!val)
-		return -ENOMEM;
-
-	if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
-		rc = -EFAULT;
-		goto out_free_val;
-	}
-
-	rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
-			      val, opt.dccpsf_len, GFP_KERNEL);
-	if (rc)
-		goto out_free_val;
-
-out:
-	return rc;
-
-out_free_val:
-	kfree(val);
-	goto out;
-}
-
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -530,20 +492,9 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = 0;
 		break;
 	case DCCP_SOCKOPT_CHANGE_L:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
-						     (struct dccp_so_feat __user *)
-						     optval);
-		break;
 	case DCCP_SOCKOPT_CHANGE_R:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
-						     (struct dccp_so_feat __user *)
-						     optval);
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		err = 0;
 		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Deprecate old setsockopt framework
@ 2008-11-15 12:11                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: dccp

The previous setsockopt interface, which passed socket options via struct
dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
ugly code since the old approach did not distinguish between NN and SP values.

This patch removes the old setsockopt interface and replaces it with two new
functions to register NN/SP values for feature negotiation. 
These are essentially wrappers around the internal __feat_register functions,
with checking added to avoid

 * wrong usage (type);
 * changing values while the connection is in progress.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 include/linux/dccp.h |    7 -----
 net/dccp/feat.c      |   72 ++++++++++++++++++-------------------------------
 net/dccp/feat.h      |    5 ++-
 net/dccp/proto.c     |   53 +-----------------------------------
 4 files changed, 32 insertions(+), 105 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -193,13 +193,6 @@ enum dccp_feature_numbers {
 	DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
-/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
-struct dccp_so_feat {
-	__u8 dccpsf_feat;
-	__u8 __user *dccpsf_val;
-	__u8 dccpsf_len;
-};
-
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE	1 /* XXX deprecated, without effect */
 #define DCCP_SOCKOPT_SERVICE		2
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -364,53 +364,35 @@ static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
 	return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
 }
 
-int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-		     u8 *val, u8 len, gfp_t gfp)
-{
-	struct dccp_opt_pend *opt;
-
-	dccp_feat_debug(type, feature, *val);
-
-	if (len > 3) {
-		DCCP_WARN("invalid length %d\n", len);
+/**
+ * dccp_feat_register_sp  -  Register requests to change SP feature values
+ * @sk: client or listening socket
+ * @feat: one of %dccp_feature_numbers
+ * @is_local: whether the local (1) or remote (0) @feat is meant
+ * @list: array of preferred values, in descending order of preference
+ * @len: length of @list in bytes
+ */
+int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+			  u8 const *list, u8 len)
+{	 /* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_SP)
 		return -EINVAL;
-	}
-	/* XXX add further sanity checks */
-
-	/* check if that feature is already being negotiated */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* ok we found a negotiation for this option already */
-		if (opt->dccpop_feat = feature && opt->dccpop_type = type) {
-			dccp_pr_debug("Replacing old\n");
-			/* replace */
-			BUG_ON(opt->dccpop_val = NULL);
-			kfree(opt->dccpop_val);
-			opt->dccpop_val	 = val;
-			opt->dccpop_len	 = len;
-			opt->dccpop_conf = 0;
-			return 0;
-		}
-	}
-
-	/* negotiation for a new feature */
-	opt = kmalloc(sizeof(*opt), gfp);
-	if (opt = NULL)
-		return -ENOMEM;
-
-	opt->dccpop_type = type;
-	opt->dccpop_feat = feature;
-	opt->dccpop_len	 = len;
-	opt->dccpop_val	 = val;
-	opt->dccpop_conf = 0;
-	opt->dccpop_sc	 = NULL;
-
-	BUG_ON(opt->dccpop_val = NULL);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending);
-	return 0;
+	return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local,
+				  0, list, len);
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_change);
+/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */
+int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val)
+{
+	/* any changes must be registered before establishing the connection */
+	if (sk->sk_state != DCCP_CLOSED)
+		return -EISCONN;
+	if (dccp_feat_type(feat) != FEAT_NN)
+		return -EINVAL;
+	return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val);
+}
 
 /*
  *	Tracking features whose value depend on the choice of CCID
@@ -1108,7 +1090,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dmsk->dccpms_ack_ratio);
+				dp->dccps_l_ack_ratio);
 out:
 	return rc;
 }
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -111,8 +111,9 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
-extern int  dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
-			     u8 *val, u8 len, gfp_t gfp);
+extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
+				  u8 const *list, u8 len);
+extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
 				  u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,44 +470,6 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
-/* byte 1 is feature.  the rest is the preference list */
-static int dccp_setsockopt_change(struct sock *sk, int type,
-				  struct dccp_so_feat __user *optval)
-{
-	struct dccp_so_feat opt;
-	u8 *val;
-	int rc;
-
-	if (copy_from_user(&opt, optval, sizeof(opt)))
-		return -EFAULT;
-	/*
-	 * rfc4340: 6.1. Change Options
-	 */
-	if (opt.dccpsf_len < 1)
-		return -EINVAL;
-
-	val = kmalloc(opt.dccpsf_len, GFP_KERNEL);
-	if (!val)
-		return -ENOMEM;
-
-	if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) {
-		rc = -EFAULT;
-		goto out_free_val;
-	}
-
-	rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat,
-			      val, opt.dccpsf_len, GFP_KERNEL);
-	if (rc)
-		goto out_free_val;
-
-out:
-	return rc;
-
-out_free_val:
-	kfree(val);
-	goto out;
-}
-
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -530,20 +492,9 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = 0;
 		break;
 	case DCCP_SOCKOPT_CHANGE_L:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L,
-						     (struct dccp_so_feat __user *)
-						     optval);
-		break;
 	case DCCP_SOCKOPT_CHANGE_R:
-		if (optlen != sizeof(struct dccp_so_feat))
-			err = -EINVAL;
-		else
-			err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R,
-						     (struct dccp_so_feat __user *)
-						     optval);
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		err = 0;
 		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: Feature negotiation for minimum-checksum-coverage
@ 2008-11-15 12:11                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +-
 net/dccp/proto.c     |   53 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 42 insertions(+), 15 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,6 +470,42 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
+{
+	u8 *list, len;
+	int i, rc;
+
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
+	/*
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
+	 */
+	if (cscov == 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list == NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	if (rc == 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
+	kfree(list);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -502,20 +538,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: Feature negotiation for minimum-checksum-coverage
@ 2008-11-15 12:11                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: dccp

This provides feature negotiation for server minimum checksum coverage
which so far has been missing.

Since sender/receiver coverage values range only from 0...15, their
type has also been reduced in size from u16 to u4.

Feature-negotiation options are now generated for both sender and receiver
coverage, i.e. when the peer has `forgotten' to enable partial coverage
then feature negotiation will automatically enable (negotiate) the partial
coverage value for this connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    4 +-
 net/dccp/proto.c     |   53 +++++++++++++++++++++++++++++++++++++------------
 2 files changed, 42 insertions(+), 15 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -527,8 +527,8 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
-	__u16				dccps_pcslen;
-	__u16				dccps_pcrlen;
+	__u8				dccps_pcslen:4;
+	__u8				dccps_pcrlen:4;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -470,6 +470,42 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service,
 	return 0;
 }
 
+static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
+{
+	u8 *list, len;
+	int i, rc;
+
+	if (cscov < 0 || cscov > 15)
+		return -EINVAL;
+	/*
+	 * Populate a list of permissible values, in the range cscov...15. This
+	 * is necessary since feature negotiation of single values only works if
+	 * both sides incidentally choose the same value. Since the list starts
+	 * lowest-value first, negotiation will pick the smallest shared value.
+	 */
+	if (cscov = 0)
+		return 0;
+	len = 16 - cscov;
+
+	list = kmalloc(len, GFP_KERNEL);
+	if (list = NULL)
+		return -ENOBUFS;
+
+	for (i = 0; i < len; i++)
+		list[i] = cscov++;
+
+	rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len);
+
+	if (rc = 0) {
+		if (rx)
+			dccp_sk(sk)->dccps_pcrlen = cscov;
+		else
+			dccp_sk(sk)->dccps_pcslen = cscov;
+	}
+	kfree(list);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -502,20 +538,11 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		else
 			dp->dccps_server_timewait = (val != 0);
 		break;
-	case DCCP_SOCKOPT_SEND_CSCOV:	/* sender side, RFC 4340, sec. 9.2 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else
-			dp->dccps_pcslen = val;
+	case DCCP_SOCKOPT_SEND_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, false);
 		break;
-	case DCCP_SOCKOPT_RECV_CSCOV:	/* receiver side, RFC 4340 sec. 9.2.1 */
-		if (val < 0 || val > 15)
-			err = -EINVAL;
-		else {
-			dp->dccps_pcrlen = val;
-			/* FIXME: add feature negotiation,
-			 * ChangeL(MinimumChecksumCoverage, val) */
-		}
+	case DCCP_SOCKOPT_RECV_CSCOV:
+		err = dccp_setsockopt_cscov(sk, val, true);
 		break;
 	default:
 		err = -ENOPROTOOPT;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Deprecate Ack Ratio sysctl
@ 2008-11-15 12:11                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch deprecates the Ack Ratio sysctl, since
 * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
 * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
 * even if it would work in CCID-2, there is no point for a user to change it:
   - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
   - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
     (since waiting for Acks which will never arrive in this window),
   - cwnd is not a user-configurable value.

The only reasonable place for Ack Ratio is to print it for debugging. It is
planned to do this later on, as part of e.g. dccp_probe.

With this patch Ack Ratio is now under full control of feature negotiation:
 * Ack Ratio is resolved as a dependency of the selected CCID;
 * if the chosen CCID supports it (i.e. CCID == CCID-2), Ack Ratio is set to
   the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
   Ratio 2 for both endpoints";
 * what happens then is part of another patch set, since it concerns the
   dynamic update of Ack Ratio while the connection is in full flight.

Thanks to Tomasz Grobelny for discussion leading up to this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    2 --
 net/dccp/dccp.h                   |    1 -
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    1 -
 net/dccp/sysctl.c                 |    7 -------
 6 files changed, 0 insertions(+), 15 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -125,9 +125,6 @@ send_ndp = 1
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
-ack_ratio = 2
-	The default Ack Ratio (sec. 11.3) to use.
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection.
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -368,7 +368,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
-  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
@@ -378,7 +377,6 @@ struct dccp_minisock {
 	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
-	__u8			dccpms_ack_ratio;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_ack_ratio;
 extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -47,7 +47,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
 	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
-	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "ack_ratio",
-		.data		= &sysctl_dccp_feat_ack_ratio,
-		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "send_ackvec",
 		.data		= &sysctl_dccp_feat_send_ack_vector,
 		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Deprecate Ack Ratio sysctl
@ 2008-11-15 12:11                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: dccp

This patch deprecates the Ack Ratio sysctl, since
 * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
 * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
 * even if it would work in CCID-2, there is no point for a user to change it:
   - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
   - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
     (since waiting for Acks which will never arrive in this window),
   - cwnd is not a user-configurable value.

The only reasonable place for Ack Ratio is to print it for debugging. It is
planned to do this later on, as part of e.g. dccp_probe.

With this patch Ack Ratio is now under full control of feature negotiation:
 * Ack Ratio is resolved as a dependency of the selected CCID;
 * if the chosen CCID supports it (i.e. CCID = CCID-2), Ack Ratio is set to
   the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
   Ratio 2 for both endpoints";
 * what happens then is part of another patch set, since it concerns the
   dynamic update of Ack Ratio while the connection is in full flight.

Thanks to Tomasz Grobelny for discussion leading up to this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    2 --
 net/dccp/dccp.h                   |    1 -
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    1 -
 net/dccp/sysctl.c                 |    7 -------
 6 files changed, 0 insertions(+), 15 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -125,9 +125,6 @@ send_ndp = 1
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
-ack_ratio = 2
-	The default Ack Ratio (sec. 11.3) to use.
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection.
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -368,7 +368,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
-  * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
@@ -378,7 +377,6 @@ struct dccp_minisock {
 	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
-	__u8			dccpms_ack_ratio;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_ack_ratio;
 extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -47,7 +47,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
 	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
-	dmsk->dccpms_ack_ratio	     = sysctl_dccp_feat_ack_ratio;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_ack_ratio	      = DCCPF_INITIAL_ACK_RATIO;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "ack_ratio",
-		.data		= &sysctl_dccp_feat_ack_ratio,
-		.maxlen		= sizeof(sysctl_dccp_feat_ack_ratio),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "send_ackvec",
 		.data		= &sysctl_dccp_feat_send_ack_vector,
 		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Tidy up setsockopt calls
@ 2008-11-15 12:11                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This splits the setsockopt calls into two groups, depending on whether an
integer argument (val) is required and whether routines being called do
their own locking.

Some options (such as setting the CCID) use u8 rather than int, so that for
these the test with regard to integer-sizeof can not be used.

The second switch-case statement now only has those statements which need
locking and which make use of `val'.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>
---
 net/dccp/proto.c |   23 ++++++++++++-----------
 1 files changed, 12 insertions(+), 11 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -512,7 +512,17 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
+	switch (optname) {
+	case DCCP_SOCKOPT_PACKET_SIZE:
+		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+		return 0;
+	case DCCP_SOCKOPT_CHANGE_L:
+	case DCCP_SOCKOPT_CHANGE_R:
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		return 0;
+	}
+
+	if (optlen < (int)sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
@@ -523,15 +533,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 
 	lock_sock(sk);
 	switch (optname) {
-	case DCCP_SOCKOPT_PACKET_SIZE:
-		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
-	case DCCP_SOCKOPT_CHANGE_L:
-	case DCCP_SOCKOPT_CHANGE_R:
-		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
-		err = 0;
-		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
@@ -548,8 +549,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Tidy up setsockopt calls
@ 2008-11-15 12:11                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-15 12:11 UTC (permalink / raw)
  To: dccp

This splits the setsockopt calls into two groups, depending on whether an
integer argument (val) is required and whether routines being called do
their own locking.

Some options (such as setting the CCID) use u8 rather than int, so that for
these the test with regard to integer-sizeof can not be used.

The second switch-case statement now only has those statements which need
locking and which make use of `val'.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>
---
 net/dccp/proto.c |   23 ++++++++++++-----------
 1 files changed, 12 insertions(+), 11 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -512,7 +512,17 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	struct dccp_sock *dp = dccp_sk(sk);
 	int val, err = 0;
 
-	if (optlen < sizeof(int))
+	switch (optname) {
+	case DCCP_SOCKOPT_PACKET_SIZE:
+		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
+		return 0;
+	case DCCP_SOCKOPT_CHANGE_L:
+	case DCCP_SOCKOPT_CHANGE_R:
+		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
+		return 0;
+	}
+
+	if (optlen < (int)sizeof(int))
 		return -EINVAL;
 
 	if (get_user(val, (int __user *)optval))
@@ -523,15 +533,6 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 
 	lock_sock(sk);
 	switch (optname) {
-	case DCCP_SOCKOPT_PACKET_SIZE:
-		DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n");
-		err = 0;
-		break;
-	case DCCP_SOCKOPT_CHANGE_L:
-	case DCCP_SOCKOPT_CHANGE_R:
-		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
-		err = 0;
-		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		if (dp->dccps_role != DCCP_ROLE_SERVER)
 			err = -EOPNOTSUPP;
@@ -548,8 +549,8 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		err = -ENOPROTOOPT;
 		break;
 	}
-
 	release_sock(sk);
+
 	return err;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
  2008-11-15 12:11                                                                       ` Gerrit Renker
@ 2008-11-17  6:50                                                                         ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:50 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:15 +0100

> This adds a hook to resolve features whose value depends on the choice of
> CCID. It is done at the server since it can only be done after the CCID
> values have been negotiated; i.e. the client will add its CCID preference
> list on the Change options sent in the Request, which will be reconciled
> with the local preference list of the server.
> 
> The concept is documented on
> http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
> 				implementation_notes.html#ccid_dependencies
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

> +	list_for_each_entry(entry, fn_list, node)
> +		if (entry->feat_num == feat_num && entry->is_local == is_local)
> +			return entry;
> +		else if (entry->feat_num > feat_num)
> +			break;

Personally, I would have put braces around this basic block.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
@ 2008-11-17  6:50                                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:50 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:15 +0100

> This adds a hook to resolve features whose value depends on the choice of
> CCID. It is done at the server since it can only be done after the CCID
> values have been negotiated; i.e. the client will add its CCID preference
> list on the Change options sent in the Request, which will be reconciled
> with the local preference list of the server.
> 
> The concept is documented on
> http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/\
> 				implementation_notes.html#ccid_dependencies
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

> +	list_for_each_entry(entry, fn_list, node)
> +		if (entry->feat_num = feat_num && entry->is_local = is_local)
> +			return entry;
> +		else if (entry->feat_num > feat_num)
> +			break;

Personally, I would have put braces around this basic block.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Deprecate old setsockopt framework
  2008-11-15 12:11                                                                         ` Gerrit Renker
@ 2008-11-17  6:53                                                                           ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:53 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:16 +0100

> The previous setsockopt interface, which passed socket options via struct
> dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
> ugly code since the old approach did not distinguish between NN and SP values.
> 
> This patch removes the old setsockopt interface and replaces it with two new
> functions to register NN/SP values for feature negotiation. 
> These are essentially wrappers around the internal __feat_register functions,
> with checking added to avoid
> 
>  * wrong usage (type);
>  * changing values while the connection is in progress.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Applied, I'll trust your judgment that we can get away with this...

But you have to understand that this is something you should think
about never doing again.  User interfaces are never "oops sorry, we
misdesigned that, we'll just take it away and emit some warning,
fix your app"  Once it's out there, you gotta support it forever.


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Deprecate old setsockopt framework
@ 2008-11-17  6:53                                                                           ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:53 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:16 +0100

> The previous setsockopt interface, which passed socket options via struct
> dccp_so_feat, is complicated/difficult to use. Continuing to support it leads to
> ugly code since the old approach did not distinguish between NN and SP values.
> 
> This patch removes the old setsockopt interface and replaces it with two new
> functions to register NN/SP values for feature negotiation. 
> These are essentially wrappers around the internal __feat_register functions,
> with checking added to avoid
> 
>  * wrong usage (type);
>  * changing values while the connection is in progress.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>

Applied, I'll trust your judgment that we can get away with this...

But you have to understand that this is something you should think
about never doing again.  User interfaces are never "oops sorry, we
misdesigned that, we'll just take it away and emit some warning,
fix your app"  Once it's out there, you gotta support it forever.


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 3/5] dccp: Feature negotiation for minimum-checksum-coverage
  2008-11-15 12:11                                                                           ` Gerrit Renker
@ 2008-11-17  6:53                                                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:53 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:17 +0100

> This provides feature negotiation for server minimum checksum coverage
> which so far has been missing.
> 
> Since sender/receiver coverage values range only from 0...15, their
> type has also been reduced in size from u16 to u4.
> 
> Feature-negotiation options are now generated for both sender and receiver
> coverage, i.e. when the peer has `forgotten' to enable partial coverage
> then feature negotiation will automatically enable (negotiate) the partial
> coverage value for this connection.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 3/5] dccp: Feature negotiation for
@ 2008-11-17  6:53                                                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:53 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:17 +0100

> This provides feature negotiation for server minimum checksum coverage
> which so far has been missing.
> 
> Since sender/receiver coverage values range only from 0...15, their
> type has also been reduced in size from u16 to u4.
> 
> Feature-negotiation options are now generated for both sender and receiver
> coverage, i.e. when the peer has `forgotten' to enable partial coverage
> then feature negotiation will automatically enable (negotiate) the partial
> coverage value for this connection.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Deprecate Ack Ratio sysctl
  2008-11-15 12:11                                                                             ` Gerrit Renker
@ 2008-11-17  6:56                                                                               ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:56 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:18 +0100

> This patch deprecates the Ack Ratio sysctl, since
>  * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
>  * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
>  * even if it would work in CCID-2, there is no point for a user to change it:
>    - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
>    - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
>      (since waiting for Acks which will never arrive in this window),
>    - cwnd is not a user-configurable value.
> 
> The only reasonable place for Ack Ratio is to print it for debugging. It is
> planned to do this later on, as part of e.g. dccp_probe.
> 
> With this patch Ack Ratio is now under full control of feature negotiation:
>  * Ack Ratio is resolved as a dependency of the selected CCID;
>  * if the chosen CCID supports it (i.e. CCID == CCID-2), Ack Ratio is set to
>    the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
>    Ratio 2 for both endpoints";
>  * what happens then is part of another patch set, since it concerns the
>    dynamic update of Ack Ratio while the connection is in full flight.
> 
> Thanks to Tomasz Grobelny for discussion leading up to this patch.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Deprecate Ack Ratio sysctl
@ 2008-11-17  6:56                                                                               ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:56 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:18 +0100

> This patch deprecates the Ack Ratio sysctl, since
>  * Ack Ratio is entirely ignored by CCID-3 and CCID-4,
>  * Ack Ratio currently doesn't work in CCID-2 (i.e. is always set to 1);
>  * even if it would work in CCID-2, there is no point for a user to change it:
>    - Ack Ratio is constrained by cwnd (RFC 4341, 6.1.2),
>    - if Ack Ratio > cwnd, the system resorts to spurious RTO timeouts
>      (since waiting for Acks which will never arrive in this window),
>    - cwnd is not a user-configurable value.
> 
> The only reasonable place for Ack Ratio is to print it for debugging. It is
> planned to do this later on, as part of e.g. dccp_probe.
> 
> With this patch Ack Ratio is now under full control of feature negotiation:
>  * Ack Ratio is resolved as a dependency of the selected CCID;
>  * if the chosen CCID supports it (i.e. CCID = CCID-2), Ack Ratio is set to
>    the default of 2, following RFC 4340, 11.3 - "New connections start with Ack
>    Ratio 2 for both endpoints";
>  * what happens then is part of another patch set, since it concerns the
>    dynamic update of Ack Ratio while the connection is in full flight.
> 
> Thanks to Tomasz Grobelny for discussion leading up to this patch.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 5/5] dccp: Tidy up setsockopt calls
  2008-11-15 12:11                                                                               ` Gerrit Renker
@ 2008-11-17  6:57                                                                                 ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:57 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:19 +0100

> This splits the setsockopt calls into two groups, depending on whether an
> integer argument (val) is required and whether routines being called do
> their own locking.
> 
> Some options (such as setting the CCID) use u8 rather than int, so that for
> these the test with regard to integer-sizeof can not be used.
> 
> The second switch-case statement now only has those statements which need
> locking and which make use of `val'.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 5/5] dccp: Tidy up setsockopt calls
@ 2008-11-17  6:57                                                                                 ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-17  6:57 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 15 Nov 2008 13:11:19 +0100

> This splits the setsockopt calls into two groups, depending on whether an
> integer argument (val) is required and whether routines being called do
> their own locking.
> 
> Some options (such as setting the CCID) use u8 rather than int, so that for
> these the test with regard to integer-sizeof can not be used.
> 
> The second switch-case statement now only has those statements which need
> locking and which make use of `val'.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> Reviewed-by: Eugene Teo <eugeneteo@kernel.sg>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Deprecate old setsockopt framework
  2008-11-15 12:11                                                                         ` Gerrit Renker
@ 2008-11-17 15:31                                                                             ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-17 15:31 UTC (permalink / raw)
  To: David Miller; +Cc: dccp, netdev

| > This patch removes the old setsockopt interface and replaces it with two new
| > functions to register NN/SP values for feature negotiation. 
<snip>
| But you have to understand that this is something you should think
| about never doing again.  User interfaces are never "oops sorry, we
| misdesigned that, we'll just take it away and emit some warning,
| fix your app"  Once it's out there, you gotta support it forever.
| 

I hope that the present solution of replacing is sufficient since there was
at least one crash reported with the old interface, on
http://www.spinics.net/lists/dccp/msg03371.html

Later within the patch set (not in the current submission) there is also a 
setsockopt warning that the old interface is no longer valid (in the patch
"dccp: Deprecate old setsockopt framework" on http://eden-feed.erg.abdn.ac.uk).

With regard to interface changes, it would be best/easier to keep them within
one release. I am not up-to-date how long net-next-2.6 will remain open,
but if you are pushing it out soon, it would be best not to push out the old
and the new interface in parallel.

I am otherwise happy to resubmit the reviewed patches again later, as
already done after the last merge window.

With regard to compilation there are no concerns, patches are all tested to
compile standalone.

Please let me know how you would like to proceed.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Deprecate old setsockopt framework
@ 2008-11-17 15:31                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-17 15:31 UTC (permalink / raw)
  To: dccp

| > This patch removes the old setsockopt interface and replaces it with two new
| > functions to register NN/SP values for feature negotiation. 
<snip>
| But you have to understand that this is something you should think
| about never doing again.  User interfaces are never "oops sorry, we
| misdesigned that, we'll just take it away and emit some warning,
| fix your app"  Once it's out there, you gotta support it forever.
| 

I hope that the present solution of replacing is sufficient since there was
at least one crash reported with the old interface, on
http://www.spinics.net/lists/dccp/msg03371.html

Later within the patch set (not in the current submission) there is also a 
setsockopt warning that the old interface is no longer valid (in the patch
"dccp: Deprecate old setsockopt framework" on http://eden-feed.erg.abdn.ac.uk).

With regard to interface changes, it would be best/easier to keep them within
one release. I am not up-to-date how long net-next-2.6 will remain open,
but if you are pushing it out soon, it would be best not to push out the old
and the new interface in parallel.

I am otherwise happy to resubmit the reviewed patches again later, as
already done after the last merge window.

With regard to compilation there are no concerns, patches are all tested to
compile standalone.

Please let me know how you would like to proceed.

Gerrit

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
  2008-11-15 12:11                                                                       ` Gerrit Renker
@ 2008-11-18  5:03                                                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-18  5:03 UTC (permalink / raw)
  To: David Miller; +Cc: dccp, netdev

[-- Attachment #1: Type: text/plain, Size: 489 bytes --]

| > +	list_for_each_entry(entry, fn_list, node)
| > +		if (entry->feat_num == feat_num && entry->is_local == is_local)
| > +			return entry;
| > +		else if (entry->feat_num > feat_num)
| > +			break;
| 
| Personally, I would have put braces around this basic block.
| 
If it is possible to modify without disturbance, I attach a patch for this and
have changed it in the test tree.

I have checked that making this change does not affect subsequent
patches - it works with either variant.

[-- Attachment #2: Missing braces --]
[-- Type: text/x-diff, Size: 395 bytes --]

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -171,11 +171,12 @@ static struct dccp_feat_entry *dccp_feat
 {
 	struct dccp_feat_entry *entry;
 
-	list_for_each_entry(entry, fn_list, node)
+	list_for_each_entry(entry, fn_list, node) {
 		if (entry->feat_num == feat_num && entry->is_local == is_local)
 			return entry;
 		else if (entry->feat_num > feat_num)
 			break;
+	}
 	return NULL;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
@ 2008-11-18  5:03                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-18  5:03 UTC (permalink / raw)
  To: dccp

[-- Attachment #1: Type: text/plain, Size: 489 bytes --]

| > +	list_for_each_entry(entry, fn_list, node)
| > +		if (entry->feat_num == feat_num && entry->is_local == is_local)
| > +			return entry;
| > +		else if (entry->feat_num > feat_num)
| > +			break;
| 
| Personally, I would have put braces around this basic block.
| 
If it is possible to modify without disturbance, I attach a patch for this and
have changed it in the test tree.

I have checked that making this change does not affect subsequent
patches - it works with either variant.

[-- Attachment #2: Missing braces --]
[-- Type: text/x-diff, Size: 395 bytes --]

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -171,11 +171,12 @@ static struct dccp_feat_entry *dccp_feat
 {
 	struct dccp_feat_entry *entry;
 
-	list_for_each_entry(entry, fn_list, node)
+	list_for_each_entry(entry, fn_list, node) {
 		if (entry->feat_num == feat_num && entry->is_local == is_local)
 			return entry;
 		else if (entry->feat_num > feat_num)
 			break;
+	}
 	return NULL;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
  2008-11-15 12:11                                                                       ` Gerrit Renker
@ 2008-11-20  9:03                                                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-20  9:03 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 18 Nov 2008 06:03:47 +0100

> | > +	list_for_each_entry(entry, fn_list, node)
> | > +		if (entry->feat_num == feat_num && entry->is_local == is_local)
> | > +			return entry;
> | > +		else if (entry->feat_num > feat_num)
> | > +			break;
> | 
> | Personally, I would have put braces around this basic block.
> | 
> If it is possible to modify without disturbance, I attach a patch for this and
> have changed it in the test tree.
> 
> I have checked that making this change does not affect subsequent
> patches - it works with either variant.

Applied, thanks Gerrit.  Please give a signoff next time.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies
@ 2008-11-20  9:03                                                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-20  9:03 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 18 Nov 2008 06:03:47 +0100

> | > +	list_for_each_entry(entry, fn_list, node)
> | > +		if (entry->feat_num = feat_num && entry->is_local = is_local)
> | > +			return entry;
> | > +		else if (entry->feat_num > feat_num)
> | > +			break;
> | 
> | Personally, I would have put braces around this basic block.
> | 
> If it is possible to modify without disturbance, I attach a patch for this and
> have changed it in the test tree.
> 
> I have checked that making this change does not affect subsequent
> patches - it works with either variant.

Applied, thanks Gerrit.  Please give a signoff next time.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/5] dccp: Feature negotiation - continuation of Part II (core)
  2008-11-15 12:11                                                                     ` Gerrit Renker
@ 2008-11-22 10:30                                                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp; +Cc: netdev

Hi Dave,

please find in this set the continuation. The patches have been tested to
compile standalone, with sparse checking enabled.

Gerrit


Commit summary:
---------------
This is a continuation of an ongoing submission to provide feature/capability
negotiation for DCCP endpoints (RFC 4340).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

This set continues within the second part (core implementation). I have split
it in such a way that up until here the old code and the new API can co-exist.

In the next (and last) patch set within this block, the old code is step-by-step
superseded by the new API.

The full integration of the new API and clean-up of the old code then happens
in the concluding part (3).


List of patches in this set:
----------------------------
Patch #1: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #2: Socket API to query the current CCID from userspace.
Patch #3: Prepares the variable-length htonl/ntohl functions for 48 bits.
          Such a length is needed by e.g. the Sequence Window feature.
Patch #4: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #5: Routine to insert feature-negotiation header options.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=76ae436e9949fd75a4faaa81f5ce915309b83a1f


Patch stats:
------------
 Documentation/networking/dccp.txt |   14 ++++
 include/linux/dccp.h              |    5 +
 net/dccp/ackvec.c                 |    9 +-
 net/dccp/ackvec.h                 |    5 -
 net/dccp/ccid.h                   |   18 +++++
 net/dccp/feat.h                   |   20 +++++
 net/dccp/options.c                |  127 +++++++++++++++++---------------------
 net/dccp/probe.c                  |    7 --
 net/dccp/proto.c                  |   44 +++++++++++++
 9 files changed, 169 insertions(+), 80 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/5] dccp: Feature negotiation - continuation of Part II (core)
@ 2008-11-22 10:30                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find in this set the continuation. The patches have been tested to
compile standalone, with sparse checking enabled.

Gerrit


Commit summary:
---------------
This is a continuation of an ongoing submission to provide feature/capability
negotiation for DCCP endpoints (RFC 4340).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

This set continues within the second part (core implementation). I have split
it in such a way that up until here the old code and the new API can co-exist.

In the next (and last) patch set within this block, the old code is step-by-step
superseded by the new API.

The full integration of the new API and clean-up of the old code then happens
in the concluding part (3).


List of patches in this set:
----------------------------
Patch #1: Set/getsockopt support to negotiate CCIDs with the peer.
Patch #2: Socket API to query the current CCID from userspace.
Patch #3: Prepares the variable-length htonl/ntohl functions for 48 bits.
          Such a length is needed by e.g. the Sequence Window feature.
Patch #4: Support for DCCP `Mandatory' type options (RFC 4340, 5.8.2).
Patch #5: Routine to insert feature-negotiation header options.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;hvae436e9949fd75a4faaa81f5ce915309b83a1f


Patch stats:
------------
 Documentation/networking/dccp.txt |   14 ++++
 include/linux/dccp.h              |    5 +
 net/dccp/ackvec.c                 |    9 +-
 net/dccp/ackvec.h                 |    5 -
 net/dccp/ccid.h                   |   18 +++++
 net/dccp/feat.h                   |   20 +++++
 net/dccp/options.c                |  127 +++++++++++++++++---------------------
 net/dccp/probe.c                  |    7 --
 net/dccp/proto.c                  |   44 +++++++++++++
 9 files changed, 169 insertions(+), 80 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Set per-connection CCIDs via socket options
@ 2008-11-22 10:30                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
overrides the defaults set by the global sysctl variables for TX/RX CCIDs.

To make full use of this facility, the remaining patches of this patch set are
needed, which track dependencies and activate negotiated feature values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 Documentation/networking/dccp.txt |   14 ++++++++++++++
 include/linux/dccp.h              |    5 +++++
 net/dccp/ackvec.c                 |    9 ++++-----
 net/dccp/ackvec.h                 |    5 ++---
 net/dccp/feat.h                   |    2 ++
 net/dccp/proto.c                  |   34 ++++++++++++++++++++++++++++++++++
 6 files changed, 61 insertions(+), 8 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
 supported by the endpoint (see include/linux/dccp.h for symbolic constants).
 The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
 
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -168,6 +168,8 @@ enum {
 	DCCPO_MIN_CCID_SPECIFIC = 128,
 	DCCPO_MAX_CCID_SPECIFIC = 255,
 };
+/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 
 /* DCCP CCIDS */
 enum {
@@ -203,6 +205,9 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -22,6 +22,8 @@
 /* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
 #define DCCPF_SEQ_WMIN		32
 #define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+/* Maximum number of SP values that fit in a single (Confirm) option */
+#define DCCP_FEAT_MAX_SP_VALS	(DCCP_SINGLE_OPT_MAXLEN - 2)
 
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,15 +11,14 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -12,7 +12,6 @@
 #include "ackvec.h"
 #include "dccp.h"
 
-#include <linux/dccp.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -68,7 +67,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +99,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +431,7 @@ found:
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -506,6 +506,36 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 	return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
+		return -EINVAL;
+
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
+	}
+
+	lock_sock(sk);
+	if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+	if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
+
+	kfree(val);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -520,6 +550,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
 		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
 	}
 
 	if (optlen < (int)sizeof(int))

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Set per-connection CCIDs via socket options
@ 2008-11-22 10:30                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp

With this patch, TX/RX CCIDs can now be changed on a per-connection basis, which
overrides the defaults set by the global sysctl variables for TX/RX CCIDs.

To make full use of this facility, the remaining patches of this patch set are
needed, which track dependencies and activate negotiated feature values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 Documentation/networking/dccp.txt |   14 ++++++++++++++
 include/linux/dccp.h              |    5 +++++
 net/dccp/ackvec.c                 |    9 ++++-----
 net/dccp/ackvec.h                 |    5 ++---
 net/dccp/feat.h                   |    2 ++
 net/dccp/proto.c                  |   34 ++++++++++++++++++++++++++++++++++
 6 files changed, 61 insertions(+), 8 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -61,6 +61,20 @@ DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs
 supported by the endpoint (see include/linux/dccp.h for symbolic constants).
 The caller needs to provide a sufficiently large (> 2) array of type uint8_t.
 
+DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same
+time, combining the operation of the next two socket options. This option is
+preferrable over the latter two, since often applications will use the same
+type of CCID for both directions; and mixed use of CCIDs is not currently well
+understood. This socket option takes as argument at least one uint8_t value, or
+an array of uint8_t values, which must match available CCIDS (see above). CCIDs
+must be registered on the socket before calling connect() or listen().
+
+DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets
+the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID.
+Please note that the getsockopt argument type here is `int', not uint8_t.
+
+DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID.
+
 DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold
 timewait state when closing the connection (RFC 4340, 8.3). The usual case is
 that the closing server sends a CloseReq, whereupon the client holds timewait
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -168,6 +168,8 @@ enum {
 	DCCPO_MIN_CCID_SPECIFIC = 128,
 	DCCPO_MAX_CCID_SPECIFIC = 255,
 };
+/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
+#define DCCP_SINGLE_OPT_MAXLEN	253
 
 /* DCCP CCIDS */
 enum {
@@ -203,6 +205,9 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_SEND_CSCOV		10
 #define DCCP_SOCKOPT_RECV_CSCOV		11
 #define DCCP_SOCKOPT_AVAILABLE_CCIDS	12
+#define DCCP_SOCKOPT_CCID		13
+#define DCCP_SOCKOPT_TX_CCID		14
+#define DCCP_SOCKOPT_RX_CCID		15
 #define DCCP_SOCKOPT_CCID_RX_INFO	128
 #define DCCP_SOCKOPT_CCID_TX_INFO	192
 
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -22,6 +22,8 @@
 /* Wmin2 and Wmax=2^46-1 from 7.5.2 */
 #define DCCPF_SEQ_WMIN		32
 #define DCCPF_SEQ_WMAX		0x3FFFFFFFFFFFull
+/* Maximum number of SP values that fit in a single (Confirm) option */
+#define DCCP_FEAT_MAX_SP_VALS	(DCCP_SINGLE_OPT_MAXLEN - 2)
 
 enum dccp_feat_type {
 	FEAT_AT_RX   = 1,	/* located at RX side of half-connection  */
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -11,15 +11,14 @@
  *	published by the Free Software Foundation.
  */
 
+#include <linux/dccp.h>
 #include <linux/compiler.h>
 #include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/types.h>
 
-/* Read about the ECN nonce to see why it is 253 */
-#define DCCP_MAX_ACKVEC_OPT_LEN 253
 /* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2)
+#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
 #define DCCP_ACKVEC_STATE_RECEIVED	0
 #define DCCP_ACKVEC_STATE_ECN_MARKED	(1 << 6)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -12,7 +12,6 @@
 #include "ackvec.h"
 #include "dccp.h"
 
-#include <linux/dccp.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -68,7 +67,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
 	/* Figure out how many options do we need to represent the ackvec */
-	const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN);
+	const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
 	u16 len = av->av_vec_len + 2 * nr_opts, i;
 	u32 elapsed_time;
 	const unsigned char *tail, *from;
@@ -100,8 +99,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
 	for (i = 0; i < nr_opts; ++i) {
 		int copylen = len;
 
-		if (len > DCCP_MAX_ACKVEC_OPT_LEN)
-			copylen = DCCP_MAX_ACKVEC_OPT_LEN;
+		if (len > DCCP_SINGLE_OPT_MAXLEN)
+			copylen = DCCP_SINGLE_OPT_MAXLEN;
 
 		*to++ = DCCPO_ACK_VECTOR_0;
 		*to++ = copylen + 2;
@@ -432,7 +431,7 @@ found:
 int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
 		      u64 *ackno, const u8 opt, const u8 *value, const u8 len)
 {
-	if (len > DCCP_MAX_ACKVEC_OPT_LEN)
+	if (len > DCCP_SINGLE_OPT_MAXLEN)
 		return -1;
 
 	/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -506,6 +506,36 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx)
 	return rc;
 }
 
+static int dccp_setsockopt_ccid(struct sock *sk, int type,
+				char __user *optval, int optlen)
+{
+	u8 *val;
+	int rc = 0;
+
+	if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
+		return -EINVAL;
+
+	val = kmalloc(optlen, GFP_KERNEL);
+	if (val = NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(val, optval, optlen)) {
+		kfree(val);
+		return -EFAULT;
+	}
+
+	lock_sock(sk);
+	if (type = DCCP_SOCKOPT_TX_CCID || type = DCCP_SOCKOPT_CCID)
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen);
+
+	if (!rc && (type = DCCP_SOCKOPT_RX_CCID || type = DCCP_SOCKOPT_CCID))
+		rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen);
+	release_sock(sk);
+
+	kfree(val);
+	return rc;
+}
+
 static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 		char __user *optval, int optlen)
 {
@@ -520,6 +550,10 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
 	case DCCP_SOCKOPT_CHANGE_R:
 		DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n");
 		return 0;
+	case DCCP_SOCKOPT_CCID:
+	case DCCP_SOCKOPT_RX_CCID:
+	case DCCP_SOCKOPT_TX_CCID:
+		return dccp_setsockopt_ccid(sk, optname, optval, optlen);
 	}
 
 	if (optlen < (int)sizeof(int))

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: API to query the current TX/RX CCID
@ 2008-11-22 10:30                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This provides function to query the current TX/RX CCID dynamically, without
reliance on the minisock value, using dynamic information available in the
currently loaded CCID module.

This query function is then used to
 (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
 (b) replace the current test for "which CCID is in use" in probe.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h  |   18 ++++++++++++++++++
 net/dccp/probe.c |    7 ++-----
 net/dccp/proto.c |   10 ++++++++++
 3 files changed, 30 insertions(+), 5 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -116,6 +116,24 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
 extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
 				   gfp_t gfp);
 
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
+
+	if (ccid == NULL || ccid->ccid_ops == NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
 
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
+	if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port == 0 || ntohs(inet->dport) == port ||
 	    ntohs(inet->sport) == port) {
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -667,6 +667,16 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 		break;
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_rx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: API to query the current TX/RX CCID
@ 2008-11-22 10:30                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp

This provides function to query the current TX/RX CCID dynamically, without
reliance on the minisock value, using dynamic information available in the
currently loaded CCID module.

This query function is then used to
 (a) provide the getsockopt part for getting/setting CCIDs via sockopts;
 (b) replace the current test for "which CCID is in use" in probe.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h  |   18 ++++++++++++++++++
 net/dccp/probe.c |    7 ++-----
 net/dccp/proto.c |   10 ++++++++++
 3 files changed, 30 insertions(+), 5 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -116,6 +116,24 @@ extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
 extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
 				   gfp_t gfp);
 
+static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_rx_ccid;
+
+	if (ccid = NULL || ccid->ccid_ops = NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
+static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp)
+{
+	struct ccid *ccid = dp->dccps_hc_tx_ccid;
+
+	if (ccid = NULL || ccid->ccid_ops = NULL)
+		return -1;
+	return ccid->ccid_ops->ccid_id;
+}
+
 extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
 extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
 
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -74,14 +74,11 @@ static void printl(const char *fmt, ...)
 static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			 struct msghdr *msg, size_t size)
 {
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 	const struct inet_sock *inet = inet_sk(sk);
-	const struct ccid3_hc_tx_sock *hctx;
+	struct ccid3_hc_tx_sock *hctx = NULL;
 
-	if (dmsk->dccpms_tx_ccid = DCCPC_CCID3)
+	if (ccid_get_current_tx_ccid(dccp_sk(sk)) = DCCPC_CCID3)
 		hctx = ccid3_hc_tx_sk(sk);
-	else
-		hctx = NULL;
 
 	if (port = 0 || ntohs(inet->dport) = port ||
 	    ntohs(inet->sport) = port) {
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -667,6 +667,16 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
 		break;
 	case DCCP_SOCKOPT_AVAILABLE_CCIDS:
 		return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
+	case DCCP_SOCKOPT_TX_CCID:
+		val = ccid_get_current_tx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
+	case DCCP_SOCKOPT_RX_CCID:
+		val = ccid_get_current_rx_ccid(dp);
+		if (val < 0)
+			return -ENOPROTOOPT;
+		break;
 	case DCCP_SOCKOPT_SERVER_TIMEWAIT:
 		val = dp->dccps_server_timewait;
 		break;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: Increase the scope of variable-length htonl/ntohl functions
@ 2008-11-22 10:30                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

This extends the scope of two available functions, encode|decode_value_var,
to work up to 6 (8) bytes, to match maximum requirements in the RFC.

These functions are going to be used both by general option processing and
feature negotiation code, hence declarations have been put into feat.h.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h    |   14 ++++++++++++++
 net/dccp/options.c |   21 ++++++++++++++-------
 2 files changed, 28 insertions(+), 7 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -124,4 +124,18 @@ extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
+/*
+ * Encoding variable-length options and their maximum length.
+ *
+ * This affects NN options (SP options are all u8) and other variable-length
+ * options (see table 3 in RFC 4340). The limit is currently given the Sequence
+ * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
+ * options consume less than 6 bytes (timestamps are 4 bytes).
+ * When updating this constant (e.g. due to new internet drafts / RFCs), make
+ * sure that you also update all code which refers to it.
+ */
+#define DCCP_OPTVAL_MAXLEN	6
+
+extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
+extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -29,16 +29,20 @@ int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
+u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
-	u32 value = 0;
+	u64 value = 0;
 
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		value += ((u64)*bf++) << 40;
+	if (len > 4)
+		value += ((u64)*bf++) << 32;
 	if (len > 3)
-		value += *bf++ << 24;
+		value += ((u64)*bf++) << 24;
 	if (len > 2)
-		value += *bf++ << 16;
+		value += ((u64)*bf++) << 16;
 	if (len > 1)
-		value += *bf++ << 8;
+		value += ((u64)*bf++) << 8;
 	if (len > 0)
 		value += *bf;
 
@@ -298,9 +302,12 @@ out_invalid_option:
 
 EXPORT_SYMBOL_GPL(dccp_parse_options);
 
-static void dccp_encode_value_var(const u32 value, unsigned char *to,
-				  const unsigned int len)
+void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
 {
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		*to++ = (value & 0xFF0000000000ull) >> 40;
+	if (len > 4)
+		*to++ = (value & 0xFF00000000ull) >> 32;
 	if (len > 3)
 		*to++ = (value & 0xFF000000) >> 24;
 	if (len > 2)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: Increase the scope of variable-length htonl/ntohl functions
@ 2008-11-22 10:30                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp

This extends the scope of two available functions, encode|decode_value_var,
to work up to 6 (8) bytes, to match maximum requirements in the RFC.

These functions are going to be used both by general option processing and
feature negotiation code, hence declarations have been put into feat.h.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h    |   14 ++++++++++++++
 net/dccp/options.c |   21 ++++++++++++++-------
 2 files changed, 28 insertions(+), 7 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -124,4 +124,18 @@ extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
+/*
+ * Encoding variable-length options and their maximum length.
+ *
+ * This affects NN options (SP options are all u8) and other variable-length
+ * options (see table 3 in RFC 4340). The limit is currently given the Sequence
+ * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other
+ * options consume less than 6 bytes (timestamps are 4 bytes).
+ * When updating this constant (e.g. due to new internet drafts / RFCs), make
+ * sure that you also update all code which refers to it.
+ */
+#define DCCP_OPTVAL_MAXLEN	6
+
+extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
+extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -29,16 +29,20 @@ int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
-static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len)
+u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
-	u32 value = 0;
+	u64 value = 0;
 
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		value += ((u64)*bf++) << 40;
+	if (len > 4)
+		value += ((u64)*bf++) << 32;
 	if (len > 3)
-		value += *bf++ << 24;
+		value += ((u64)*bf++) << 24;
 	if (len > 2)
-		value += *bf++ << 16;
+		value += ((u64)*bf++) << 16;
 	if (len > 1)
-		value += *bf++ << 8;
+		value += ((u64)*bf++) << 8;
 	if (len > 0)
 		value += *bf;
 
@@ -298,9 +302,12 @@ out_invalid_option:
 
 EXPORT_SYMBOL_GPL(dccp_parse_options);
 
-static void dccp_encode_value_var(const u32 value, unsigned char *to,
-				  const unsigned int len)
+void dccp_encode_value_var(const u64 value, u8 *to, const u8 len)
 {
+	if (len >= DCCP_OPTVAL_MAXLEN)
+		*to++ = (value & 0xFF0000000000ull) >> 40;
+	if (len > 4)
+		*to++ = (value & 0xFF00000000ull) >> 32;
 	if (len > 3)
 		*to++ = (value & 0xFF000000) >> 24;
 	if (len > 2)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Support for Mandatory options
@ 2008-11-22 10:30                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

Support for Mandatory options is provided by this patch, which will
be used by subsequent feature-negotiation patches.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h    |    2 ++
 net/dccp/options.c |   15 +++++++++++++++
 2 files changed, 17 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -138,4 +138,6 @@ extern int  dccp_feat_init(struct sock *sk);
 
 extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
+
+extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -467,6 +467,21 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
 	return 0;
 }
 
+/**
+ * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
+ * Note that since we are using skb_push, this function needs to be called
+ * _after_ inserting the option it is supposed to influence (stack order).
+ */
+int dccp_insert_option_mandatory(struct sk_buff *skb)
+{
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
+		return -1;
+
+	DCCP_SKB_CB(skb)->dccpd_opt_len++;
+	*skb_push(skb, 1) = DCCPO_MANDATORY;
+	return 0;
+}
+
 static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 				u8 *val, u8 len)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Support for Mandatory options
@ 2008-11-22 10:30                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp

Support for Mandatory options is provided by this patch, which will
be used by subsequent feature-negotiation patches.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 net/dccp/feat.h    |    2 ++
 net/dccp/options.c |   15 +++++++++++++++
 2 files changed, 17 insertions(+), 0 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -138,4 +138,6 @@ extern int  dccp_feat_init(struct sock *sk);
 
 extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
+
+extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -467,6 +467,21 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
 	return 0;
 }
 
+/**
+ * dccp_insert_option_mandatory  -  Mandatory option (5.8.2)
+ * Note that since we are using skb_push, this function needs to be called
+ * _after_ inserting the option it is supposed to influence (stack order).
+ */
+int dccp_insert_option_mandatory(struct sk_buff *skb)
+{
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN)
+		return -1;
+
+	DCCP_SKB_CB(skb)->dccpd_opt_len++;
+	*skb_push(skb, 1) = DCCPO_MANDATORY;
+	return 0;
+}
+
 static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 				u8 *val, u8 len)
 {

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Header option insertion routine for feature-negotiation
@ 2008-11-22 10:30                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp; +Cc: netdev, Gerrit Renker

The patch extends existing code:
 * Confirm options divide into the confirmed value plus an optional preference
   list for SP values. Previously only the preference list was echoed for SP
   values, now the confirmed value is added as per RFC 4340, 6.1;
 * length and sanity checks are added to avoid illegal memory (or NULL) access.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |    2 +
 net/dccp/options.c |   91 ++++++++++++++++++----------------------------------
 2 files changed, 33 insertions(+), 60 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -140,4 +140,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 
 extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
+extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+			       u8 *val, u8 len, bool repeat_first);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb)
 	return 0;
 }
 
-static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
-				u8 *val, u8 len)
+/**
+ * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
+ * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
+ * @feat: one out of %dccp_feature_numbers
+ * @val: NN value or SP array (preferred element first) to copy
+ * @len: true length of @val in bytes (excluding first element repetition)
+ * @repeat_first: whether to copy the first element of @val twice
+ * The last argument is used to construct Confirm options, where the preferred
+ * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
+ * lists are kept such that the preferred entry is always first, so we only need
+ * to copy twice, and avoid the overhead of cloning into a bigger array.
+ */
+int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+		       u8 *val, u8 len, bool repeat_first)
 {
-	u8 *to;
+	u8 tot_len, *to;
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
-		DCCP_WARN("packet too small for feature %d option!\n", feat);
+	/* take the `Feature' field and possible repetition into account */
+	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
+		DCCP_WARN("length %u for feature %u too large\n", len, feat);
 		return -1;
 	}
 
-	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+	if (unlikely(val == NULL || len == 0))
+		len = repeat_first = 0;
+	tot_len = 3 + repeat_first + len;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
+		DCCP_WARN("packet too small for feature %d option!\n", feat);
+		return -1;
+	}
+	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
 
-	to    = skb_push(skb, len + 3);
+	to    = skb_push(skb, tot_len);
 	*to++ = type;
-	*to++ = len + 3;
+	*to++ = tot_len;
 	*to++ = feat;
 
+	if (repeat_first)
+		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
 
@@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 	return 0;
 }
 
-static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt, *next;
-	int change = 0;
-
-	/* confirm any options [NN opts] */
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		dccp_insert_feat_opt(skb, opt->dccpop_type,
-				     opt->dccpop_feat, opt->dccpop_val,
-				     opt->dccpop_len);
-		/* fear empty confirms */
-		if (opt->dccpop_val)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-
-	/* see which features we need to send */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* see if we need to send any confirm */
-		if (opt->dccpop_sc) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
-					     opt->dccpop_feat,
-					     opt->dccpop_sc->dccpoc_val,
-					     opt->dccpop_sc->dccpoc_len);
-
-			BUG_ON(!opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-			opt->dccpop_sc = NULL;
-		}
-
-		/* any option not confirmed, re-send it */
-		if (!opt->dccpop_conf) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type,
-					     opt->dccpop_feat, opt->dccpop_val,
-					     opt->dccpop_len);
-			change++;
-		}
-	}
-
-	return 0;
-}
-
 /* The length of all options needs to be a multiple of 4 (5.8) */
 static void dccp_insert_option_padding(struct sk_buff *skb)
 {
@@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/* Feature negotiation */
-	/* Data packets can't do feat negotiation */
-	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
-	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
-	    dccp_insert_options_feat(sk, skb))
-		return -1;
-
 	/*
 	 * Obtain RTT sample from Request/Response exchange.
 	 * This is currently used in CCID 3 initialisation.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Header option insertion routine for feature-negotiation
@ 2008-11-22 10:30                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-22 10:30 UTC (permalink / raw)
  To: dccp

The patch extends existing code:
 * Confirm options divide into the confirmed value plus an optional preference
   list for SP values. Previously only the preference list was echoed for SP
   values, now the confirmed value is added as per RFC 4340, 6.1;
 * length and sanity checks are added to avoid illegal memory (or NULL) access.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |    2 +
 net/dccp/options.c |   91 ++++++++++++++++++----------------------------------
 2 files changed, 33 insertions(+), 60 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -140,4 +140,6 @@ extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len);
 extern u64  dccp_decode_value_var(const u8 *bf, const u8 len);
 
 extern int  dccp_insert_option_mandatory(struct sk_buff *skb);
+extern int  dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+			       u8 *val, u8 len, bool repeat_first);
 #endif /* _DCCP_FEAT_H */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -482,23 +482,46 @@ int dccp_insert_option_mandatory(struct sk_buff *skb)
 	return 0;
 }
 
-static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
-				u8 *val, u8 len)
+/**
+ * dccp_insert_fn_opt  -  Insert single Feature-Negotiation option into @skb
+ * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R
+ * @feat: one out of %dccp_feature_numbers
+ * @val: NN value or SP array (preferred element first) to copy
+ * @len: true length of @val in bytes (excluding first element repetition)
+ * @repeat_first: whether to copy the first element of @val twice
+ * The last argument is used to construct Confirm options, where the preferred
+ * value and the preference list appear separately (RFC 4340, 6.3.1). Preference
+ * lists are kept such that the preferred entry is always first, so we only need
+ * to copy twice, and avoid the overhead of cloning into a bigger array.
+ */
+int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
+		       u8 *val, u8 len, bool repeat_first)
 {
-	u8 *to;
+	u8 tot_len, *to;
 
-	if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) {
-		DCCP_WARN("packet too small for feature %d option!\n", feat);
+	/* take the `Feature' field and possible repetition into account */
+	if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) {
+		DCCP_WARN("length %u for feature %u too large\n", len, feat);
 		return -1;
 	}
 
-	DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3;
+	if (unlikely(val = NULL || len = 0))
+		len = repeat_first = 0;
+	tot_len = 3 + repeat_first + len;
+
+	if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) {
+		DCCP_WARN("packet too small for feature %d option!\n", feat);
+		return -1;
+	}
+	DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len;
 
-	to    = skb_push(skb, len + 3);
+	to    = skb_push(skb, tot_len);
 	*to++ = type;
-	*to++ = len + 3;
+	*to++ = tot_len;
 	*to++ = feat;
 
+	if (repeat_first)
+		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
 
@@ -508,51 +531,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
 	return 0;
 }
 
-static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt, *next;
-	int change = 0;
-
-	/* confirm any options [NN opts] */
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		dccp_insert_feat_opt(skb, opt->dccpop_type,
-				     opt->dccpop_feat, opt->dccpop_val,
-				     opt->dccpop_len);
-		/* fear empty confirms */
-		if (opt->dccpop_val)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-
-	/* see which features we need to send */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		/* see if we need to send any confirm */
-		if (opt->dccpop_sc) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type + 1,
-					     opt->dccpop_feat,
-					     opt->dccpop_sc->dccpoc_val,
-					     opt->dccpop_sc->dccpoc_len);
-
-			BUG_ON(!opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-			opt->dccpop_sc = NULL;
-		}
-
-		/* any option not confirmed, re-send it */
-		if (!opt->dccpop_conf) {
-			dccp_insert_feat_opt(skb, opt->dccpop_type,
-					     opt->dccpop_feat, opt->dccpop_val,
-					     opt->dccpop_len);
-			change++;
-		}
-	}
-
-	return 0;
-}
-
 /* The length of all options needs to be a multiple of 4 (5.8) */
 static void dccp_insert_option_padding(struct sk_buff *skb)
 {
@@ -589,13 +567,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/* Feature negotiation */
-	/* Data packets can't do feat negotiation */
-	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
-	    DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
-	    dccp_insert_options_feat(sk, skb))
-		return -1;
-
 	/*
 	 * Obtain RTT sample from Request/Response exchange.
 	 * This is currently used in CCID 3 initialisation.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Support for Mandatory options
  2008-11-22 10:30                                                                               ` Gerrit Renker
@ 2008-11-24  0:09                                                                                 ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-24  0:09 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 22 Nov 2008 11:30:40 +0100

> Support for Mandatory options is provided by this patch, which will
> be used by subsequent feature-negotiation patches.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Support for Mandatory options
@ 2008-11-24  0:09                                                                                 ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-11-24  0:09 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat, 22 Nov 2008 11:30:40 +0100

> Support for Mandatory options is provided by this patch, which will
> be used by subsequent feature-negotiation patches.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II (core)
@ 2008-11-30 13:22                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

please find attached the completion of the feature-negotiation
implementation, the concluding part of the second block.

The final/third block is then clerical, integrating the code 
presented in the second block; and tidying up the remaining bits.

Gerrit


Commit summary:
---------------
This is a continuation of an ongoing submission to provide feature/capability
negotiation for DCCP endpoints (RFC 4340 - 4342, 5348).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

This set completes the implementation (part (2)). Online information is also at
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/


List of patches in this set:
----------------------------
Patch #1: Continues where the previous patch set left off, by adding
          the insertion of feature-negotiation options onto the skb.
Patch #2: Completes the insertion of featneg options.
Patch #3: Logic/algorithm to actually reconcile negotiation options.
Patch #4: Receiver support to process incoming Change L/R options. 
Patch #5: Receiver support to process incoming Confirm R/L options.
Patch #6: Handlers for activating successfully negotiated features.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=94163f6514044c53c3761305db3c59d640c03ec1


Patch stats:
------------
 dccp.h    |    3 
 feat.c    |  635 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 feat.h    |    6 
 options.c |   72 +++----
 4 files changed, 657 insertions(+), 59 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II (core)
@ 2008-11-30 13:22                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find attached the completion of the feature-negotiation
implementation, the concluding part of the second block.

The final/third block is then clerical, integrating the code 
presented in the second block; and tidying up the remaining bits.

Gerrit


Commit summary:
---------------
This is a continuation of an ongoing submission to provide feature/capability
negotiation for DCCP endpoints (RFC 4340 - 4342, 5348).

The whole set is structured into 3 main blocks - (1) basis, (2) core,
(3) integration and cleanup.

This set completes the implementation (part (2)). Online information is also at
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/feature_negotiation/


List of patches in this set:
----------------------------
Patch #1: Continues where the previous patch set left off, by adding
          the insertion of feature-negotiation options onto the skb.
Patch #2: Completes the insertion of featneg options.
Patch #3: Logic/algorithm to actually reconcile negotiation options.
Patch #4: Receiver support to process incoming Change L/R options. 
Patch #5: Receiver support to process incoming Confirm R/L options.
Patch #6: Handlers for activating successfully negotiated features.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;hî163f6514044c53c3761305db3c59d640c03ec1


Patch stats:
------------
 dccp.h    |    3 
 feat.c    |  635 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 feat.h    |    6 
 options.c |   72 +++----
 4 files changed, 657 insertions(+), 59 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/6] dccp: Insert feature-negotiation options into skb
@ 2008-11-30 13:22                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch replaces the earlier insertion routine from options.c, so that
code specific to feature negotiation can remain in feat.c. This is possible
by calling a function already existing in options.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 
 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*,
+				  struct sk_buff *skb);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -272,6 +272,20 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+/**
+ * dccp_feat_valid_nn_length  -  Enforce length constraints on NN options
+ * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only,
+ * incoming options are accepted as long as their values are valid.
+ */
+static u8 dccp_feat_valid_nn_length(u8 feat_num)
+{
+	if (feat_num == DCCPF_ACK_RATIO)	/* RFC 4340, 11.3 and 6.6.8 */
+		return 2;
+	if (feat_num == DCCPF_SEQUENCE_WINDOW)	/* RFC 4340, 7.5.2 and 6.5  */
+		return 6;
+	return 0;
+}
+
 static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
 {
 	switch (feat_num) {
@@ -314,6 +328,57 @@ static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
 }
 
 /**
+ * dccp_feat_insert_opts  -  Generate FN options from current list state
+ * @skb: next sk_buff to be sent to the peer
+ * @dp: for client during handshake and general negotiation
+ * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND)
+ */
+int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
+			  struct sk_buff *skb)
+{
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	struct dccp_feat_entry *pos, *next;
+	u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN];
+	bool rpt;
+
+	/* put entries into @skb in the order they appear in the list */
+	list_for_each_entry_safe_reverse(pos, next, fn, node) {
+		opt  = dccp_feat_genopt(pos);
+		type = dccp_feat_type(pos->feat_num);
+		rpt  = false;
+
+		if (pos->empty_confirm) {
+			len = 0;
+			ptr = NULL;
+		} else {
+			if (type == FEAT_SP) {
+				len = pos->val.sp.len;
+				ptr = pos->val.sp.vec;
+				rpt = pos->needs_confirm;
+			} else if (type == FEAT_NN) {
+				len = dccp_feat_valid_nn_length(pos->feat_num);
+				ptr = nn_in_nbo;
+				dccp_encode_value_var(pos->val.nn, ptr, len);
+			} else {
+				DCCP_BUG("unknown feature %u", pos->feat_num);
+				return -1;
+			}
+		}
+
+		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
+			return -1;
+		if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
+			return -1;
+		/*
+		 * Enter CHANGING after transmitting the Change option (6.6.2).
+		 */
+		if (pos->state == FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+	}
+	return 0;
+}
+
+/**
  * __feat_register_nn  -  Register new NN value on socket
  * @fn: feature-negotiation list to register with
  * @feat: an NN feature from %dccp_feature_numbers

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/6] dccp: Insert feature-negotiation options into skb
@ 2008-11-30 13:22                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

This patch replaces the earlier insertion routine from options.c, so that
code specific to feature negotiation can remain in feat.c. This is possible
by calling a function already existing in options.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    2 +
 net/dccp/feat.c |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 0 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -443,6 +443,8 @@ static inline int dccp_ack_pending(const struct sock *sk)
 
 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*,
+				  struct sk_buff *skb);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -272,6 +272,20 @@ cloning_failed:
 	return -ENOMEM;
 }
 
+/**
+ * dccp_feat_valid_nn_length  -  Enforce length constraints on NN options
+ * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only,
+ * incoming options are accepted as long as their values are valid.
+ */
+static u8 dccp_feat_valid_nn_length(u8 feat_num)
+{
+	if (feat_num = DCCPF_ACK_RATIO)	/* RFC 4340, 11.3 and 6.6.8 */
+		return 2;
+	if (feat_num = DCCPF_SEQUENCE_WINDOW)	/* RFC 4340, 7.5.2 and 6.5  */
+		return 6;
+	return 0;
+}
+
 static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
 {
 	switch (feat_num) {
@@ -314,6 +328,57 @@ static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
 }
 
 /**
+ * dccp_feat_insert_opts  -  Generate FN options from current list state
+ * @skb: next sk_buff to be sent to the peer
+ * @dp: for client during handshake and general negotiation
+ * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND)
+ */
+int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
+			  struct sk_buff *skb)
+{
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	struct dccp_feat_entry *pos, *next;
+	u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN];
+	bool rpt;
+
+	/* put entries into @skb in the order they appear in the list */
+	list_for_each_entry_safe_reverse(pos, next, fn, node) {
+		opt  = dccp_feat_genopt(pos);
+		type = dccp_feat_type(pos->feat_num);
+		rpt  = false;
+
+		if (pos->empty_confirm) {
+			len = 0;
+			ptr = NULL;
+		} else {
+			if (type = FEAT_SP) {
+				len = pos->val.sp.len;
+				ptr = pos->val.sp.vec;
+				rpt = pos->needs_confirm;
+			} else if (type = FEAT_NN) {
+				len = dccp_feat_valid_nn_length(pos->feat_num);
+				ptr = nn_in_nbo;
+				dccp_encode_value_var(pos->val.nn, ptr, len);
+			} else {
+				DCCP_BUG("unknown feature %u", pos->feat_num);
+				return -1;
+			}
+		}
+
+		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
+			return -1;
+		if (pos->needs_mandatory && dccp_insert_option_mandatory(skb))
+			return -1;
+		/*
+		 * Enter CHANGING after transmitting the Change option (6.6.2).
+		 */
+		if (pos->state = FEAT_INITIALISING)
+			pos->state = FEAT_CHANGING;
+	}
+	return 0;
+}
+
+/**
  * __feat_register_nn  -  Register new NN value on socket
  * @fn: feature-negotiation list to register with
  * @feat: an NN feature from %dccp_feature_numbers

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/6] dccp: Integrate feature-negotiation insertion code
@ 2008-11-30 13:22                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

The patch implements insertion of feature negotiation at the server (listening
and request socket) and the client (connecting socket).

In dccp_insert_options(), several statements have been grouped together now
to achieve (it is hoped) better efficiency by reducing the number of tests
each packet has to go through:
 - Ack Vectors are sent if the packet is neither a Data or a Request packet;
 - a previous issue is corrected - feature negotiation options are allowed
   on DataAck packets (5.8).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/options.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -554,11 +554,25 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 	    dccp_insert_option_ndp(sk, skb))
 		return -1;
 
-	if (!dccp_packet_without_ack(skb)) {
-		if (dmsk->dccpms_send_ack_vector &&
-		    dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
-		    dccp_insert_option_ackvec(sk, skb))
+	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
+
+		/* Feature Negotiation */
+		if (dccp_feat_insert_opts(dp, NULL, skb))
 			return -1;
+
+		if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) {
+			/*
+			 * Obtain RTT sample from Request/Response exchange.
+			 * This is currently used in CCID 3 initialisation.
+			 */
+			if (dccp_insert_option_timestamp(sk, skb))
+				return -1;
+
+		} else if (dmsk->dccpms_send_ack_vector	&&
+			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
+			   dccp_insert_option_ackvec(sk, skb)) {
+				return -1;
+		}
 	}
 
 	if (dp->dccps_hc_rx_insert_options) {
@@ -567,14 +581,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/*
-	 * Obtain RTT sample from Request/Response exchange.
-	 * This is currently used in CCID 3 initialisation.
-	 */
-	if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST &&
-	    dccp_insert_option_timestamp(sk, skb))
-		return -1;
-
 	if (dp->dccps_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(dp, NULL, skb))
 		return -1;
@@ -587,6 +593,9 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
 {
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
+	if (dccp_feat_insert_opts(NULL, dreq, skb))
+		return -1;
+
 	if (dreq->dreq_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 		return -1;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/6] dccp: Integrate feature-negotiation insertion code
@ 2008-11-30 13:22                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

The patch implements insertion of feature negotiation at the server (listening
and request socket) and the client (connecting socket).

In dccp_insert_options(), several statements have been grouped together now
to achieve (it is hoped) better efficiency by reducing the number of tests
each packet has to go through:
 - Ack Vectors are sent if the packet is neither a Data or a Request packet;
 - a previous issue is corrected - feature negotiation options are allowed
   on DataAck packets (5.8).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/options.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -554,11 +554,25 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 	    dccp_insert_option_ndp(sk, skb))
 		return -1;
 
-	if (!dccp_packet_without_ack(skb)) {
-		if (dmsk->dccpms_send_ack_vector &&
-		    dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
-		    dccp_insert_option_ackvec(sk, skb))
+	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
+
+		/* Feature Negotiation */
+		if (dccp_feat_insert_opts(dp, NULL, skb))
 			return -1;
+
+		if (DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST) {
+			/*
+			 * Obtain RTT sample from Request/Response exchange.
+			 * This is currently used in CCID 3 initialisation.
+			 */
+			if (dccp_insert_option_timestamp(sk, skb))
+				return -1;
+
+		} else if (dmsk->dccpms_send_ack_vector	&&
+			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
+			   dccp_insert_option_ackvec(sk, skb)) {
+				return -1;
+		}
 	}
 
 	if (dp->dccps_hc_rx_insert_options) {
@@ -567,14 +581,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 		dp->dccps_hc_rx_insert_options = 0;
 	}
 
-	/*
-	 * Obtain RTT sample from Request/Response exchange.
-	 * This is currently used in CCID 3 initialisation.
-	 */
-	if (DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST &&
-	    dccp_insert_option_timestamp(sk, skb))
-		return -1;
-
 	if (dp->dccps_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(dp, NULL, skb))
 		return -1;
@@ -587,6 +593,9 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb)
 {
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
+	if (dccp_feat_insert_opts(NULL, dreq, skb))
+		return -1;
+
 	if (dreq->dreq_timestamp_echo != 0 &&
 	    dccp_insert_option_timestamp_echo(NULL, dreq, skb))
 		return -1;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/6] dccp: Preference list reconciliation
@ 2008-11-30 13:22                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This provides two functions to
 * reconcile preference lists (with appropriate return codes) and
 * reorder the preference list if successful reconciliation changed the
   preferred value.

The patch also removes the old code for processing SP/NN Change options, since
new code to process these is mostly there already; related references have been
commented out.

The code for processing Change options follows in the next patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 2 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -690,6 +690,76 @@ static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
 	return 0;
 }
 
+/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
+static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
+{
+	u8 c, s;
+
+	for (s = 0; s < slen; s++)
+		for (c = 0; c < clen; c++)
+			if (servlist[s] == clilist[c])
+				return servlist[s];
+	return -1;
+}
+
+/**
+ * dccp_feat_prefer  -  Move preferred entry to the start of array
+ * Reorder the @array_len elements in @array so that @preferred_value comes
+ * first. Returns >0 to indicate that @preferred_value does occur in @array.
+ */
+static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len)
+{
+	u8 i, does_occur = 0;
+
+	if (array != NULL) {
+		for (i = 0; i < array_len; i++)
+			if (array[i] == preferred_value) {
+				array[i] = array[0];
+				does_occur++;
+			}
+		if (does_occur)
+			array[0] = preferred_value;
+	}
+	return does_occur;
+}
+
+/**
+ * dccp_feat_reconcile  -  Reconcile SP preference lists
+ *  @fval: SP list to reconcile into
+ *  @arr: received SP preference list
+ *  @len: length of @arr in bytes
+ *  @is_server: whether this side is the server (and @fv is the server's list)
+ *  @reorder: whether to reorder the list in @fv after reconciling with @arr
+ * When successful, > 0 is returned and the reconciled list is in @fval.
+ * A value of 0 means that negotiation failed (no shared entry).
+ */
+static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
+			       bool is_server, bool reorder)
+{
+	int rc;
+
+	if (!fv->sp.vec || !arr) {
+		DCCP_CRIT("NULL feature value or array");
+		return 0;
+	}
+
+	if (is_server)
+		rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len);
+	else
+		rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len);
+
+	if (!reorder)
+		return rc;
+	if (rc < 0)
+		return 0;
+
+	/*
+	 * Reorder list: used for activating features and in dccp_insert_fn_opt.
+	 */
+	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
+}
+
+#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
 static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
 			       u8 *rpref, u8 rlen)
 {
@@ -885,6 +955,7 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
+#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -960,12 +1031,14 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 	switch (feature) {
 	/* deal with SP features */
 	case DCCPF_CCID:
-		rc = dccp_feat_sp(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_sp(sk, type, feature, val, len); */
 		break;
 
 	/* deal with NN features */
 	case DCCPF_ACK_RATIO:
-		rc = dccp_feat_nn(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_nn(sk, type, feature, val, len); */
 		break;
 
 	/* XXX implement other features */

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/6] dccp: Preference list reconciliation
@ 2008-11-30 13:22                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

This provides two functions to
 * reconcile preference lists (with appropriate return codes) and
 * reorder the preference list if successful reconciliation changed the
   preferred value.

The patch also removes the old code for processing SP/NN Change options, since
new code to process these is mostly there already; related references have been
commented out.

The code for processing Change options follows in the next patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 2 deletions(-)

--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -690,6 +690,76 @@ static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
 	return 0;
 }
 
+/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
+static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
+{
+	u8 c, s;
+
+	for (s = 0; s < slen; s++)
+		for (c = 0; c < clen; c++)
+			if (servlist[s] = clilist[c])
+				return servlist[s];
+	return -1;
+}
+
+/**
+ * dccp_feat_prefer  -  Move preferred entry to the start of array
+ * Reorder the @array_len elements in @array so that @preferred_value comes
+ * first. Returns >0 to indicate that @preferred_value does occur in @array.
+ */
+static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len)
+{
+	u8 i, does_occur = 0;
+
+	if (array != NULL) {
+		for (i = 0; i < array_len; i++)
+			if (array[i] = preferred_value) {
+				array[i] = array[0];
+				does_occur++;
+			}
+		if (does_occur)
+			array[0] = preferred_value;
+	}
+	return does_occur;
+}
+
+/**
+ * dccp_feat_reconcile  -  Reconcile SP preference lists
+ *  @fval: SP list to reconcile into
+ *  @arr: received SP preference list
+ *  @len: length of @arr in bytes
+ *  @is_server: whether this side is the server (and @fv is the server's list)
+ *  @reorder: whether to reorder the list in @fv after reconciling with @arr
+ * When successful, > 0 is returned and the reconciled list is in @fval.
+ * A value of 0 means that negotiation failed (no shared entry).
+ */
+static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
+			       bool is_server, bool reorder)
+{
+	int rc;
+
+	if (!fv->sp.vec || !arr) {
+		DCCP_CRIT("NULL feature value or array");
+		return 0;
+	}
+
+	if (is_server)
+		rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len);
+	else
+		rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len);
+
+	if (!reorder)
+		return rc;
+	if (rc < 0)
+		return 0;
+
+	/*
+	 * Reorder list: used for activating features and in dccp_insert_fn_opt.
+	 */
+	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
+}
+
+#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
 static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
 			       u8 *rpref, u8 rlen)
 {
@@ -885,6 +955,7 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
+#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -960,12 +1031,14 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 	switch (feature) {
 	/* deal with SP features */
 	case DCCPF_CCID:
-		rc = dccp_feat_sp(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_sp(sk, type, feature, val, len); */
 		break;
 
 	/* deal with NN features */
 	case DCCPF_ACK_RATIO:
-		rc = dccp_feat_nn(sk, type, feature, val, len);
+		/* XXX Obsoleted by next patch
+		rc = dccp_feat_nn(sk, type, feature, val, len); */
 		break;
 
 	/* XXX implement other features */

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/6] dccp: Process incoming Change feature-negotiation options
@ 2008-11-30 13:22                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This adds/replaces code for processing incoming ChangeL/R options.
The main difference is that:
 * mandatory FN options are now interpreted inside the function
  (there are too many individual cases to do this externally);
 * the function returns an appropriate Reset code or 0,
   which is then used to fill in the data for the Reset packet.

Old code, which is no longer used or referenced, has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.h    |    4 +-
 net/dccp/feat.c    |  180 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/options.c |   23 ++----
 3 files changed, 189 insertions(+), 18 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -116,8 +116,8 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
-extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
-				  u8 *val, u8 len);
+extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
+				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -237,6 +237,40 @@ static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
 	return 0;
 }
 
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new == NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval == NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
 static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
 {
 	list_del(&entry->node);
@@ -955,7 +989,6 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
-#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -1066,6 +1099,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
+#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1206,6 +1240,150 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
+/**
+ * dccp_feat_change_recv  -  Process incoming ChangeL/R options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether the Change was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is the server (1) or the client (0)
+ */
+static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 defval, type = dccp_feat_type(feat);
+	const bool local = (opt == DCCPO_CHANGE_R);
+	struct dccp_feat_entry *entry;
+	dccp_feat_val fval;
+
+	if (len == 0 || type == FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
+		goto unknown_feature_or_value;
+
+	/*
+	 *	Negotiation of NN features: Change R is invalid, so there is no
+	 *	simultaneous negotiation; hence we do not look up in the list.
+	 */
+	if (type == FEAT_NN) {
+		if (local || len > sizeof(fval.nn))
+			goto unknown_feature_or_value;
+
+		/* 6.3.2: "The feature remote MUST accept any valid value..." */
+		fval.nn = dccp_decode_value_var(val, len);
+		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+			goto unknown_feature_or_value;
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+	}
+
+	/*
+	 *	Unidirectional/simultaneous negotiation of SP features (6.3.1)
+	 */
+	entry = dccp_feat_list_lookup(fn, feat, local);
+	if (entry == NULL) {
+		/*
+		 * No particular preferences have been registered. We deal with
+		 * this situation by assuming that all valid values are equally
+		 * acceptable, and apply the following checks:
+		 * - if the peer's list is a singleton, we accept a valid value;
+		 * - if we are the server, we first try to see if the peer (the
+		 *   client) advertises the default value. If yes, we use it,
+		 *   otherwise we accept the preferred value;
+		 * - else if we are the client, we use the first list element.
+		 */
+		if (dccp_feat_clone_sp_val(&fval, val, 1))
+			return DCCP_RESET_CODE_TOO_BUSY;
+
+		if (len > 1 && server) {
+			defval = dccp_feat_default_value(feat);
+			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
+				fval.sp.vec[0] = defval;
+		} else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
+			kfree(fval.sp.vec);
+			goto unknown_feature_or_value;
+		}
+
+		/* Treat unsupported CCIDs like invalid values */
+		if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
+			kfree(fval.sp.vec);
+			goto not_valid_or_not_known;
+		}
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+
+	} else if (entry->state == FEAT_UNSTABLE) {	/* 6.6.2 */
+		return 0;
+	}
+
+	if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
+		entry->empty_confirm = 0;
+	} else if (is_mandatory) {
+		return DCCP_RESET_CODE_MANDATORY_ERROR;
+	} else if (entry->state == FEAT_INITIALISING) {
+		/*
+		 * Failed simultaneous negotiation (server only): try to `save'
+		 * the connection by checking whether entry contains the default
+		 * value for @feat. If yes, send an empty Confirm to signal that
+		 * the received Change was not understood - which implies using
+		 * the default value.
+		 * If this also fails, we use Reset as the last resort.
+		 */
+		WARN_ON(!server);
+		defval = dccp_feat_default_value(feat);
+		if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
+			return DCCP_RESET_CODE_OPTION_ERROR;
+		entry->empty_confirm = 1;
+	}
+	entry->needs_confirm   = 1;
+	entry->needs_mandatory = 0;
+	entry->state	       = FEAT_STABLE;
+	return 0;
+
+unknown_feature_or_value:
+	if (!is_mandatory)
+		return dccp_push_empty_confirm(fn, feat, local);
+
+not_valid_or_not_known:
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
+ * dccp_feat_parse_options  -  Process Feature-Negotiation Options
+ * @sk: for general use and used by the client during connection setup
+ * @dreq: used by the server during connection setup
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: value contents of @opt
+ * @len: length of @val in bytes
+ * Returns 0 on success, a Reset code for ending the connection otherwise.
+ */
+int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
+			    u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	bool server = false;
+
+	switch (sk->sk_state) {
+	/*
+	 *	Negotiation during connection setup
+	 */
+	case DCCP_LISTEN:
+		server = true;			/* fall through */
+	case DCCP_REQUESTING:
+		switch (opt) {
+		case DCCPO_CHANGE_L:
+		case DCCPO_CHANGE_R:
+			return dccp_feat_change_recv(fn, mandatory, opt, feat,
+						     val, len, server);
+		}
+	}
+	return 0;	/* ignore FN options in all other states */
+}
+
 int dccp_feat_init(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -135,22 +135,13 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
 		case DCCPO_CHANGE_L:
-			/* fall through */
 		case DCCPO_CHANGE_R:
 			if (pkt_type == DCCP_PKT_DATA)
 				break;
-			if (len < 2)
-				goto out_invalid_option;
-			rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
-						   len - 1);
-			/*
-			 * When there is a change error, change_recv is
-			 * responsible for dealing with it.  i.e. reply with an
-			 * empty confirm.
-			 * If the change was mandatory, then we need to die.
-			 */
-			if (rc && mandatory)
-				goto out_invalid_option;
+			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
+						    *value, value + 1, len - 1);
+			if (rc)
+				goto out_featneg_failed;
 			break;
 		case DCCPO_CONFIRM_L:
 			/* fall through */
@@ -292,8 +283,10 @@ out_nonsensical_length:
 
 out_invalid_option:
 	DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
-	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
-	DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
+	rc = DCCP_RESET_CODE_OPTION_ERROR;
+out_featneg_failed:
+	DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
+	DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/6] dccp: Process incoming Change feature-negotiation options
@ 2008-11-30 13:22                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

This adds/replaces code for processing incoming ChangeL/R options.
The main difference is that:
 * mandatory FN options are now interpreted inside the function
  (there are too many individual cases to do this externally);
 * the function returns an appropriate Reset code or 0,
   which is then used to fill in the data for the Reset packet.

Old code, which is no longer used or referenced, has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
 net/dccp/feat.h    |    4 +-
 net/dccp/feat.c    |  180 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/options.c |   23 ++----
 3 files changed, 189 insertions(+), 18 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -116,8 +116,8 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
-extern int  dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature,
-				  u8 *val, u8 len);
+extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
+				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -237,6 +237,40 @@ static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
 	return 0;
 }
 
+/**
+ * dccp_feat_push_confirm  -  Add a Confirm entry to the FN list
+ * @fn_list: feature-negotiation list to add to
+ * @feat: one of %dccp_feature_numbers
+ * @local: whether local (1) or remote (0) @feat_num is being confirmed
+ * @fval: pointer to NN/SP value to be inserted or NULL
+ * Returns 0 on success, a Reset code for further processing otherwise.
+ */
+static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
+				  dccp_feat_val *fval)
+{
+	struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
+
+	if (new = NULL)
+		return DCCP_RESET_CODE_TOO_BUSY;
+
+	new->feat_num	     = feat;
+	new->is_local	     = local;
+	new->state	     = FEAT_STABLE;	/* transition in 6.6.2 */
+	new->needs_confirm   = 1;
+	new->empty_confirm   = (fval = NULL);
+	new->val.nn	     = 0;		/* zeroes the whole structure */
+	if (!new->empty_confirm)
+		new->val     = *fval;
+	new->needs_mandatory = 0;
+
+	return 0;
+}
+
+static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
+{
+	return dccp_feat_push_confirm(fn_list, feat, local, NULL);
+}
+
 static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
 {
 	list_del(&entry->node);
@@ -955,7 +989,6 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 
 	return 0;
 }
-#endif /* (later) */
 
 static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
 				    u8 type, u8 feature)
@@ -1066,6 +1099,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
+#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1206,6 +1240,150 @@ out_clean:
 
 EXPORT_SYMBOL_GPL(dccp_feat_clone);
 
+/**
+ * dccp_feat_change_recv  -  Process incoming ChangeL/R options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether the Change was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is the server (1) or the client (0)
+ */
+static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 defval, type = dccp_feat_type(feat);
+	const bool local = (opt = DCCPO_CHANGE_R);
+	struct dccp_feat_entry *entry;
+	dccp_feat_val fval;
+
+	if (len = 0 || type = FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
+		goto unknown_feature_or_value;
+
+	/*
+	 *	Negotiation of NN features: Change R is invalid, so there is no
+	 *	simultaneous negotiation; hence we do not look up in the list.
+	 */
+	if (type = FEAT_NN) {
+		if (local || len > sizeof(fval.nn))
+			goto unknown_feature_or_value;
+
+		/* 6.3.2: "The feature remote MUST accept any valid value..." */
+		fval.nn = dccp_decode_value_var(val, len);
+		if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
+			goto unknown_feature_or_value;
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+	}
+
+	/*
+	 *	Unidirectional/simultaneous negotiation of SP features (6.3.1)
+	 */
+	entry = dccp_feat_list_lookup(fn, feat, local);
+	if (entry = NULL) {
+		/*
+		 * No particular preferences have been registered. We deal with
+		 * this situation by assuming that all valid values are equally
+		 * acceptable, and apply the following checks:
+		 * - if the peer's list is a singleton, we accept a valid value;
+		 * - if we are the server, we first try to see if the peer (the
+		 *   client) advertises the default value. If yes, we use it,
+		 *   otherwise we accept the preferred value;
+		 * - else if we are the client, we use the first list element.
+		 */
+		if (dccp_feat_clone_sp_val(&fval, val, 1))
+			return DCCP_RESET_CODE_TOO_BUSY;
+
+		if (len > 1 && server) {
+			defval = dccp_feat_default_value(feat);
+			if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
+				fval.sp.vec[0] = defval;
+		} else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
+			kfree(fval.sp.vec);
+			goto unknown_feature_or_value;
+		}
+
+		/* Treat unsupported CCIDs like invalid values */
+		if (feat = DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
+			kfree(fval.sp.vec);
+			goto not_valid_or_not_known;
+		}
+
+		return dccp_feat_push_confirm(fn, feat, local, &fval);
+
+	} else if (entry->state = FEAT_UNSTABLE) {	/* 6.6.2 */
+		return 0;
+	}
+
+	if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
+		entry->empty_confirm = 0;
+	} else if (is_mandatory) {
+		return DCCP_RESET_CODE_MANDATORY_ERROR;
+	} else if (entry->state = FEAT_INITIALISING) {
+		/*
+		 * Failed simultaneous negotiation (server only): try to `save'
+		 * the connection by checking whether entry contains the default
+		 * value for @feat. If yes, send an empty Confirm to signal that
+		 * the received Change was not understood - which implies using
+		 * the default value.
+		 * If this also fails, we use Reset as the last resort.
+		 */
+		WARN_ON(!server);
+		defval = dccp_feat_default_value(feat);
+		if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
+			return DCCP_RESET_CODE_OPTION_ERROR;
+		entry->empty_confirm = 1;
+	}
+	entry->needs_confirm   = 1;
+	entry->needs_mandatory = 0;
+	entry->state	       = FEAT_STABLE;
+	return 0;
+
+unknown_feature_or_value:
+	if (!is_mandatory)
+		return dccp_push_empty_confirm(fn, feat, local);
+
+not_valid_or_not_known:
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
+ * dccp_feat_parse_options  -  Process Feature-Negotiation Options
+ * @sk: for general use and used by the client during connection setup
+ * @dreq: used by the server during connection setup
+ * @mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: value contents of @opt
+ * @len: length of @val in bytes
+ * Returns 0 on success, a Reset code for ending the connection otherwise.
+ */
+int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
+			    u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
+	bool server = false;
+
+	switch (sk->sk_state) {
+	/*
+	 *	Negotiation during connection setup
+	 */
+	case DCCP_LISTEN:
+		server = true;			/* fall through */
+	case DCCP_REQUESTING:
+		switch (opt) {
+		case DCCPO_CHANGE_L:
+		case DCCPO_CHANGE_R:
+			return dccp_feat_change_recv(fn, mandatory, opt, feat,
+						     val, len, server);
+		}
+	}
+	return 0;	/* ignore FN options in all other states */
+}
+
 int dccp_feat_init(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -135,22 +135,13 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
 		case DCCPO_CHANGE_L:
-			/* fall through */
 		case DCCPO_CHANGE_R:
 			if (pkt_type = DCCP_PKT_DATA)
 				break;
-			if (len < 2)
-				goto out_invalid_option;
-			rc = dccp_feat_change_recv(sk, opt, *value, value + 1,
-						   len - 1);
-			/*
-			 * When there is a change error, change_recv is
-			 * responsible for dealing with it.  i.e. reply with an
-			 * empty confirm.
-			 * If the change was mandatory, then we need to die.
-			 */
-			if (rc && mandatory)
-				goto out_invalid_option;
+			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
+						    *value, value + 1, len - 1);
+			if (rc)
+				goto out_featneg_failed;
 			break;
 		case DCCPO_CONFIRM_L:
 			/* fall through */
@@ -292,8 +283,10 @@ out_nonsensical_length:
 
 out_invalid_option:
 	DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
-	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR;
-	DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len);
+	rc = DCCP_RESET_CODE_OPTION_ERROR;
+out_featneg_failed:
+	DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
+	DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
 	DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/6] dccp: Processing Confirm options
@ 2008-11-30 13:22                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

Analogous to the previous patch, this adds code to interpret incoming Confirm
feature-negotiation options. Both functions operate on the feature-negotiation
list of either the request_sock (server) or the dccp_sock (client).

Thanks to Wei Yongjun for pointing out that it is overly restrictive to check
the entire list of confirmed SP values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |    2 -
 net/dccp/feat.c    |  100 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/options.c |   16 +-------
 3 files changed, 101 insertions(+), 17 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -118,8 +118,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -104,6 +104,13 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
+/* Test for "Req'd" feature (RFC 4340, 6.4) */
+static inline int dccp_feat_must_be_understood(u8 feat_num)
+{
+	return	feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS ||
+		feat_num == DCCPF_SEQUENCE_WINDOW;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -1099,7 +1106,6 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1154,6 +1160,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
+#endif	/* (later) */
 
 void dccp_feat_clean(struct dccp_minisock *dmsk)
 {
@@ -1350,6 +1357,93 @@ not_valid_or_not_known:
 }
 
 /**
+ * dccp_feat_confirm_recv  -  Process received Confirm options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is server (1) or client (0)
+ */
+static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				 u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 *plist, plen, type = dccp_feat_type(feat);
+	const bool local = (opt == DCCPO_CONFIRM_R);
+	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
+
+	if (entry == NULL) {	/* nothing queued: ignore or handle error */
+		if (is_mandatory && type == FEAT_UNKNOWN)
+			return DCCP_RESET_CODE_MANDATORY_ERROR;
+
+		if (!local && type == FEAT_NN)		/* 6.3.2 */
+			goto confirmation_failed;
+		return 0;
+	}
+
+	if (entry->state != FEAT_CHANGING)		/* 6.6.2 */
+		return 0;
+
+	if (len == 0) {
+		if (dccp_feat_must_be_understood(feat))	/* 6.6.7 */
+			goto confirmation_failed;
+		/*
+		 * Empty Confirm during connection setup: this means reverting
+		 * to the `old' value, which in this case is the default. Since
+		 * we handle default values automatically when no other values
+		 * have been set, we revert to the old value by removing this
+		 * entry from the list.
+		 */
+		dccp_feat_list_pop(entry);
+		return 0;
+	}
+
+	if (type == FEAT_NN) {
+		if (len > sizeof(entry->val.nn))
+			goto confirmation_failed;
+
+		if (entry->val.nn == dccp_decode_value_var(val, len))
+			goto confirmation_succeeded;
+
+		DCCP_WARN("Bogus Confirm for non-existing value\n");
+		goto confirmation_failed;
+	}
+
+	/*
+	 * Parsing SP Confirms: the first element of @val is the preferred
+	 * SP value which the peer confirms, the remainder depends on @len.
+	 * Note that only the confirmed value need to be a valid SP value.
+	 */
+	if (!dccp_feat_is_valid_sp_val(feat, *val))
+		goto confirmation_failed;
+
+	if (len == 1) {		/* peer didn't supply a preference list */
+		plist = val;
+		plen  = len;
+	} else {		/* preferred value + preference list */
+		plist = val + 1;
+		plen  = len - 1;
+	}
+
+	/* Check whether the peer got the reconciliation right (6.6.8) */
+	if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
+		DCCP_WARN("Confirm selected the wrong value %u\n", *val);
+		return DCCP_RESET_CODE_OPTION_ERROR;
+	}
+	entry->val.sp.vec[0] = *val;
+
+confirmation_succeeded:
+	entry->state = FEAT_STABLE;
+	return 0;
+
+confirmation_failed:
+	DCCP_WARN("Confirmation failed\n");
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
  * dccp_feat_parse_options  -  Process Feature-Negotiation Options
  * @sk: for general use and used by the client during connection setup
  * @dreq: used by the server during connection setup
@@ -1379,6 +1473,10 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_CHANGE_R:
 			return dccp_feat_change_recv(fn, mandatory, opt, feat,
 						     val, len, server);
+		case DCCPO_CONFIRM_R:
+		case DCCPO_CONFIRM_L:
+			return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
+						      val, len, server);
 		}
 	}
 	return 0;	/* ignore FN options in all other states */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -134,26 +134,14 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 			dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
-		case DCCPO_CHANGE_L:
-		case DCCPO_CHANGE_R:
-			if (pkt_type == DCCP_PKT_DATA)
+		case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
+			if (pkt_type == DCCP_PKT_DATA)      /* RFC 4340, 6 */
 				break;
 			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
 						    *value, value + 1, len - 1);
 			if (rc)
 				goto out_featneg_failed;
 			break;
-		case DCCPO_CONFIRM_L:
-			/* fall through */
-		case DCCPO_CONFIRM_R:
-			if (pkt_type == DCCP_PKT_DATA)
-				break;
-			if (len < 2)	/* FIXME this disallows empty confirm */
-				goto out_invalid_option;
-			if (dccp_feat_confirm_recv(sk, opt, *value,
-						   value + 1, len - 1))
-				goto out_invalid_option;
-			break;
 		case DCCPO_ACK_VECTOR_0:
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/6] dccp: Processing Confirm options
@ 2008-11-30 13:22                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

Analogous to the previous patch, this adds code to interpret incoming Confirm
feature-negotiation options. Both functions operate on the feature-negotiation
list of either the request_sock (server) or the dccp_sock (client).

Thanks to Wei Yongjun for pointing out that it is overly restrictive to check
the entire list of confirmed SP values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h    |    2 -
 net/dccp/feat.c    |  100 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 net/dccp/options.c |   16 +-------
 3 files changed, 101 insertions(+), 17 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -118,8 +118,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern int  dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-				   u8 *val, u8 len);
 extern void dccp_feat_clean(struct dccp_minisock *dmsk);
 extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -104,6 +104,13 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
+/* Test for "Req'd" feature (RFC 4340, 6.4) */
+static inline int dccp_feat_must_be_understood(u8 feat_num)
+{
+	return	feat_num = DCCPF_CCID || feat_num = DCCPF_SHORT_SEQNOS ||
+		feat_num = DCCPF_SEQUENCE_WINDOW;
+}
+
 /* copy constructor, fval must not already contain allocated memory */
 static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
 {
@@ -1099,7 +1106,6 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-#endif	/* (later) */
 
 int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 			   u8 *val, u8 len)
@@ -1154,6 +1160,7 @@ int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
 }
 
 EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
+#endif	/* (later) */
 
 void dccp_feat_clean(struct dccp_minisock *dmsk)
 {
@@ -1350,6 +1357,93 @@ not_valid_or_not_known:
 }
 
 /**
+ * dccp_feat_confirm_recv  -  Process received Confirm options
+ * @fn: feature-negotiation list to update
+ * @is_mandatory: whether @opt was preceded by a Mandatory option
+ * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R
+ * @feat: one of %dccp_feature_numbers
+ * @val: NN value or SP value/preference list
+ * @len: length of @val in bytes
+ * @server: whether this node is server (1) or client (0)
+ */
+static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
+				 u8 feat, u8 *val, u8 len, const bool server)
+{
+	u8 *plist, plen, type = dccp_feat_type(feat);
+	const bool local = (opt = DCCPO_CONFIRM_R);
+	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
+
+	if (entry = NULL) {	/* nothing queued: ignore or handle error */
+		if (is_mandatory && type = FEAT_UNKNOWN)
+			return DCCP_RESET_CODE_MANDATORY_ERROR;
+
+		if (!local && type = FEAT_NN)		/* 6.3.2 */
+			goto confirmation_failed;
+		return 0;
+	}
+
+	if (entry->state != FEAT_CHANGING)		/* 6.6.2 */
+		return 0;
+
+	if (len = 0) {
+		if (dccp_feat_must_be_understood(feat))	/* 6.6.7 */
+			goto confirmation_failed;
+		/*
+		 * Empty Confirm during connection setup: this means reverting
+		 * to the `old' value, which in this case is the default. Since
+		 * we handle default values automatically when no other values
+		 * have been set, we revert to the old value by removing this
+		 * entry from the list.
+		 */
+		dccp_feat_list_pop(entry);
+		return 0;
+	}
+
+	if (type = FEAT_NN) {
+		if (len > sizeof(entry->val.nn))
+			goto confirmation_failed;
+
+		if (entry->val.nn = dccp_decode_value_var(val, len))
+			goto confirmation_succeeded;
+
+		DCCP_WARN("Bogus Confirm for non-existing value\n");
+		goto confirmation_failed;
+	}
+
+	/*
+	 * Parsing SP Confirms: the first element of @val is the preferred
+	 * SP value which the peer confirms, the remainder depends on @len.
+	 * Note that only the confirmed value need to be a valid SP value.
+	 */
+	if (!dccp_feat_is_valid_sp_val(feat, *val))
+		goto confirmation_failed;
+
+	if (len = 1) {		/* peer didn't supply a preference list */
+		plist = val;
+		plen  = len;
+	} else {		/* preferred value + preference list */
+		plist = val + 1;
+		plen  = len - 1;
+	}
+
+	/* Check whether the peer got the reconciliation right (6.6.8) */
+	if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) {
+		DCCP_WARN("Confirm selected the wrong value %u\n", *val);
+		return DCCP_RESET_CODE_OPTION_ERROR;
+	}
+	entry->val.sp.vec[0] = *val;
+
+confirmation_succeeded:
+	entry->state = FEAT_STABLE;
+	return 0;
+
+confirmation_failed:
+	DCCP_WARN("Confirmation failed\n");
+	return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
+			    : DCCP_RESET_CODE_OPTION_ERROR;
+}
+
+/**
  * dccp_feat_parse_options  -  Process Feature-Negotiation Options
  * @sk: for general use and used by the client during connection setup
  * @dreq: used by the server during connection setup
@@ -1379,6 +1473,10 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_CHANGE_R:
 			return dccp_feat_change_recv(fn, mandatory, opt, feat,
 						     val, len, server);
+		case DCCPO_CONFIRM_R:
+		case DCCPO_CONFIRM_L:
+			return dccp_feat_confirm_recv(fn, mandatory, opt, feat,
+						      val, len, server);
 		}
 	}
 	return 0;	/* ignore FN options in all other states */
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -134,26 +134,14 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 			dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk),
 				      (unsigned long long)opt_recv->dccpor_ndp);
 			break;
-		case DCCPO_CHANGE_L:
-		case DCCPO_CHANGE_R:
-			if (pkt_type = DCCP_PKT_DATA)
+		case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R:
+			if (pkt_type = DCCP_PKT_DATA)      /* RFC 4340, 6 */
 				break;
 			rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
 						    *value, value + 1, len - 1);
 			if (rc)
 				goto out_featneg_failed;
 			break;
-		case DCCPO_CONFIRM_L:
-			/* fall through */
-		case DCCPO_CONFIRM_R:
-			if (pkt_type = DCCP_PKT_DATA)
-				break;
-			if (len < 2)	/* FIXME this disallows empty confirm */
-				goto out_invalid_option;
-			if (dccp_feat_confirm_recv(sk, opt, *value,
-						   value + 1, len - 1))
-				goto out_invalid_option;
-			break;
 		case DCCPO_ACK_VECTOR_0:
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 6/6] dccp: Feature activation handlers
@ 2008-11-30 13:22                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch provides the post-processing of feature negotiation state, after
the negotiation has completed.

To this purpose, handlers are used and added to the dccp_feat_table. Each
handler is passed a boolean flag whether the RX or TX side of the feature
is meant.

Several handlers are provided already, new handlers can easily be added.

The initialisation is now fully dynamic, i.e. CCIDs are activated only
after the feature negotiation. The integration of this dynamic activation
is done in the subsequent patches.

Thanks to Wei Yongjun for pointing out the necessity of skipping over empty
Confirm options while copying the negotiated feature values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    1 +
 net/dccp/feat.c |  213 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 204 insertions(+), 10 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -445,6 +445,7 @@ 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*,
 				  struct sk_buff *skb);
+extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,11 +25,101 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/*
+ * Feature activation handlers.
+ *
+ * These all use an u64 argument, to provide enough room for NN/SP features. At
+ * this stage the negotiated values have been checked to be within their range.
+ */
+static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
+
+	if (new_ccid == NULL)
+		return -ENOMEM;
+
+	if (rx) {
+		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+		dp->dccps_hc_rx_ccid = new_ccid;
+	} else {
+		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+		dp->dccps_hc_tx_ccid = new_ccid;
+	}
+	return 0;
+}
+
+static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	return 0;
+}
+
+static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
+{
+	if (rx)
+		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
+	else
+		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
+	return 0;
+}
+
+static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		if (enable && dp->dccps_hc_rx_ackvec == NULL) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
+			if (dp->dccps_hc_rx_ackvec == NULL)
+				return -ENOMEM;
+		} else if (!enable) {
+			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+			dp->dccps_hc_rx_ackvec = NULL;
+		}
+	}
+	return 0;
+}
+
+static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+	return 0;
+}
+
+/*
+ * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
+ * `rx' holds when the sending peer informs about his partial coverage via a
+ * ChangeR() option. In the other case, we are the sender and the receiver
+ * announces its coverage via ChangeL() options. The policy here is to honour
+ * such communication by enabling the corresponding partial coverage - but only
+ * if it has not been set manually before; the warning here means that all
+ * packets will be dropped.
+ */
+static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx)
+		dp->dccps_pcrlen = cscov;
+	else {
+		if (dp->dccps_pcslen == 0)
+			dp->dccps_pcslen = cscov;
+		else if (cscov > dp->dccps_pcslen)
+			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
+				  dp->dccps_pcslen, (u8)cscov);
+	}
+	return 0;
+}
+
 static const struct {
 	u8			feat_num;		/* DCCPF_xxx */
 	enum dccp_feat_type	rxtx;			/* RX or TX  */
 	enum dccp_feat_type	reconciliation;		/* SP or NN  */
 	u8			default_value;		/* as in 6.4 */
+	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
 /*
  *    Lookup table for location and type of features (from RFC 4340/4342)
  *  +--------------------------+----+-----+----+----+---------+-----------+
@@ -49,16 +139,16 @@ static const struct {
  *  +--------------------------+----+-----+----+----+---------+-----------+
  */
 } dccp_feat_table[] = {
-	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
-	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
-	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
-	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
@@ -104,6 +194,41 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
+static int __dccp_feat_activate(struct sock *sk, const int idx,
+				const bool is_local, dccp_feat_val const *fval)
+{
+	bool rx;
+	u64 val;
+
+	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
+		return -1;
+	if (dccp_feat_table[idx].activation_hdlr == NULL)
+		return 0;
+
+	if (fval == NULL) {
+		val = dccp_feat_table[idx].default_value;
+	} else if (dccp_feat_table[idx].reconciliation == FEAT_SP) {
+		if (fval->sp.vec == NULL) {
+			/*
+			 * This can happen when an empty Confirm is sent
+			 * for an SP (i.e. known) feature. In this case
+			 * we would be using the default anyway.
+			 */
+			DCCP_CRIT("Feature #%d undefined: using default", idx);
+			val = dccp_feat_table[idx].default_value;
+		} else {
+			val = fval->sp.vec[0];
+		}
+	} else {
+		val = fval->nn;
+	}
+
+	/* Location is RX if this is a local-RX or remote-TX feature */
+	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
+
+	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
+}
+
 /* Test for "Req'd" feature (RFC 4340, 6.4) */
 static inline int dccp_feat_must_be_understood(u8 feat_num)
 {
@@ -1512,6 +1637,74 @@ out:
 
 EXPORT_SYMBOL_GPL(dccp_feat_init);
 
+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_feat_entry *cur, *next;
+	int idx;
+	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
+		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
+	};
+
+	list_for_each_entry(cur, fn_list, node) {
+		/*
+		 * An empty Confirm means that either an unknown feature type
+		 * or an invalid value was present. In the first case there is
+		 * nothing to activate, in the other the default value is used.
+		 */
+		if (cur->empty_confirm)
+			continue;
+
+		idx = dccp_feat_index(cur->feat_num);
+		if (idx < 0) {
+			DCCP_BUG("Unknown feature %u", cur->feat_num);
+			goto activation_failed;
+		}
+		if (cur->state != FEAT_STABLE) {
+			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+				  cur->is_local ? "local" : "remote",
+				  cur->feat_num, cur->state);
+			goto activation_failed;
+		}
+		fvals[idx][cur->is_local] = &cur->val;
+	}
+
+	/*
+	 * Activate in decreasing order of index, so that the CCIDs are always
+	 * activated as the last feature. This avoids the case where a CCID
+	 * relies on the initialisation of one or more features that it depends
+	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
+	 */
+	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
+		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
+		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
+			DCCP_CRIT("Could not activate %d", idx);
+			goto activation_failed;
+		}
+
+	/* Clean up Change options which have been confirmed already */
+	list_for_each_entry_safe(cur, next, fn_list, node)
+		if (!cur->needs_confirm)
+			dccp_feat_list_pop(cur);
+
+	dccp_pr_debug("Activation OK\n");
+	return 0;
+
+activation_failed:
+	/*
+	 * We clean up everything that may have been allocated, since
+	 * it is difficult to track at which stage negotiation failed.
+	 * This is ok, since all allocation functions below are robust
+	 * against NULL arguments.
+	 */
+	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+	dp->dccps_hc_rx_ackvec = NULL;
+	return -1;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 const char *dccp_feat_typename(const u8 type)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 6/6] dccp: Feature activation handlers
@ 2008-11-30 13:22                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-11-30 13:22 UTC (permalink / raw)
  To: dccp

This patch provides the post-processing of feature negotiation state, after
the negotiation has completed.

To this purpose, handlers are used and added to the dccp_feat_table. Each
handler is passed a boolean flag whether the RX or TX side of the feature
is meant.

Several handlers are provided already, new handlers can easily be added.

The initialisation is now fully dynamic, i.e. CCIDs are activated only
after the feature negotiation. The integration of this dynamic activation
is done in the subsequent patches.

Thanks to Wei Yongjun for pointing out the necessity of skipping over empty
Confirm options while copying the negotiated feature values.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h |    1 +
 net/dccp/feat.c |  213 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 204 insertions(+), 10 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -445,6 +445,7 @@ 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*,
 				  struct sk_buff *skb);
+extern int  dccp_feat_activate_values(struct sock *sk, struct list_head *fn);
 extern void dccp_feat_list_purge(struct list_head *fn_list);
 
 extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,11 +25,101 @@
 
 #define DCCP_FEAT_SP_NOAGREE (-123)
 
+/*
+ * Feature activation handlers.
+ *
+ * These all use an u64 argument, to provide enough room for NN/SP features. At
+ * this stage the negotiated values have been checked to be within their range.
+ */
+static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any());
+
+	if (new_ccid = NULL)
+		return -ENOMEM;
+
+	if (rx) {
+		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+		dp->dccps_hc_rx_ccid = new_ccid;
+	} else {
+		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+		dp->dccps_hc_tx_ccid = new_ccid;
+	}
+	return 0;
+}
+
+static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	return 0;
+}
+
+static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx)
+{
+	if (rx)
+		dccp_sk(sk)->dccps_r_ack_ratio = ratio;
+	else
+		dccp_sk(sk)->dccps_l_ack_ratio = ratio;
+	return 0;
+}
+
+static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		if (enable && dp->dccps_hc_rx_ackvec = NULL) {
+			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any());
+			if (dp->dccps_hc_rx_ackvec = NULL)
+				return -ENOMEM;
+		} else if (!enable) {
+			dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+			dp->dccps_hc_rx_ackvec = NULL;
+		}
+	}
+	return 0;
+}
+
+static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
+{
+	if (!rx)
+		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+	return 0;
+}
+
+/*
+ * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that
+ * `rx' holds when the sending peer informs about his partial coverage via a
+ * ChangeR() option. In the other case, we are the sender and the receiver
+ * announces its coverage via ChangeL() options. The policy here is to honour
+ * such communication by enabling the corresponding partial coverage - but only
+ * if it has not been set manually before; the warning here means that all
+ * packets will be dropped.
+ */
+static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx)
+		dp->dccps_pcrlen = cscov;
+	else {
+		if (dp->dccps_pcslen = 0)
+			dp->dccps_pcslen = cscov;
+		else if (cscov > dp->dccps_pcslen)
+			DCCP_WARN("CsCov %u too small, peer requires >= %u\n",
+				  dp->dccps_pcslen, (u8)cscov);
+	}
+	return 0;
+}
+
 static const struct {
 	u8			feat_num;		/* DCCPF_xxx */
 	enum dccp_feat_type	rxtx;			/* RX or TX  */
 	enum dccp_feat_type	reconciliation;		/* SP or NN  */
 	u8			default_value;		/* as in 6.4 */
+	int (*activation_hdlr)(struct sock *sk, u64 val, bool rx);
 /*
  *    Lookup table for location and type of features (from RFC 4340/4342)
  *  +--------------------------+----+-----+----+----+---------+-----------+
@@ -49,16 +139,16 @@ static const struct {
  *  +--------------------------+----+-----+----+----+---------+-----------+
  */
 } dccp_feat_table[] = {
-	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2 },
-	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100 },
-	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2 },
-	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0 },
-	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0 },
-	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0 },
+	{ DCCPF_CCID,		 FEAT_AT_TX, FEAT_SP, 2,   dccp_hdlr_ccid     },
+	{ DCCPF_SHORT_SEQNOS,	 FEAT_AT_TX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win  },
+	{ DCCPF_ECN_INCAPABLE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_ACK_RATIO,	 FEAT_AT_TX, FEAT_NN, 2,   dccp_hdlr_ack_ratio},
+	{ DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_ackvec   },
+	{ DCCPF_SEND_NDP_COUNT,  FEAT_AT_TX, FEAT_SP, 0,   dccp_hdlr_ndp      },
+	{ DCCPF_MIN_CSUM_COVER,  FEAT_AT_RX, FEAT_SP, 0,   dccp_hdlr_min_cscov},
+	{ DCCPF_DATA_CHECKSUM,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
+	{ DCCPF_SEND_LEV_RATE,	 FEAT_AT_RX, FEAT_SP, 0,   NULL },
 };
 #define DCCP_FEAT_SUPPORTED_MAX		ARRAY_SIZE(dccp_feat_table)
 
@@ -104,6 +194,41 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
+static int __dccp_feat_activate(struct sock *sk, const int idx,
+				const bool is_local, dccp_feat_val const *fval)
+{
+	bool rx;
+	u64 val;
+
+	if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX)
+		return -1;
+	if (dccp_feat_table[idx].activation_hdlr = NULL)
+		return 0;
+
+	if (fval = NULL) {
+		val = dccp_feat_table[idx].default_value;
+	} else if (dccp_feat_table[idx].reconciliation = FEAT_SP) {
+		if (fval->sp.vec = NULL) {
+			/*
+			 * This can happen when an empty Confirm is sent
+			 * for an SP (i.e. known) feature. In this case
+			 * we would be using the default anyway.
+			 */
+			DCCP_CRIT("Feature #%d undefined: using default", idx);
+			val = dccp_feat_table[idx].default_value;
+		} else {
+			val = fval->sp.vec[0];
+		}
+	} else {
+		val = fval->nn;
+	}
+
+	/* Location is RX if this is a local-RX or remote-TX feature */
+	rx = (is_local = (dccp_feat_table[idx].rxtx = FEAT_AT_RX));
+
+	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
+}
+
 /* Test for "Req'd" feature (RFC 4340, 6.4) */
 static inline int dccp_feat_must_be_understood(u8 feat_num)
 {
@@ -1512,6 +1637,74 @@ out:
 
 EXPORT_SYMBOL_GPL(dccp_feat_init);
 
+int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_feat_entry *cur, *next;
+	int idx;
+	dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = {
+		 [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL }
+	};
+
+	list_for_each_entry(cur, fn_list, node) {
+		/*
+		 * An empty Confirm means that either an unknown feature type
+		 * or an invalid value was present. In the first case there is
+		 * nothing to activate, in the other the default value is used.
+		 */
+		if (cur->empty_confirm)
+			continue;
+
+		idx = dccp_feat_index(cur->feat_num);
+		if (idx < 0) {
+			DCCP_BUG("Unknown feature %u", cur->feat_num);
+			goto activation_failed;
+		}
+		if (cur->state != FEAT_STABLE) {
+			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+				  cur->is_local ? "local" : "remote",
+				  cur->feat_num, cur->state);
+			goto activation_failed;
+		}
+		fvals[idx][cur->is_local] = &cur->val;
+	}
+
+	/*
+	 * Activate in decreasing order of index, so that the CCIDs are always
+	 * activated as the last feature. This avoids the case where a CCID
+	 * relies on the initialisation of one or more features that it depends
+	 * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features).
+	 */
+	for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;)
+		if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) ||
+		    __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) {
+			DCCP_CRIT("Could not activate %d", idx);
+			goto activation_failed;
+		}
+
+	/* Clean up Change options which have been confirmed already */
+	list_for_each_entry_safe(cur, next, fn_list, node)
+		if (!cur->needs_confirm)
+			dccp_feat_list_pop(cur);
+
+	dccp_pr_debug("Activation OK\n");
+	return 0;
+
+activation_failed:
+	/*
+	 * We clean up everything that may have been allocated, since
+	 * it is difficult to track at which stage negotiation failed.
+	 * This is ok, since all allocation functions below are robust
+	 * against NULL arguments.
+	 */
+	ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
+	ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
+	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
+	dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+	dp->dccps_hc_rx_ackvec = NULL;
+	return -1;
+}
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 const char *dccp_feat_typename(const u8 type)
 {
-- 
1.6.0.rc2


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II (core)
@ 2008-12-02  7:34                                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-02  7:34 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sun, 30 Nov 2008 14:22:50 +0100

> Patch #1: Continues where the previous patch set left off, by adding
>           the insertion of feature-negotiation options onto the skb.
> Patch #2: Completes the insertion of featneg options.
> Patch #3: Logic/algorithm to actually reconcile negotiation options.
> Patch #4: Receiver support to process incoming Change L/R options. 
> Patch #5: Receiver support to process incoming Confirm R/L options.
> Patch #6: Handlers for activating successfully negotiated features.

Looks fine enough, all applied to net-next-2.6, thanks Gerrit.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II
@ 2008-12-02  7:34                                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-02  7:34 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sun, 30 Nov 2008 14:22:50 +0100

> Patch #1: Continues where the previous patch set left off, by adding
>           the insertion of feature-negotiation options onto the skb.
> Patch #2: Completes the insertion of featneg options.
> Patch #3: Logic/algorithm to actually reconcile negotiation options.
> Patch #4: Receiver support to process incoming Change L/R options. 
> Patch #5: Receiver support to process incoming Confirm R/L options.
> Patch #6: Handlers for activating successfully negotiated features.

Looks fine enough, all applied to net-next-2.6, thanks Gerrit.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/7] dccp: Feature negotiation - Part III (integration)
@ 2008-12-06 16:40                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

please find enclosed the penultimate set, the first out of two in the last
block, of the feature-negotiation patch set submission.
I have checked these to compile individually. 

Gerrit


Commit summary:
---------------
This is a continuation of an ongoing submission to provide feature/capability
negotiation for DCCP endpoints (RFC 4340 - 4342, 5348).

The whole set is structured into 3 main blocks - (1) basis, (2) core, (3)
integration and cleanup.

This set is the first out of two in block (3) and  removes the old, now unused,
parts of the older interface and begins the integration of the new interface 
that formed part (2) of this submission.

The second and last part of block (3) deals with the initialization of 
feature-negotiation state.


List of patches in this set:
----------------------------
Patch #1: Integration of dynamic negotiation, part I (socket setup).
Patch #2: Integration of dynamic negotiation, part II (server side).
Patch #3: Integration of dynamic negotiation, part III (client side).
Patch #4: Cleans up the older infrastructure.
Patch #5: Removes obsolete parts of the old CCID interface.
Patch #6: Removes manual intervention on NDP count (now automatic).
Patch #7: Removes Ack Vector sysctl (handled automatically now).

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=c47390a8b5faaec4a41337714b2d80c85fc6ba26


Patch stats:
------------
 Documentation/networking/dccp.txt |   11 
 include/linux/dccp.h              |   10 
 net/dccp/ccid.c                   |   14 -
 net/dccp/ccid.h                   |    5 
 net/dccp/dccp.h                   |    4 
 net/dccp/diag.c                   |    2 
 net/dccp/feat.c                   |  519 --------------------------------------
 net/dccp/feat.h                   |   12 
 net/dccp/input.c                  |   42 ++-
 net/dccp/minisocks.c              |   46 ---
 net/dccp/options.c                |   11 
 net/dccp/proto.c                  |   49 ---
 net/dccp/sysctl.c                 |   14 -
 13 files changed, 70 insertions(+), 669 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/7] dccp: Feature negotiation - Part III (integration)
@ 2008-12-06 16:40                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find enclosed the penultimate set, the first out of two in the last
block, of the feature-negotiation patch set submission.
I have checked these to compile individually. 

Gerrit


Commit summary:
---------------
This is a continuation of an ongoing submission to provide feature/capability
negotiation for DCCP endpoints (RFC 4340 - 4342, 5348).

The whole set is structured into 3 main blocks - (1) basis, (2) core, (3)
integration and cleanup.

This set is the first out of two in block (3) and  removes the old, now unused,
parts of the older interface and begins the integration of the new interface 
that formed part (2) of this submission.

The second and last part of block (3) deals with the initialization of 
feature-negotiation state.


List of patches in this set:
----------------------------
Patch #1: Integration of dynamic negotiation, part I (socket setup).
Patch #2: Integration of dynamic negotiation, part II (server side).
Patch #3: Integration of dynamic negotiation, part III (client side).
Patch #4: Cleans up the older infrastructure.
Patch #5: Removes obsolete parts of the old CCID interface.
Patch #6: Removes manual intervention on NDP count (now automatic).
Patch #7: Removes Ack Vector sysctl (handled automatically now).

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?pÜcp_exp.git;a=commitdiff;hÄ7390a8b5faaec4a41337714b2d80c85fc6ba26


Patch stats:
------------
 Documentation/networking/dccp.txt |   11 
 include/linux/dccp.h              |   10 
 net/dccp/ccid.c                   |   14 -
 net/dccp/ccid.h                   |    5 
 net/dccp/dccp.h                   |    4 
 net/dccp/diag.c                   |    2 
 net/dccp/feat.c                   |  519 --------------------------------------
 net/dccp/feat.h                   |   12 
 net/dccp/input.c                  |   42 ++-
 net/dccp/minisocks.c              |   46 ---
 net/dccp/options.c                |   11 
 net/dccp/proto.c                  |   49 ---
 net/dccp/sysctl.c                 |   14 -
 13 files changed, 70 insertions(+), 669 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/7] dccp: Integration of dynamic feature activation - part 1 (socket setup)
@ 2008-12-06 16:40                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This first patch out of three replaces the hardcoded default settings with
initialisation code for the dynamic feature negotiation.

The patch also ensures that the client feature-negotiation queue is flushed
only when entering the OPEN state.

Since confirmed Change options are removed as soon as they are confirmed
(in the DCCP-Response), this ensures that Confirm options are retransmitted.

Note on retransmitting Confirm options:
---------------------------------------
Implementation experience showed that it is necessary to retransmit Confirm
options. Thanks to Leandro Melo de Sales who reported a bug in an earlier
revision of the patch set, resulting from not retransmitting these options.

As long as the client is in PARTOPEN, it needs to retransmit the Confirm
options for the Change options received on the DCCP-Response from the server.

Otherwise, if the packet containing the Confirm options gets dropped in the
network, the connection aborts due to undefined feature negotiation state.


Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/proto.c |   46 ++++++----------------------------------------
 1 files changed, 6 insertions(+), 40 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -67,6 +67,9 @@ void dccp_set_state(struct sock *sk, const int state)
 	case DCCP_OPEN:
 		if (oldstate != DCCP_OPEN)
 			DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+		/* Client retransmits all Confirm options until entering OPEN */
+		if (oldstate == DCCP_PARTOPEN)
+			dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
 		break;
 
 	case DCCP_CLOSED:
@@ -175,7 +178,6 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
 int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	dccp_minisock_init(&dp->dccps_minisock);
@@ -194,45 +196,9 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	dccp_init_xmit_timers(sk);
 
 	INIT_LIST_HEAD(&dp->dccps_featneg);
-	/*
-	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
-	 * the listening (master) sock get CCID control blocks, which is not
-	 * necessary, but for now, to not mess with the test userspace apps,
-	 * lets leave it here, later the real solution is to do this in a
-	 * setsockopt(CCIDs-I-want/accept). -acme
-	 */
-	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(sk);
-
-		if (rc)
-			return rc;
-
-		if (dmsk->dccpms_send_ack_vector) {
-			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
-			if (dp->dccps_hc_rx_ackvec == NULL)
-				return -ENOMEM;
-		}
-		dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
-						      sk, GFP_KERNEL);
-		dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
-						      sk, GFP_KERNEL);
-		if (unlikely(dp->dccps_hc_rx_ccid == NULL ||
-			     dp->dccps_hc_tx_ccid == NULL)) {
-			ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-			ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-			if (dmsk->dccpms_send_ack_vector) {
-				dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-				dp->dccps_hc_rx_ackvec = NULL;
-			}
-			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		/* control socket doesn't need feat nego */
-		INIT_LIST_HEAD(&dmsk->dccpms_pending);
-		INIT_LIST_HEAD(&dmsk->dccpms_conf);
-	}
-
+	/* control socket doesn't need feat nego */
+	if (likely(ctl_sock_initialized))
+		return dccp_feat_init(sk);
 	return 0;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/7] dccp: Integration of dynamic feature activation - part 1 (socket setup)
@ 2008-12-06 16:40                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

This first patch out of three replaces the hardcoded default settings with
initialisation code for the dynamic feature negotiation.

The patch also ensures that the client feature-negotiation queue is flushed
only when entering the OPEN state.

Since confirmed Change options are removed as soon as they are confirmed
(in the DCCP-Response), this ensures that Confirm options are retransmitted.

Note on retransmitting Confirm options:
---------------------------------------
Implementation experience showed that it is necessary to retransmit Confirm
options. Thanks to Leandro Melo de Sales who reported a bug in an earlier
revision of the patch set, resulting from not retransmitting these options.

As long as the client is in PARTOPEN, it needs to retransmit the Confirm
options for the Change options received on the DCCP-Response from the server.

Otherwise, if the packet containing the Confirm options gets dropped in the
network, the connection aborts due to undefined feature negotiation state.


Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/proto.c |   46 ++++++----------------------------------------
 1 files changed, 6 insertions(+), 40 deletions(-)

--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -67,6 +67,9 @@ void dccp_set_state(struct sock *sk, const int state)
 	case DCCP_OPEN:
 		if (oldstate != DCCP_OPEN)
 			DCCP_INC_STATS(DCCP_MIB_CURRESTAB);
+		/* Client retransmits all Confirm options until entering OPEN */
+		if (oldstate = DCCP_PARTOPEN)
+			dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg);
 		break;
 
 	case DCCP_CLOSED:
@@ -175,7 +178,6 @@ EXPORT_SYMBOL_GPL(dccp_state_name);
 int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
 	dccp_minisock_init(&dp->dccps_minisock);
@@ -194,45 +196,9 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	dccp_init_xmit_timers(sk);
 
 	INIT_LIST_HEAD(&dp->dccps_featneg);
-	/*
-	 * FIXME: We're hardcoding the CCID, and doing this at this point makes
-	 * the listening (master) sock get CCID control blocks, which is not
-	 * necessary, but for now, to not mess with the test userspace apps,
-	 * lets leave it here, later the real solution is to do this in a
-	 * setsockopt(CCIDs-I-want/accept). -acme
-	 */
-	if (likely(ctl_sock_initialized)) {
-		int rc = dccp_feat_init(sk);
-
-		if (rc)
-			return rc;
-
-		if (dmsk->dccpms_send_ack_vector) {
-			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
-			if (dp->dccps_hc_rx_ackvec = NULL)
-				return -ENOMEM;
-		}
-		dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid,
-						      sk, GFP_KERNEL);
-		dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid,
-						      sk, GFP_KERNEL);
-		if (unlikely(dp->dccps_hc_rx_ccid = NULL ||
-			     dp->dccps_hc_tx_ccid = NULL)) {
-			ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-			ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-			if (dmsk->dccpms_send_ack_vector) {
-				dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
-				dp->dccps_hc_rx_ackvec = NULL;
-			}
-			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
-			return -ENOMEM;
-		}
-	} else {
-		/* control socket doesn't need feat nego */
-		INIT_LIST_HEAD(&dmsk->dccpms_pending);
-		INIT_LIST_HEAD(&dmsk->dccpms_conf);
-	}
-
+	/* control socket doesn't need feat nego */
+	if (likely(ctl_sock_initialized))
+		return dccp_feat_init(sk);
 	return 0;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/7] dccp: Integration of dynamic feature activation - part 2 (server side)
@ 2008-12-06 16:40                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch integrates the activation of features at the end of negotiation
into the server-side code.

Note regarding the removal of 'const':
--------------------------------------
 The 'const' attribute has been removed from 'dreq' since dccp_activate_values()
 needs to operate on dreq's feature list. Part of the activation is to remove
 those options from the list that have already been confirmed, hence it is not
 purely read-only.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/minisocks.c |   42 ++++++++++++------------------------------
 1 files changed, 12 insertions(+), 30 deletions(-)

--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -111,7 +111,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 	struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
 	if (newsk != NULL) {
-		const struct dccp_request_sock *dreq = dccp_rsk(req);
+		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
 		struct dccp_minisock *newdmsk = dccp_msk(newsk);
@@ -125,35 +125,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
 		INIT_LIST_HEAD(&newdp->dccps_featneg);
-		if (dccp_feat_clone(sk, newsk))
-			goto out_free;
-
-		if (newdmsk->dccpms_send_ack_vector) {
-			newdp->dccps_hc_rx_ackvec =
-						dccp_ackvec_alloc(GFP_ATOMIC);
-			if (unlikely(newdp->dccps_hc_rx_ackvec == NULL))
-				goto out_free;
-		}
-
-		newdp->dccps_hc_rx_ccid =
-			    ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
-					   newsk, GFP_ATOMIC);
-		newdp->dccps_hc_tx_ccid =
-			    ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
-					   newsk, GFP_ATOMIC);
-		if (unlikely(newdp->dccps_hc_rx_ccid == NULL ||
-			     newdp->dccps_hc_tx_ccid == NULL)) {
-			dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-			ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
-			ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
-out_free:
-			/* It is still raw copy of parent, so invalidate
-			 * destructor and make plain sk_free() */
-			newsk->sk_destruct = NULL;
-			sk_free(newsk);
-			return NULL;
-		}
-
 		/*
 		 * Step 3: Process LISTEN state
 		 *
@@ -184,6 +155,17 @@ out_free:
 		dccp_set_seqno(&newdp->dccps_awl,
 			       max48(newdp->dccps_awl, newdp->dccps_iss));
 
+		/*
+		 * Activate features after initialising the sequence numbers,
+		 * since CCID initialisation may depend on GSS, ISR, ISS etc.
+		 */
+		if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
+			/* It is still raw copy of parent, so invalidate
+			 * destructor and make plain sk_free() */
+			newsk->sk_destruct = NULL;
+			sk_free(newsk);
+			return NULL;
+		}
 		dccp_init_xmit_timers(newsk);
 
 		DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/7] dccp: Integration of dynamic feature activation - part 2 (server side)
@ 2008-12-06 16:40                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

This patch integrates the activation of features at the end of negotiation
into the server-side code.

Note regarding the removal of 'const':
--------------------------------------
 The 'const' attribute has been removed from 'dreq' since dccp_activate_values()
 needs to operate on dreq's feature list. Part of the activation is to remove
 those options from the list that have already been confirmed, hence it is not
 purely read-only.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/minisocks.c |   42 ++++++++++++------------------------------
 1 files changed, 12 insertions(+), 30 deletions(-)

--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -111,7 +111,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 	struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC);
 
 	if (newsk != NULL) {
-		const struct dccp_request_sock *dreq = dccp_rsk(req);
+		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
 		struct dccp_minisock *newdmsk = dccp_msk(newsk);
@@ -125,35 +125,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		newicsk->icsk_rto	    = DCCP_TIMEOUT_INIT;
 
 		INIT_LIST_HEAD(&newdp->dccps_featneg);
-		if (dccp_feat_clone(sk, newsk))
-			goto out_free;
-
-		if (newdmsk->dccpms_send_ack_vector) {
-			newdp->dccps_hc_rx_ackvec -						dccp_ackvec_alloc(GFP_ATOMIC);
-			if (unlikely(newdp->dccps_hc_rx_ackvec = NULL))
-				goto out_free;
-		}
-
-		newdp->dccps_hc_rx_ccid -			    ccid_hc_rx_new(newdmsk->dccpms_rx_ccid,
-					   newsk, GFP_ATOMIC);
-		newdp->dccps_hc_tx_ccid -			    ccid_hc_tx_new(newdmsk->dccpms_tx_ccid,
-					   newsk, GFP_ATOMIC);
-		if (unlikely(newdp->dccps_hc_rx_ccid = NULL ||
-			     newdp->dccps_hc_tx_ccid = NULL)) {
-			dccp_ackvec_free(newdp->dccps_hc_rx_ackvec);
-			ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk);
-			ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk);
-out_free:
-			/* It is still raw copy of parent, so invalidate
-			 * destructor and make plain sk_free() */
-			newsk->sk_destruct = NULL;
-			sk_free(newsk);
-			return NULL;
-		}
-
 		/*
 		 * Step 3: Process LISTEN state
 		 *
@@ -184,6 +155,17 @@ out_free:
 		dccp_set_seqno(&newdp->dccps_awl,
 			       max48(newdp->dccps_awl, newdp->dccps_iss));
 
+		/*
+		 * Activate features after initialising the sequence numbers,
+		 * since CCID initialisation may depend on GSS, ISR, ISS etc.
+		 */
+		if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) {
+			/* It is still raw copy of parent, so invalidate
+			 * destructor and make plain sk_free() */
+			newsk->sk_destruct = NULL;
+			sk_free(newsk);
+			return NULL;
+		}
 		dccp_init_xmit_timers(newsk);
 
 		DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/7] dccp: Integration of dynamic feature activation - part 3 (client side)
@ 2008-12-06 16:40                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This integrates feature-activation in the client:

 1. When dccp_parse_options() fails, the reset code is already set; request_sent\
    _state_process() currently overrides this with `Packet Error', which is not
    intended - changed to use the reset code supplied by dccp_parse_options().

 2. When feature negotiation fails, the socket should be marked as not usable,
    so that the application is notified that an error occurred. This is achieved
    by a new label 'unable_to_proceed': generating an error code of `Aborted',
    setting the socket state to CLOSED, returning with ECOMM in sk_err.

 3. Avoids parsing the Ack twice in Respond state by not doing option processing
    again in dccp_rcv_respond_partopen_state_process (as option processing has
    already been done on the request_sock in dccp_check_req).

Since this addresses congestion-control initialisation, a corresponding
FIXME has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/input.c |   30 ++++++++++++++++++++++++++----
 1 files changed, 26 insertions(+), 4 deletions(-)

--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -421,8 +421,13 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			goto out_invalid_packet;
 		}
 
+		/*
+		 * If option processing (Step 8) failed, return 1 here so that
+		 * dccp_v4_do_rcv() sends a Reset. The Reset code depends on
+		 * the option type and is set in dccp_parse_options().
+		 */
 		if (dccp_parse_options(sk, NULL, skb))
-			goto out_invalid_packet;
+			return 1;
 
 		/* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
 		if (likely(dp->dccps_options_received.dccpor_timestamp_echo))
@@ -475,6 +480,15 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 		 */
 		dccp_set_state(sk, DCCP_PARTOPEN);
 
+		/*
+		 * If feature negotiation was successful, activate features now;
+		 * an activation failure means that this host could not activate
+		 * one ore more features (e.g. insufficient memory), which would
+		 * leave at least one feature in an undefined state.
+		 */
+		if (dccp_feat_activate_values(sk, &dp->dccps_featneg))
+			goto unable_to_proceed;
+
 		/* Make sure socket is routed, for correct metrics. */
 		icsk->icsk_af_ops->rebuild_header(sk);
 
@@ -509,6 +523,16 @@ out_invalid_packet:
 	/* dccp_v4_do_rcv will send a reset */
 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
 	return 1;
+
+unable_to_proceed:
+	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_ABORTED;
+	/*
+	 * We mark this socket as no longer usable, so that the loop in
+	 * dccp_sendmsg() terminates and the application gets notified.
+	 */
+	dccp_set_state(sk, DCCP_CLOSED);
+	sk->sk_err = ECOMM;
+	return 1;
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -600,7 +624,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 	}
 
-	if (sk->sk_state != DCCP_REQUESTING) {
+	if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
 		if (dccp_check_seqno(sk, skb))
 			goto discard;
 
@@ -665,8 +689,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 
 	case DCCP_REQUESTING:
-		/* FIXME: do congestion control initialization */
-
 		queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
 		if (queued >= 0)
 			return queued;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/7] dccp: Integration of dynamic feature activation - part 3 (client side)
@ 2008-12-06 16:40                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

This integrates feature-activation in the client:

 1. When dccp_parse_options() fails, the reset code is already set; request_sent\
    _state_process() currently overrides this with `Packet Error', which is not
    intended - changed to use the reset code supplied by dccp_parse_options().

 2. When feature negotiation fails, the socket should be marked as not usable,
    so that the application is notified that an error occurred. This is achieved
    by a new label 'unable_to_proceed': generating an error code of `Aborted',
    setting the socket state to CLOSED, returning with ECOMM in sk_err.

 3. Avoids parsing the Ack twice in Respond state by not doing option processing
    again in dccp_rcv_respond_partopen_state_process (as option processing has
    already been done on the request_sock in dccp_check_req).

Since this addresses congestion-control initialisation, a corresponding
FIXME has been removed.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/input.c |   30 ++++++++++++++++++++++++++----
 1 files changed, 26 insertions(+), 4 deletions(-)

--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -421,8 +421,13 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			goto out_invalid_packet;
 		}
 
+		/*
+		 * If option processing (Step 8) failed, return 1 here so that
+		 * dccp_v4_do_rcv() sends a Reset. The Reset code depends on
+		 * the option type and is set in dccp_parse_options().
+		 */
 		if (dccp_parse_options(sk, NULL, skb))
-			goto out_invalid_packet;
+			return 1;
 
 		/* Obtain usec RTT sample from SYN exchange (used by CCID 3) */
 		if (likely(dp->dccps_options_received.dccpor_timestamp_echo))
@@ -475,6 +480,15 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 		 */
 		dccp_set_state(sk, DCCP_PARTOPEN);
 
+		/*
+		 * If feature negotiation was successful, activate features now;
+		 * an activation failure means that this host could not activate
+		 * one ore more features (e.g. insufficient memory), which would
+		 * leave at least one feature in an undefined state.
+		 */
+		if (dccp_feat_activate_values(sk, &dp->dccps_featneg))
+			goto unable_to_proceed;
+
 		/* Make sure socket is routed, for correct metrics. */
 		icsk->icsk_af_ops->rebuild_header(sk);
 
@@ -509,6 +523,16 @@ out_invalid_packet:
 	/* dccp_v4_do_rcv will send a reset */
 	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR;
 	return 1;
+
+unable_to_proceed:
+	DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_ABORTED;
+	/*
+	 * We mark this socket as no longer usable, so that the loop in
+	 * dccp_sendmsg() terminates and the application gets notified.
+	 */
+	dccp_set_state(sk, DCCP_CLOSED);
+	sk->sk_err = ECOMM;
+	return 1;
 }
 
 static int dccp_rcv_respond_partopen_state_process(struct sock *sk,
@@ -600,7 +624,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 	}
 
-	if (sk->sk_state != DCCP_REQUESTING) {
+	if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) {
 		if (dccp_check_seqno(sk, skb))
 			goto discard;
 
@@ -665,8 +689,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		return 1;
 
 	case DCCP_REQUESTING:
-		/* FIXME: do congestion control initialization */
-
 		queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len);
 		if (queued >= 0)
 			return queued;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/7] dccp: Clean up old feature-negotiation infrastructure
@ 2008-12-06 16:40                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

The code removed by this patch is no longer referenced or used, the added
lines update documentation and copyrights.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h |   12 +-
 net/dccp/feat.c |  504 +------------------------------------------------------
 2 files changed, 11 insertions(+), 505 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -3,14 +3,14 @@
 /*
  *  net/dccp/feat.h
  *
- *  An implementation of the DCCP protocol
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
  *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
  *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License version 2 as
- *	published by the Free Software Foundation.
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
  */
-
 #include <linux/types.h>
 #include "dccp.h"
 
@@ -118,8 +118,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern void dccp_feat_clean(struct dccp_minisock *dmsk);
-extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1,8 +1,12 @@
 /*
  *  net/dccp/feat.c
  *
- *  An implementation of the DCCP protocol
- *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ *  Rewrote from scratch, some bits from earlier code by
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
  *
  *  ASSUMPTIONS
  *  -----------
@@ -17,14 +21,10 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-
 #include <linux/module.h>
-
 #include "ccid.h"
 #include "feat.h"
 
-#define DCCP_FEAT_SP_NOAGREE (-123)
-
 /*
  * Feature activation handlers.
  *
@@ -811,51 +811,6 @@ int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
 	return 0;
 }
 
-static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* figure out if we are changing our CCID or the peer's */
-	const int rx = type == DCCPO_CHANGE_R;
-	const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
-	struct ccid *new_ccid;
-
-	/* Check if nothing is being changed. */
-	if (ccid_nr == new_ccid_nr)
-		return 0;
-
-	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
-	if (new_ccid == NULL)
-		return -ENOMEM;
-
-	if (rx) {
-		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-		dp->dccps_hc_rx_ccid = new_ccid;
-		dmsk->dccpms_rx_ccid = new_ccid_nr;
-	} else {
-		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-		dp->dccps_hc_tx_ccid = new_ccid;
-		dmsk->dccpms_tx_ccid = new_ccid_nr;
-	}
-
-	return 0;
-}
-
-static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
-{
-	dccp_feat_debug(type, feat, val);
-
-	switch (feat) {
-	case DCCPF_CCID:
-		return dccp_feat_update_ccid(sk, type, val);
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n",
-			      dccp_feat_typename(type), feat);
-		break;
-	}
-	return 0;
-}
-
 /* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
 static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
 {
@@ -925,453 +880,6 @@ static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
 	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
 }
 
-#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
-static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
-			       u8 *rpref, u8 rlen)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	u8 *spref, slen, *res = NULL;
-	int i, j, rc, agree = 1;
-
-	BUG_ON(rpref == NULL);
-
-	/* check if we are the black sheep */
-	if (dp->dccps_role == DCCP_ROLE_CLIENT) {
-		spref = rpref;
-		slen  = rlen;
-		rpref = opt->dccpop_val;
-		rlen  = opt->dccpop_len;
-	} else {
-		spref = opt->dccpop_val;
-		slen  = opt->dccpop_len;
-	}
-	/*
-	 * Now we have server preference list in spref and client preference in
-	 * rpref
-	 */
-	BUG_ON(spref == NULL);
-	BUG_ON(rpref == NULL);
-
-	/* FIXME sanity check vals */
-
-	/* Are values in any order?  XXX Lame "algorithm" here */
-	for (i = 0; i < slen; i++) {
-		for (j = 0; j < rlen; j++) {
-			if (spref[i] == rpref[j]) {
-				res = &spref[i];
-				break;
-			}
-		}
-		if (res)
-			break;
-	}
-
-	/* we didn't agree on anything */
-	if (res == NULL) {
-		/* confirm previous value */
-		switch (opt->dccpop_feat) {
-		case DCCPF_CCID:
-			/* XXX did i get this right? =P */
-			if (opt->dccpop_type == DCCPO_CHANGE_L)
-				res = &dccp_msk(sk)->dccpms_tx_ccid;
-			else
-				res = &dccp_msk(sk)->dccpms_rx_ccid;
-			break;
-
-		default:
-			DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat);
-			/* XXX implement res */
-			return -EFAULT;
-		}
-
-		dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
-		agree = 0; /* this is used for mandatory options... */
-	}
-
-	/* need to put result and our preference list */
-	rlen = 1 + opt->dccpop_len;
-	rpref = kmalloc(rlen, GFP_ATOMIC);
-	if (rpref == NULL)
-		return -ENOMEM;
-
-	*rpref = *res;
-	memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
-
-	/* put it in the "confirm queue" */
-	if (opt->dccpop_sc == NULL) {
-		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
-		if (opt->dccpop_sc == NULL) {
-			kfree(rpref);
-			return -ENOMEM;
-		}
-	} else {
-		/* recycle the confirm slot */
-		BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
-		kfree(opt->dccpop_sc->dccpoc_val);
-		dccp_pr_debug("recycling confirm slot\n");
-	}
-	memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
-
-	opt->dccpop_sc->dccpoc_val = rpref;
-	opt->dccpop_sc->dccpoc_len = rlen;
-
-	/* update the option on our side [we are about to send the confirm] */
-	rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
-	if (rc) {
-		kfree(opt->dccpop_sc->dccpoc_val);
-		kfree(opt->dccpop_sc);
-		opt->dccpop_sc = NULL;
-		return rc;
-	}
-
-	dccp_pr_debug("Will confirm %d\n", *rpref);
-
-	/* say we want to change to X but we just got a confirm X, suppress our
-	 * change
-	 */
-	if (!opt->dccpop_conf) {
-		if (*opt->dccpop_val == *res)
-			opt->dccpop_conf = 1;
-		dccp_pr_debug("won't ask for change of same feature\n");
-	}
-
-	return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
-}
-
-static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt;
-	int rc = 1;
-	u8 t;
-
-	/*
-	 * We received a CHANGE.  We gotta match it against our own preference
-	 * list.  If we got a CHANGE_R it means it's a change for us, so we need
-	 * to compare our CHANGE_L list.
-	 */
-	if (type == DCCPO_CHANGE_L)
-		t = DCCPO_CHANGE_R;
-	else
-		t = DCCPO_CHANGE_L;
-
-	/* find our preference list for this feature */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (opt->dccpop_type != t || opt->dccpop_feat != feature)
-			continue;
-
-		/* find the winner from the two preference lists */
-		rc = dccp_feat_reconcile(sk, opt, val, len);
-		break;
-	}
-
-	/* We didn't deal with the change.  This can happen if we have no
-	 * preference list for the feature.  In fact, it just shouldn't
-	 * happen---if we understand a feature, we should have a preference list
-	 * with at least the default value.
-	 */
-	BUG_ON(rc == 1);
-
-	return rc;
-}
-
-static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	u8 *copy;
-	int rc;
-
-	/* NN features must be Change L (sec. 6.3.2) */
-	if (type != DCCPO_CHANGE_L) {
-		dccp_pr_debug("received %s for NN feature %d\n",
-				dccp_feat_typename(type), feature);
-		return -EFAULT;
-	}
-
-	/* XXX sanity check opt val */
-
-	/* copy option so we can confirm it */
-	opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-	if (opt == NULL)
-		return -ENOMEM;
-
-	copy = kmemdup(val, len, GFP_ATOMIC);
-	if (copy == NULL) {
-		kfree(opt);
-		return -ENOMEM;
-	}
-
-	opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = copy;
-	opt->dccpop_len	 = len;
-
-	/* change feature */
-	rc = dccp_feat_update(sk, type, feature, *val);
-	if (rc) {
-		kfree(opt->dccpop_val);
-		kfree(opt);
-		return rc;
-	}
-
-	dccp_feat_debug(type, feature, *copy);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-
-	return 0;
-}
-
-static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
-				    u8 type, u8 feature)
-{
-	/* XXX check if other confirms for that are queued and recycle slot */
-	struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-
-	if (opt == NULL) {
-		/* XXX what do we do?  Ignoring should be fine.  It's a change
-		 * after all =P
-		 */
-		return;
-	}
-
-	switch (type) {
-	case DCCPO_CHANGE_L:
-		opt->dccpop_type = DCCPO_CONFIRM_R;
-		break;
-	case DCCPO_CHANGE_R:
-		opt->dccpop_type = DCCPO_CONFIRM_L;
-		break;
-	default:
-		DCCP_WARN("invalid type %d\n", type);
-		kfree(opt);
-		return;
-	}
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = NULL;
-	opt->dccpop_len	 = 0;
-
-	/* change feature */
-	dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-}
-
-static void dccp_feat_flush_confirm(struct sock *sk)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* Check if there is anything to confirm in the first place */
-	int yes = !list_empty(&dmsk->dccpms_conf);
-
-	if (!yes) {
-		struct dccp_opt_pend *opt;
-
-		list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-			if (opt->dccpop_conf) {
-				yes = 1;
-				break;
-			}
-		}
-	}
-
-	if (!yes)
-		return;
-
-	/* OK there is something to confirm... */
-	/* XXX check if packet is in flight?  Send delayed ack?? */
-	if (sk->sk_state == DCCP_OPEN)
-		dccp_send_ack(sk);
-}
-
-int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	int rc;
-
-	/* Ignore Change requests other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* figure out if it's SP or NN feature */
-	switch (feature) {
-	/* deal with SP features */
-	case DCCPF_CCID:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_sp(sk, type, feature, val, len); */
-		break;
-
-	/* deal with NN features */
-	case DCCPF_ACK_RATIO:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_nn(sk, type, feature, val, len); */
-		break;
-
-	/* XXX implement other features */
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n",
-			      dccp_feat_typename(type), feature);
-		rc = -EFAULT;
-		break;
-	}
-
-	/* check if there were problems changing features */
-	if (rc) {
-		/* If we don't agree on SP, we sent a confirm for old value.
-		 * However we propagate rc to caller in case option was
-		 * mandatory
-		 */
-		if (rc != DCCP_FEAT_SP_NOAGREE)
-			dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
-	}
-
-	/* generate the confirm [if required] */
-	dccp_feat_flush_confirm(sk);
-
-	return rc;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-
-int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-			   u8 *val, u8 len)
-{
-	u8 t;
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	int found = 0;
-	int all_confirmed = 1;
-
-	/* Ignore Confirm options other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* locate our change request */
-	switch (type) {
-	case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
-	case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
-	default:	      DCCP_WARN("invalid type %d\n", type);
-			      return 1;
-
-	}
-	/* XXX sanity check feature value */
-
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (!opt->dccpop_conf && opt->dccpop_type == t &&
-		    opt->dccpop_feat == feature) {
-			found = 1;
-			dccp_pr_debug("feature %d found\n", opt->dccpop_feat);
-
-			/* XXX do sanity check */
-
-			opt->dccpop_conf = 1;
-
-			/* We got a confirmation---change the option */
-			dccp_feat_update(sk, opt->dccpop_type,
-					 opt->dccpop_feat, *val);
-
-			/* XXX check the return value of dccp_feat_update */
-			break;
-		}
-
-		if (!opt->dccpop_conf)
-			all_confirmed = 0;
-	}
-
-	if (!found)
-		dccp_pr_debug("%s(%d, ...) never requested\n",
-			      dccp_feat_typename(type), feature);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
-#endif	/* (later) */
-
-void dccp_feat_clean(struct dccp_minisock *dmsk)
-{
-	struct dccp_opt_pend *opt, *next;
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
-				 dccpop_node) {
-		BUG_ON(opt->dccpop_val == NULL);
-		kfree(opt->dccpop_val);
-
-		if (opt->dccpop_sc != NULL) {
-			BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-		}
-
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		BUG_ON(opt == NULL);
-		if (opt->dccpop_val != NULL)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clean);
-
-/* this is to be called only when a listening sock creates its child.  It is
- * assumed by the function---the confirm is not duplicated, but rather it is
- * "passed on".
- */
-int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
-{
-	struct dccp_minisock *olddmsk = dccp_msk(oldsk);
-	struct dccp_minisock *newdmsk = dccp_msk(newsk);
-	struct dccp_opt_pend *opt;
-	int rc = 0;
-
-	INIT_LIST_HEAD(&newdmsk->dccpms_pending);
-	INIT_LIST_HEAD(&newdmsk->dccpms_conf);
-
-	list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
-		struct dccp_opt_pend *newopt;
-		/* copy the value of the option */
-		u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC);
-
-		if (val == NULL)
-			goto out_clean;
-
-		newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC);
-		if (newopt == NULL) {
-			kfree(val);
-			goto out_clean;
-		}
-
-		/* insert the option */
-		newopt->dccpop_val = val;
-		list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
-
-		/* XXX what happens with backlogs and multiple connections at
-		 * once...
-		 */
-		/* the master socket no longer needs to worry about confirms */
-		opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
-
-		/* reset state for a new socket */
-		opt->dccpop_conf = 0;
-	}
-
-	/* XXX not doing anything about the conf queue */
-
-out:
-	return rc;
-
-out_clean:
-	dccp_feat_clean(newdmsk);
-	rc = -ENOMEM;
-	goto out;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clone);
-
 /**
  * dccp_feat_change_recv  -  Process incoming ChangeL/R options
  * @fn: feature-negotiation list to update

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/7] dccp: Clean up old feature-negotiation infrastructure
@ 2008-12-06 16:40                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

The code removed by this patch is no longer referenced or used, the added
lines update documentation and copyrights.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/feat.h |   12 +-
 net/dccp/feat.c |  504 +------------------------------------------------------
 2 files changed, 11 insertions(+), 505 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -3,14 +3,14 @@
 /*
  *  net/dccp/feat.h
  *
- *  An implementation of the DCCP protocol
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
  *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
  *
- *	This program is free software; you can redistribute it and/or modify it
- *	under the terms of the GNU General Public License version 2 as
- *	published by the Free Software Foundation.
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
  */
-
 #include <linux/types.h>
 #include "dccp.h"
 
@@ -118,8 +118,6 @@ extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
-extern void dccp_feat_clean(struct dccp_minisock *dmsk);
-extern int  dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
 extern int  dccp_feat_init(struct sock *sk);
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1,8 +1,12 @@
 /*
  *  net/dccp/feat.c
  *
- *  An implementation of the DCCP protocol
- *  Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *  Feature negotiation for the DCCP protocol (RFC 4340, section 6)
+ *
+ *  Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
+ *  Rewrote from scratch, some bits from earlier code by
+ *  Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
+ *
  *
  *  ASSUMPTIONS
  *  -----------
@@ -17,14 +21,10 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  */
-
 #include <linux/module.h>
-
 #include "ccid.h"
 #include "feat.h"
 
-#define DCCP_FEAT_SP_NOAGREE (-123)
-
 /*
  * Feature activation handlers.
  *
@@ -811,51 +811,6 @@ int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
 	return 0;
 }
 
-static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* figure out if we are changing our CCID or the peer's */
-	const int rx = type = DCCPO_CHANGE_R;
-	const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
-	struct ccid *new_ccid;
-
-	/* Check if nothing is being changed. */
-	if (ccid_nr = new_ccid_nr)
-		return 0;
-
-	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
-	if (new_ccid = NULL)
-		return -ENOMEM;
-
-	if (rx) {
-		ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
-		dp->dccps_hc_rx_ccid = new_ccid;
-		dmsk->dccpms_rx_ccid = new_ccid_nr;
-	} else {
-		ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
-		dp->dccps_hc_tx_ccid = new_ccid;
-		dmsk->dccpms_tx_ccid = new_ccid_nr;
-	}
-
-	return 0;
-}
-
-static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
-{
-	dccp_feat_debug(type, feat, val);
-
-	switch (feat) {
-	case DCCPF_CCID:
-		return dccp_feat_update_ccid(sk, type, val);
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n",
-			      dccp_feat_typename(type), feat);
-		break;
-	}
-	return 0;
-}
-
 /* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
 static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
 {
@@ -925,453 +880,6 @@ static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
 	return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
 }
 
-#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
-static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
-			       u8 *rpref, u8 rlen)
-{
-	struct dccp_sock *dp = dccp_sk(sk);
-	u8 *spref, slen, *res = NULL;
-	int i, j, rc, agree = 1;
-
-	BUG_ON(rpref = NULL);
-
-	/* check if we are the black sheep */
-	if (dp->dccps_role = DCCP_ROLE_CLIENT) {
-		spref = rpref;
-		slen  = rlen;
-		rpref = opt->dccpop_val;
-		rlen  = opt->dccpop_len;
-	} else {
-		spref = opt->dccpop_val;
-		slen  = opt->dccpop_len;
-	}
-	/*
-	 * Now we have server preference list in spref and client preference in
-	 * rpref
-	 */
-	BUG_ON(spref = NULL);
-	BUG_ON(rpref = NULL);
-
-	/* FIXME sanity check vals */
-
-	/* Are values in any order?  XXX Lame "algorithm" here */
-	for (i = 0; i < slen; i++) {
-		for (j = 0; j < rlen; j++) {
-			if (spref[i] = rpref[j]) {
-				res = &spref[i];
-				break;
-			}
-		}
-		if (res)
-			break;
-	}
-
-	/* we didn't agree on anything */
-	if (res = NULL) {
-		/* confirm previous value */
-		switch (opt->dccpop_feat) {
-		case DCCPF_CCID:
-			/* XXX did i get this right? =P */
-			if (opt->dccpop_type = DCCPO_CHANGE_L)
-				res = &dccp_msk(sk)->dccpms_tx_ccid;
-			else
-				res = &dccp_msk(sk)->dccpms_rx_ccid;
-			break;
-
-		default:
-			DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat);
-			/* XXX implement res */
-			return -EFAULT;
-		}
-
-		dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
-		agree = 0; /* this is used for mandatory options... */
-	}
-
-	/* need to put result and our preference list */
-	rlen = 1 + opt->dccpop_len;
-	rpref = kmalloc(rlen, GFP_ATOMIC);
-	if (rpref = NULL)
-		return -ENOMEM;
-
-	*rpref = *res;
-	memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
-
-	/* put it in the "confirm queue" */
-	if (opt->dccpop_sc = NULL) {
-		opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
-		if (opt->dccpop_sc = NULL) {
-			kfree(rpref);
-			return -ENOMEM;
-		}
-	} else {
-		/* recycle the confirm slot */
-		BUG_ON(opt->dccpop_sc->dccpoc_val = NULL);
-		kfree(opt->dccpop_sc->dccpoc_val);
-		dccp_pr_debug("recycling confirm slot\n");
-	}
-	memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
-
-	opt->dccpop_sc->dccpoc_val = rpref;
-	opt->dccpop_sc->dccpoc_len = rlen;
-
-	/* update the option on our side [we are about to send the confirm] */
-	rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
-	if (rc) {
-		kfree(opt->dccpop_sc->dccpoc_val);
-		kfree(opt->dccpop_sc);
-		opt->dccpop_sc = NULL;
-		return rc;
-	}
-
-	dccp_pr_debug("Will confirm %d\n", *rpref);
-
-	/* say we want to change to X but we just got a confirm X, suppress our
-	 * change
-	 */
-	if (!opt->dccpop_conf) {
-		if (*opt->dccpop_val = *res)
-			opt->dccpop_conf = 1;
-		dccp_pr_debug("won't ask for change of same feature\n");
-	}
-
-	return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
-}
-
-static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	struct dccp_opt_pend *opt;
-	int rc = 1;
-	u8 t;
-
-	/*
-	 * We received a CHANGE.  We gotta match it against our own preference
-	 * list.  If we got a CHANGE_R it means it's a change for us, so we need
-	 * to compare our CHANGE_L list.
-	 */
-	if (type = DCCPO_CHANGE_L)
-		t = DCCPO_CHANGE_R;
-	else
-		t = DCCPO_CHANGE_L;
-
-	/* find our preference list for this feature */
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (opt->dccpop_type != t || opt->dccpop_feat != feature)
-			continue;
-
-		/* find the winner from the two preference lists */
-		rc = dccp_feat_reconcile(sk, opt, val, len);
-		break;
-	}
-
-	/* We didn't deal with the change.  This can happen if we have no
-	 * preference list for the feature.  In fact, it just shouldn't
-	 * happen---if we understand a feature, we should have a preference list
-	 * with at least the default value.
-	 */
-	BUG_ON(rc = 1);
-
-	return rc;
-}
-
-static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	u8 *copy;
-	int rc;
-
-	/* NN features must be Change L (sec. 6.3.2) */
-	if (type != DCCPO_CHANGE_L) {
-		dccp_pr_debug("received %s for NN feature %d\n",
-				dccp_feat_typename(type), feature);
-		return -EFAULT;
-	}
-
-	/* XXX sanity check opt val */
-
-	/* copy option so we can confirm it */
-	opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-	if (opt = NULL)
-		return -ENOMEM;
-
-	copy = kmemdup(val, len, GFP_ATOMIC);
-	if (copy = NULL) {
-		kfree(opt);
-		return -ENOMEM;
-	}
-
-	opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = copy;
-	opt->dccpop_len	 = len;
-
-	/* change feature */
-	rc = dccp_feat_update(sk, type, feature, *val);
-	if (rc) {
-		kfree(opt->dccpop_val);
-		kfree(opt);
-		return rc;
-	}
-
-	dccp_feat_debug(type, feature, *copy);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-
-	return 0;
-}
-
-static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
-				    u8 type, u8 feature)
-{
-	/* XXX check if other confirms for that are queued and recycle slot */
-	struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
-
-	if (opt = NULL) {
-		/* XXX what do we do?  Ignoring should be fine.  It's a change
-		 * after all =P
-		 */
-		return;
-	}
-
-	switch (type) {
-	case DCCPO_CHANGE_L:
-		opt->dccpop_type = DCCPO_CONFIRM_R;
-		break;
-	case DCCPO_CHANGE_R:
-		opt->dccpop_type = DCCPO_CONFIRM_L;
-		break;
-	default:
-		DCCP_WARN("invalid type %d\n", type);
-		kfree(opt);
-		return;
-	}
-	opt->dccpop_feat = feature;
-	opt->dccpop_val	 = NULL;
-	opt->dccpop_len	 = 0;
-
-	/* change feature */
-	dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature);
-
-	list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
-}
-
-static void dccp_feat_flush_confirm(struct sock *sk)
-{
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	/* Check if there is anything to confirm in the first place */
-	int yes = !list_empty(&dmsk->dccpms_conf);
-
-	if (!yes) {
-		struct dccp_opt_pend *opt;
-
-		list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-			if (opt->dccpop_conf) {
-				yes = 1;
-				break;
-			}
-		}
-	}
-
-	if (!yes)
-		return;
-
-	/* OK there is something to confirm... */
-	/* XXX check if packet is in flight?  Send delayed ack?? */
-	if (sk->sk_state = DCCP_OPEN)
-		dccp_send_ack(sk);
-}
-
-int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
-{
-	int rc;
-
-	/* Ignore Change requests other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* figure out if it's SP or NN feature */
-	switch (feature) {
-	/* deal with SP features */
-	case DCCPF_CCID:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_sp(sk, type, feature, val, len); */
-		break;
-
-	/* deal with NN features */
-	case DCCPF_ACK_RATIO:
-		/* XXX Obsoleted by next patch
-		rc = dccp_feat_nn(sk, type, feature, val, len); */
-		break;
-
-	/* XXX implement other features */
-	default:
-		dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n",
-			      dccp_feat_typename(type), feature);
-		rc = -EFAULT;
-		break;
-	}
-
-	/* check if there were problems changing features */
-	if (rc) {
-		/* If we don't agree on SP, we sent a confirm for old value.
-		 * However we propagate rc to caller in case option was
-		 * mandatory
-		 */
-		if (rc != DCCP_FEAT_SP_NOAGREE)
-			dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
-	}
-
-	/* generate the confirm [if required] */
-	dccp_feat_flush_confirm(sk);
-
-	return rc;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
-
-int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
-			   u8 *val, u8 len)
-{
-	u8 t;
-	struct dccp_opt_pend *opt;
-	struct dccp_minisock *dmsk = dccp_msk(sk);
-	int found = 0;
-	int all_confirmed = 1;
-
-	/* Ignore Confirm options other than during connection setup */
-	if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
-		return 0;
-	dccp_feat_debug(type, feature, *val);
-
-	/* locate our change request */
-	switch (type) {
-	case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
-	case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
-	default:	      DCCP_WARN("invalid type %d\n", type);
-			      return 1;
-
-	}
-	/* XXX sanity check feature value */
-
-	list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
-		if (!opt->dccpop_conf && opt->dccpop_type = t &&
-		    opt->dccpop_feat = feature) {
-			found = 1;
-			dccp_pr_debug("feature %d found\n", opt->dccpop_feat);
-
-			/* XXX do sanity check */
-
-			opt->dccpop_conf = 1;
-
-			/* We got a confirmation---change the option */
-			dccp_feat_update(sk, opt->dccpop_type,
-					 opt->dccpop_feat, *val);
-
-			/* XXX check the return value of dccp_feat_update */
-			break;
-		}
-
-		if (!opt->dccpop_conf)
-			all_confirmed = 0;
-	}
-
-	if (!found)
-		dccp_pr_debug("%s(%d, ...) never requested\n",
-			      dccp_feat_typename(type), feature);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
-#endif	/* (later) */
-
-void dccp_feat_clean(struct dccp_minisock *dmsk)
-{
-	struct dccp_opt_pend *opt, *next;
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
-				 dccpop_node) {
-		BUG_ON(opt->dccpop_val = NULL);
-		kfree(opt->dccpop_val);
-
-		if (opt->dccpop_sc != NULL) {
-			BUG_ON(opt->dccpop_sc->dccpoc_val = NULL);
-			kfree(opt->dccpop_sc->dccpoc_val);
-			kfree(opt->dccpop_sc);
-		}
-
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);
-
-	list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
-		BUG_ON(opt = NULL);
-		if (opt->dccpop_val != NULL)
-			kfree(opt->dccpop_val);
-		kfree(opt);
-	}
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clean);
-
-/* this is to be called only when a listening sock creates its child.  It is
- * assumed by the function---the confirm is not duplicated, but rather it is
- * "passed on".
- */
-int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
-{
-	struct dccp_minisock *olddmsk = dccp_msk(oldsk);
-	struct dccp_minisock *newdmsk = dccp_msk(newsk);
-	struct dccp_opt_pend *opt;
-	int rc = 0;
-
-	INIT_LIST_HEAD(&newdmsk->dccpms_pending);
-	INIT_LIST_HEAD(&newdmsk->dccpms_conf);
-
-	list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
-		struct dccp_opt_pend *newopt;
-		/* copy the value of the option */
-		u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC);
-
-		if (val = NULL)
-			goto out_clean;
-
-		newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC);
-		if (newopt = NULL) {
-			kfree(val);
-			goto out_clean;
-		}
-
-		/* insert the option */
-		newopt->dccpop_val = val;
-		list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
-
-		/* XXX what happens with backlogs and multiple connections at
-		 * once...
-		 */
-		/* the master socket no longer needs to worry about confirms */
-		opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
-
-		/* reset state for a new socket */
-		opt->dccpop_conf = 0;
-	}
-
-	/* XXX not doing anything about the conf queue */
-
-out:
-	return rc;
-
-out_clean:
-	dccp_feat_clean(newdmsk);
-	rc = -ENOMEM;
-	goto out;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_clone);
-
 /**
  * dccp_feat_change_recv  -  Process incoming ChangeL/R options
  * @fn: feature-negotiation list to update

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/7] dccp: Remove obsolete parts of the old CCID interface
@ 2008-12-06 16:40                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

The TX/RX CCIDs of the minisock are now redundant: similar to the Ack Vector
case, their value equals initially that of the sysctl, but at the end of
feature negotiation may be something different.

The old interface removed by this patch thus has been replaced by the newer
interface to dynamically query the currently loaded CCIDs.

Also removed are the constructors for the TX CCID and the RX CCID, since the
switch "rx <-> non-rx" is done by the handler in minisocks.c (and the handler
is the only place in the code where CCIDs are loaded).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    5 +++--
 include/linux/dccp.h              |    3 ---
 net/dccp/ccid.c                   |   14 --------------
 net/dccp/ccid.h                   |    5 -----
 net/dccp/feat.c                   |   13 -------------
 net/dccp/minisocks.c              |    2 --
 6 files changed, 3 insertions(+), 39 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -140,10 +140,11 @@ send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
 tx_ccid = 2
-	Default CCID for the sender-receiver half-connection.
+	Default CCID for the sender-receiver half-connection. Depending on the
+	choice of CCID, the Send Ack Vector feature is enabled automatically.
 
 rx_ccid = 2
-	Default CCID for the receiver-sender half-connection.
+	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
 	The initial sequence window (sec. 7.5.2).
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -111,11 +111,6 @@ extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-
 static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
 {
 	struct ccid *ccid = dp->dccps_hc_rx_ccid;
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -253,20 +253,6 @@ out_module_put:
 
 EXPORT_SYMBOL_GPL(ccid_new);
 
-struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
-{
-	return ccid_new(id, sk, 1, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
-
-struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk,  gfp_t gfp)
-{
-	return ccid_new(id, sk, 0, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
-
 static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 {
 	struct ccid_operations *ccid_ops;
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -370,7 +370,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
@@ -378,8 +377,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_rx_ccid;
-	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1124,22 +1124,9 @@ int dccp_feat_init(struct sock *sk)
 	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
 	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
-	/* CCID L */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
-				&dmsk->dccpms_tx_ccid, 1);
-	if (rc)
-		goto out;
-
-	/* CCID R */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
-				&dmsk->dccpms_rx_ccid, 1);
-	if (rc)
-		goto out;
-
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
 				dp->dccps_l_ack_ratio);
-out:
 	return rc;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,8 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
-	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/7] dccp: Remove obsolete parts of the old CCID interface
@ 2008-12-06 16:40                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

The TX/RX CCIDs of the minisock are now redundant: similar to the Ack Vector
case, their value equals initially that of the sysctl, but at the end of
feature negotiation may be something different.

The old interface removed by this patch thus has been replaced by the newer
interface to dynamically query the currently loaded CCIDs.

Also removed are the constructors for the TX CCID and the RX CCID, since the
switch "rx <-> non-rx" is done by the handler in minisocks.c (and the handler
is the only place in the code where CCIDs are loaded).

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    5 +++--
 include/linux/dccp.h              |    3 ---
 net/dccp/ccid.c                   |   14 --------------
 net/dccp/ccid.h                   |    5 -----
 net/dccp/feat.c                   |   13 -------------
 net/dccp/minisocks.c              |    2 --
 6 files changed, 3 insertions(+), 39 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -140,10 +140,11 @@ send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
 tx_ccid = 2
-	Default CCID for the sender-receiver half-connection.
+	Default CCID for the sender-receiver half-connection. Depending on the
+	choice of CCID, the Send Ack Vector feature is enabled automatically.
 
 rx_ccid = 2
-	Default CCID for the receiver-sender half-connection.
+	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
 	The initial sequence window (sec. 7.5.2).
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -111,11 +111,6 @@ extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
-extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk,
-				   gfp_t gfp);
-
 static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp)
 {
 	struct ccid *ccid = dp->dccps_hc_rx_ccid;
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -253,20 +253,6 @@ out_module_put:
 
 EXPORT_SYMBOL_GPL(ccid_new);
 
-struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp)
-{
-	return ccid_new(id, sk, 1, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_rx_new);
-
-struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk,  gfp_t gfp)
-{
-	return ccid_new(id, sk, 0, gfp);
-}
-
-EXPORT_SYMBOL_GPL(ccid_hc_tx_new);
-
 static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx)
 {
 	struct ccid_operations *ccid_ops;
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -370,7 +370,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_ccid - Congestion Control Id (CCID) (section 10)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
@@ -378,8 +377,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_rx_ccid;
-	__u8			dccpms_tx_ccid;
 	__u8			dccpms_send_ack_vector;
 	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1124,22 +1124,9 @@ int dccp_feat_init(struct sock *sk)
 	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
 	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
 
-	/* CCID L */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
-				&dmsk->dccpms_tx_ccid, 1);
-	if (rc)
-		goto out;
-
-	/* CCID R */
-	rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
-				&dmsk->dccpms_rx_ccid, 1);
-	if (rc)
-		goto out;
-
 	/* Ack ratio */
 	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
 				dp->dccps_l_ack_ratio);
-out:
 	return rc;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,8 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_rx_ccid	     = sysctl_dccp_feat_rx_ccid;
-	dmsk->dccpms_tx_ccid	     = sysctl_dccp_feat_tx_ccid;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 6/7] dccp: Remove manual influence on NDP Count feature
@ 2008-12-06 16:40                                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

Updating the NDP count feature is handled automatically now:
 * for CCID-2 it is disabled, since the code does not use NDP counts;
 * for CCID-3 it is enabled, as NDP counts are used to determine loss lengths.

Allowing the user to change NDP values leads to unpredictable and failing
behaviour, since it is then possible to disable NDP counts even when they
are needed (e.g. in CCID-3).

This means that only those user settings are sensible that agree with the
values for Send NDP Count implied by the choice of CCID. But those settings
are already activated by the feature negotiation (CCID dependency tracking),
hence this form of support is redundant.

At startup the initialisation of the NDP count feature uses the default
value of 0, which is done implicitly by the zeroing-out of the socket when
it is allocated. If the choice of CCID or feature negotiation enables NDP
count, this will then be updated via the NDP activation handler.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    4 ++--
 net/dccp/dccp.h                   |    1 -
 net/dccp/feat.c                   |    2 +-
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    4 +---
 net/dccp/sysctl.c                 |    7 -------
 7 files changed, 4 insertions(+), 18 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ndp = 1
-	Whether or not to send NDP count options (sec. 7.7.2).
-
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -371,14 +371,12 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
-  * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
 	__u8			dccpms_send_ack_vector;
-	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
@@ -490,6 +488,7 @@ struct dccp_ackvec;
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
+ * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
@@ -529,6 +528,7 @@ struct dccp_sock {
 	__u16				dccps_r_ack_ratio;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
+	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -99,7 +99,6 @@ extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_feat_send_ack_vector;
-extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -85,7 +85,7 @@ static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
 static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
 {
 	if (!rx)
-		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+		dccp_sk(sk)->dccps_send_ndp_count = (enable > 0);
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -46,7 +46,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
-	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -27,7 +27,6 @@ int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
-int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -531,8 +530,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-	if (dmsk->dccpms_send_ndp_count &&
-	    dccp_insert_option_ndp(sk, skb))
+	if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
 		return -1;
 
 	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -48,13 +48,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ndp",
-		.data		= &sysctl_dccp_feat_send_ndp_count,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ndp_count),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 6/7] dccp: Remove manual influence on NDP Count feature
@ 2008-12-06 16:40                                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

Updating the NDP count feature is handled automatically now:
 * for CCID-2 it is disabled, since the code does not use NDP counts;
 * for CCID-3 it is enabled, as NDP counts are used to determine loss lengths.

Allowing the user to change NDP values leads to unpredictable and failing
behaviour, since it is then possible to disable NDP counts even when they
are needed (e.g. in CCID-3).

This means that only those user settings are sensible that agree with the
values for Send NDP Count implied by the choice of CCID. But those settings
are already activated by the feature negotiation (CCID dependency tracking),
hence this form of support is redundant.

At startup the initialisation of the NDP count feature uses the default
value of 0, which is done implicitly by the zeroing-out of the socket when
it is allocated. If the choice of CCID or feature negotiation enables NDP
count, this will then be updated via the NDP activation handler.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    4 ++--
 net/dccp/dccp.h                   |    1 -
 net/dccp/feat.c                   |    2 +-
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    4 +---
 net/dccp/sysctl.c                 |    7 -------
 7 files changed, 4 insertions(+), 18 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ndp = 1
-	Whether or not to send NDP count options (sec. 7.7.2).
-
 send_ackvec = 1
 	Whether or not to send Ack Vector options (sec. 11.5).
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -371,14 +371,12 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
   * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
-  * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
 	__u8			dccpms_send_ack_vector;
-	__u8			dccpms_send_ndp_count;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
@@ -490,6 +488,7 @@ struct dccp_ackvec;
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
+ * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
@@ -529,6 +528,7 @@ struct dccp_sock {
 	__u16				dccps_r_ack_ratio;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
+	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
 	struct dccp_minisock		dccps_minisock;
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -99,7 +99,6 @@ extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_feat_send_ack_vector;
-extern int  sysctl_dccp_feat_send_ndp_count;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -85,7 +85,7 @@ static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx)
 static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx)
 {
 	if (!rx)
-		dccp_msk(sk)->dccpms_send_ndp_count = (enable > 0);
+		dccp_sk(sk)->dccps_send_ndp_count = (enable > 0);
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -46,7 +46,6 @@ void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
 	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
-	dmsk->dccpms_send_ndp_count  = sysctl_dccp_feat_send_ndp_count;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -27,7 +27,6 @@ int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
-int sysctl_dccp_feat_send_ndp_count  = DCCPF_INITIAL_SEND_NDP_COUNT;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -531,8 +530,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
-	if (dmsk->dccpms_send_ndp_count &&
-	    dccp_insert_option_ndp(sk, skb))
+	if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb))
 		return -1;
 
 	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -48,13 +48,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ndp",
-		.data		= &sysctl_dccp_feat_send_ndp_count,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ndp_count),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 7/7] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl
@ 2008-12-06 16:40                                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This removes the use of the sysctl and the minisock variable for the Send Ack
Vector feature, as it now is handled fully dynamically via feature negotiation
(i.e. when CCID-2 is enabled, Ack Vectors are automatically enabled as per
 RFC 4341, 4.).

Using a sysctl in parallel to this implementation would open the door to
crashes, since much of the code relies on tests of the boolean minisock /
sysctl variable. Thus, this patch replaces all tests of type

	if (dccp_msk(sk)->dccpms_send_ack_vector)
		/* ... */
with
	if (dp->dccps_hc_rx_ackvec != NULL)
		/* ... */

The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
negotiation concluded that Ack Vectors are to be used on the half-connection.
Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
so that the test is a valid one.

The activation handler for Ack Vectors is called as soon as the feature
negotiation has concluded at the
 * server when the Ack marking the transition RESPOND => OPEN arrives;
 * client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.

Adding the sequence number of the Response packet to the Ack Vector has been
removed, since
 (a) connection establishment implies that the Response has been received;
 (b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
     this entry will always be ignored;
 (c) it can not be used for anything useful - to detect loss for instance, only
     packets received after the loss can serve as pseudo-dupacks.

There was a FIXME to change the error code when dccp_ackvec_add() fails.
I removed this after finding out that:
 * the check whether ackno < ISN is already made earlier,
 * this Response is likely the 1st packet with an Ackno that the client gets,
 * so when dccp_ackvec_add() fails, the reason is likely not a packet error.


Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    3 ---
 net/dccp/dccp.h                   |    3 +--
 net/dccp/diag.c                   |    2 +-
 net/dccp/input.c                  |   12 +++---------
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    7 ++-----
 net/dccp/proto.c                  |    3 +--
 net/dccp/sysctl.c                 |    7 -------
 9 files changed, 8 insertions(+), 33 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ackvec = 1
-	Whether or not to send Ack Vector options (sec. 11.5).
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection. Depending on the
 	choice of CCID, the Send Ack Vector feature is enabled automatically.
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -360,7 +360,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
 #define DCCPF_INITIAL_ACK_RATIO			2
 #define DCCPF_INITIAL_CCID			DCCPC_CCID2
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -370,13 +369,11 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_send_ack_vector;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
@@ -434,7 +433,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	const struct dccp_sock *dp = dccp_sk(sk);
 	return dp->dccps_timestamp_echo != 0 ||
 #ifdef CONFIG_IP_DCCP_ACKVEC
-	       (dccp_msk(sk)->dccpms_send_ack_vector &&
+	       (dp->dccps_hc_rx_ackvec != NULL &&
 		dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 #endif
 	       inet_csk_ack_scheduled(sk);
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -29,7 +29,7 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info)
 	info->tcpi_backoff	= icsk->icsk_backoff;
 	info->tcpi_pmtu		= icsk->icsk_pmtu_cookie;
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		info->tcpi_options |= TCPI_OPT_SACK;
 
 	ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -163,7 +163,7 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
 					    DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
@@ -375,7 +375,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
 	if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 		dccp_event_ack_recv(sk, skb);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector &&
+	if (dp->dccps_hc_rx_ackvec != NULL &&
 	    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 			    DCCP_SKB_CB(skb)->dccpd_seq,
 			    DCCP_ACKVEC_STATE_RECEIVED))
@@ -434,12 +434,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp -
 			    dp->dccps_options_received.dccpor_timestamp_echo));
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
-		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
-				    DCCP_SKB_CB(skb)->dccpd_seq,
-				    DCCP_ACKVEC_STATE_RECEIVED))
-			goto out_invalid_packet; /* FIXME: change error code */
-
 		/* Stop the REQUEST timer */
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
 		WARN_ON(sk->sk_send_head == NULL);
@@ -637,7 +631,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 			dccp_event_ack_recv(sk, skb);
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
+		if (dp->dccps_hc_rx_ackvec != NULL &&
 		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 				    DCCP_SKB_CB(skb)->dccpd_seq,
 				    DCCP_ACKVEC_STATE_RECEIVED))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,7 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -145,8 +144,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
 				break;
-
-			if (dccp_msk(sk)->dccpms_send_ack_vector &&
+			if (dp->dccps_hc_rx_ackvec != NULL &&
 			    dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
 				goto out_invalid_option;
 			break;
@@ -526,7 +524,6 @@ static void dccp_insert_option_padding(struct sk_buff *skb)
 int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
@@ -547,7 +544,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 			if (dccp_insert_option_timestamp(sk, skb))
 				return -1;
 
-		} else if (dmsk->dccpms_send_ack_vector	&&
+		} else if (dp->dccps_hc_rx_ackvec != NULL &&
 			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
 			   dccp_insert_option_ackvec(sk, skb)) {
 				return -1;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -207,7 +207,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
 void dccp_destroy_sock(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	/*
 	 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -225,7 +224,7 @@ void dccp_destroy_sock(struct sock *sk)
 	kfree(dp->dccps_service_list);
 	dp->dccps_service_list = NULL;
 
-	if (dmsk->dccpms_send_ack_vector) {
+	if (dp->dccps_hc_rx_ackvec != NULL) {
 		dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
 		dp->dccps_hc_rx_ackvec = NULL;
 	}
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ackvec",
-		.data		= &sysctl_dccp_feat_send_ack_vector,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 7/7] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl
@ 2008-12-06 16:40                                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-06 16:40 UTC (permalink / raw)
  To: dccp

This removes the use of the sysctl and the minisock variable for the Send Ack
Vector feature, as it now is handled fully dynamically via feature negotiation
(i.e. when CCID-2 is enabled, Ack Vectors are automatically enabled as per
 RFC 4341, 4.).

Using a sysctl in parallel to this implementation would open the door to
crashes, since much of the code relies on tests of the boolean minisock /
sysctl variable. Thus, this patch replaces all tests of type

	if (dccp_msk(sk)->dccpms_send_ack_vector)
		/* ... */
with
	if (dp->dccps_hc_rx_ackvec != NULL)
		/* ... */

The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
negotiation concluded that Ack Vectors are to be used on the half-connection.
Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
so that the test is a valid one.

The activation handler for Ack Vectors is called as soon as the feature
negotiation has concluded at the
 * server when the Ack marking the transition RESPOND => OPEN arrives;
 * client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.

Adding the sequence number of the Response packet to the Ack Vector has been
removed, since
 (a) connection establishment implies that the Response has been received;
 (b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
     this entry will always be ignored;
 (c) it can not be used for anything useful - to detect loss for instance, only
     packets received after the loss can serve as pseudo-dupacks.

There was a FIXME to change the error code when dccp_ackvec_add() fails.
I removed this after finding out that:
 * the check whether ackno < ISN is already made earlier,
 * this Response is likely the 1st packet with an Ackno that the client gets,
 * so when dccp_ackvec_add() fails, the reason is likely not a packet error.


Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ---
 include/linux/dccp.h              |    3 ---
 net/dccp/dccp.h                   |    3 +--
 net/dccp/diag.c                   |    2 +-
 net/dccp/input.c                  |   12 +++---------
 net/dccp/minisocks.c              |    1 -
 net/dccp/options.c                |    7 ++-----
 net/dccp/proto.c                  |    3 +--
 net/dccp/sysctl.c                 |    7 -------
 9 files changed, 8 insertions(+), 33 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -133,9 +133,6 @@ retries2
 	importance for retransmitted acknowledgments and feature negotiation,
 	data packets are never retransmitted. Analogue of tcp_retries2.
 
-send_ackvec = 1
-	Whether or not to send Ack Vector options (sec. 11.5).
-
 tx_ccid = 2
 	Default CCID for the sender-receiver half-connection. Depending on the
 	choice of CCID, the Send Ack Vector feature is enabled automatically.
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -360,7 +360,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
 #define DCCPF_INITIAL_ACK_RATIO			2
 #define DCCPF_INITIAL_CCID			DCCPC_CCID2
-#define DCCPF_INITIAL_SEND_ACK_VECTOR		1
 /* FIXME: for now we're default to 1 but it should really be 0 */
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
@@ -370,13 +369,11 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5)
   * @dccpms_pending - List of features being negotiated
   * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	__u8			dccpms_send_ack_vector;
 	struct list_head	dccpms_pending;
 	struct list_head	dccpms_conf;
 };
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -98,7 +98,6 @@ extern int  sysctl_dccp_retries2;
 extern int  sysctl_dccp_feat_sequence_window;
 extern int  sysctl_dccp_feat_rx_ccid;
 extern int  sysctl_dccp_feat_tx_ccid;
-extern int  sysctl_dccp_feat_send_ack_vector;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
@@ -434,7 +433,7 @@ static inline int dccp_ack_pending(const struct sock *sk)
 	const struct dccp_sock *dp = dccp_sk(sk);
 	return dp->dccps_timestamp_echo != 0 ||
 #ifdef CONFIG_IP_DCCP_ACKVEC
-	       (dccp_msk(sk)->dccpms_send_ack_vector &&
+	       (dp->dccps_hc_rx_ackvec != NULL &&
 		dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
 #endif
 	       inet_csk_ack_scheduled(sk);
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -29,7 +29,7 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info)
 	info->tcpi_backoff	= icsk->icsk_backoff;
 	info->tcpi_pmtu		= icsk->icsk_pmtu_cookie;
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		info->tcpi_options |= TCPI_OPT_SACK;
 
 	ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info);
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -163,7 +163,7 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector)
+	if (dp->dccps_hc_rx_ackvec != NULL)
 		dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
 					    DCCP_SKB_CB(skb)->dccpd_ack_seq);
 }
@@ -375,7 +375,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
 	if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 		dccp_event_ack_recv(sk, skb);
 
-	if (dccp_msk(sk)->dccpms_send_ack_vector &&
+	if (dp->dccps_hc_rx_ackvec != NULL &&
 	    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 			    DCCP_SKB_CB(skb)->dccpd_seq,
 			    DCCP_ACKVEC_STATE_RECEIVED))
@@ -434,12 +434,6 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
 			dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp -
 			    dp->dccps_options_received.dccpor_timestamp_echo));
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
-		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
-				    DCCP_SKB_CB(skb)->dccpd_seq,
-				    DCCP_ACKVEC_STATE_RECEIVED))
-			goto out_invalid_packet; /* FIXME: change error code */
-
 		/* Stop the REQUEST timer */
 		inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS);
 		WARN_ON(sk->sk_send_head = NULL);
@@ -637,7 +631,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 		if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
 			dccp_event_ack_recv(sk, skb);
 
-		if (dccp_msk(sk)->dccpms_send_ack_vector &&
+		if (dp->dccps_hc_rx_ackvec != NULL &&
 		    dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
 				    DCCP_SKB_CB(skb)->dccpd_seq,
 				    DCCP_ACKVEC_STATE_RECEIVED))
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -45,7 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row);
 void dccp_minisock_init(struct dccp_minisock *dmsk)
 {
 	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-	dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector;
 }
 
 void dccp_time_wait(struct sock *sk, int state, int timeo)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -26,7 +26,6 @@
 int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
 int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
 int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR;
 
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
@@ -145,8 +144,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 		case DCCPO_ACK_VECTOR_1:
 			if (dccp_packet_without_ack(skb))   /* RFC 4340, 11.4 */
 				break;
-
-			if (dccp_msk(sk)->dccpms_send_ack_vector &&
+			if (dp->dccps_hc_rx_ackvec != NULL &&
 			    dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
 				goto out_invalid_option;
 			break;
@@ -526,7 +524,6 @@ static void dccp_insert_option_padding(struct sk_buff *skb)
 int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
 
@@ -547,7 +544,7 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 			if (dccp_insert_option_timestamp(sk, skb))
 				return -1;
 
-		} else if (dmsk->dccpms_send_ack_vector	&&
+		} else if (dp->dccps_hc_rx_ackvec != NULL &&
 			   dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
 			   dccp_insert_option_ackvec(sk, skb)) {
 				return -1;
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -207,7 +207,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock);
 void dccp_destroy_sock(struct sock *sk)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	/*
 	 * DCCP doesn't use sk_write_queue, just sk_send_head
@@ -225,7 +224,7 @@ void dccp_destroy_sock(struct sock *sk)
 	kfree(dp->dccps_service_list);
 	dp->dccps_service_list = NULL;
 
-	if (dmsk->dccpms_send_ack_vector) {
+	if (dp->dccps_hc_rx_ackvec != NULL) {
 		dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
 		dp->dccps_hc_rx_ackvec = NULL;
 	}
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -41,13 +41,6 @@ static struct ctl_table dccp_default_table[] = {
 		.proc_handler	= proc_dointvec,
 	},
 	{
-		.procname	= "send_ackvec",
-		.data		= &sysctl_dccp_feat_send_ack_vector,
-		.maxlen		= sizeof(sysctl_dccp_feat_send_ack_vector),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/7] dccp: Integration of dynamic feature activation - part 1 (socket setup)
  2008-12-06 16:40                                                                           ` Gerrit Renker
@ 2008-12-08  9:15                                                                             ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:15 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:51 +0100

> This first patch out of three replaces the hardcoded default settings with
> initialisation code for the dynamic feature negotiation.
> 
> The patch also ensures that the client feature-negotiation queue is flushed
> only when entering the OPEN state.
> 
> Since confirmed Change options are removed as soon as they are confirmed
> (in the DCCP-Response), this ensures that Confirm options are retransmitted.
> 
> Note on retransmitting Confirm options:
> ---------------------------------------
> Implementation experience showed that it is necessary to retransmit Confirm
> options. Thanks to Leandro Melo de Sales who reported a bug in an earlier
> revision of the patch set, resulting from not retransmitting these options.
> 
> As long as the client is in PARTOPEN, it needs to retransmit the Confirm
> options for the Change options received on the DCCP-Response from the server.
> 
> Otherwise, if the packet containing the Confirm options gets dropped in the
> network, the connection aborts due to undefined feature negotiation state.
> 
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 1/7] dccp: Integration of dynamic feature activation -
@ 2008-12-08  9:15                                                                             ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:15 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:51 +0100

> This first patch out of three replaces the hardcoded default settings with
> initialisation code for the dynamic feature negotiation.
> 
> The patch also ensures that the client feature-negotiation queue is flushed
> only when entering the OPEN state.
> 
> Since confirmed Change options are removed as soon as they are confirmed
> (in the DCCP-Response), this ensures that Confirm options are retransmitted.
> 
> Note on retransmitting Confirm options:
> ---------------------------------------
> Implementation experience showed that it is necessary to retransmit Confirm
> options. Thanks to Leandro Melo de Sales who reported a bug in an earlier
> revision of the patch set, resulting from not retransmitting these options.
> 
> As long as the client is in PARTOPEN, it needs to retransmit the Confirm
> options for the Change options received on the DCCP-Response from the server.
> 
> Otherwise, if the packet containing the Confirm options gets dropped in the
> network, the connection aborts due to undefined feature negotiation state.
> 
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/7] dccp: Integration of dynamic feature activation - part 2 (server side)
  2008-12-06 16:40                                                                             ` Gerrit Renker
@ 2008-12-08  9:16                                                                               ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:16 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:52 +0100

> This patch integrates the activation of features at the end of negotiation
> into the server-side code.
> 
> Note regarding the removal of 'const':
> --------------------------------------
>  The 'const' attribute has been removed from 'dreq' since dccp_activate_values()
>  needs to operate on dreq's feature list. Part of the activation is to remove
>  those options from the list that have already been confirmed, hence it is not
>  purely read-only.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/7] dccp: Integration of dynamic feature activation -
@ 2008-12-08  9:16                                                                               ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:16 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:52 +0100

> This patch integrates the activation of features at the end of negotiation
> into the server-side code.
> 
> Note regarding the removal of 'const':
> --------------------------------------
>  The 'const' attribute has been removed from 'dreq' since dccp_activate_values()
>  needs to operate on dreq's feature list. Part of the activation is to remove
>  those options from the list that have already been confirmed, hence it is not
>  purely read-only.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 3/7] dccp: Integration of dynamic feature activation - part 3 (client side)
  2008-12-06 16:40                                                                               ` Gerrit Renker
@ 2008-12-08  9:16                                                                                 ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:16 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:53 +0100

> This integrates feature-activation in the client:
> 
>  1. When dccp_parse_options() fails, the reset code is already set; request_sent\
>     _state_process() currently overrides this with `Packet Error', which is not
>     intended - changed to use the reset code supplied by dccp_parse_options().
> 
>  2. When feature negotiation fails, the socket should be marked as not usable,
>     so that the application is notified that an error occurred. This is achieved
>     by a new label 'unable_to_proceed': generating an error code of `Aborted',
>     setting the socket state to CLOSED, returning with ECOMM in sk_err.
> 
>  3. Avoids parsing the Ack twice in Respond state by not doing option processing
>     again in dccp_rcv_respond_partopen_state_process (as option processing has
>     already been done on the request_sock in dccp_check_req).
> 
> Since this addresses congestion-control initialisation, a corresponding
> FIXME has been removed.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 3/7] dccp: Integration of dynamic feature activation -
@ 2008-12-08  9:16                                                                                 ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:16 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:53 +0100

> This integrates feature-activation in the client:
> 
>  1. When dccp_parse_options() fails, the reset code is already set; request_sent\
>     _state_process() currently overrides this with `Packet Error', which is not
>     intended - changed to use the reset code supplied by dccp_parse_options().
> 
>  2. When feature negotiation fails, the socket should be marked as not usable,
>     so that the application is notified that an error occurred. This is achieved
>     by a new label 'unable_to_proceed': generating an error code of `Aborted',
>     setting the socket state to CLOSED, returning with ECOMM in sk_err.
> 
>  3. Avoids parsing the Ack twice in Respond state by not doing option processing
>     again in dccp_rcv_respond_partopen_state_process (as option processing has
>     already been done on the request_sock in dccp_check_req).
> 
> Since this addresses congestion-control initialisation, a corresponding
> FIXME has been removed.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/7] dccp: Clean up old feature-negotiation infrastructure
  2008-12-06 16:40                                                                                 ` Gerrit Renker
@ 2008-12-08  9:17                                                                                   ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:17 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:54 +0100

> The code removed by this patch is no longer referenced or used, the added
> lines update documentation and copyrights.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/7] dccp: Clean up old feature-negotiation
@ 2008-12-08  9:17                                                                                   ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:17 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:54 +0100

> The code removed by this patch is no longer referenced or used, the added
> lines update documentation and copyrights.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 5/7] dccp: Remove obsolete parts of the old CCID interface
  2008-12-06 16:40                                                                                   ` Gerrit Renker
@ 2008-12-08  9:18                                                                                     ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:18 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:55 +0100

> The TX/RX CCIDs of the minisock are now redundant: similar to the Ack Vector
> case, their value equals initially that of the sysctl, but at the end of
> feature negotiation may be something different.
> 
> The old interface removed by this patch thus has been replaced by the newer
> interface to dynamically query the currently loaded CCIDs.
> 
> Also removed are the constructors for the TX CCID and the RX CCID, since the
> switch "rx <-> non-rx" is done by the handler in minisocks.c (and the handler
> is the only place in the code where CCIDs are loaded).
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 5/7] dccp: Remove obsolete parts of the old CCID
@ 2008-12-08  9:18                                                                                     ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:18 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:55 +0100

> The TX/RX CCIDs of the minisock are now redundant: similar to the Ack Vector
> case, their value equals initially that of the sysctl, but at the end of
> feature negotiation may be something different.
> 
> The old interface removed by this patch thus has been replaced by the newer
> interface to dynamically query the currently loaded CCIDs.
> 
> Also removed are the constructors for the TX CCID and the RX CCID, since the
> switch "rx <-> non-rx" is done by the handler in minisocks.c (and the handler
> is the only place in the code where CCIDs are loaded).
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 6/7] dccp: Remove manual influence on NDP Count feature
  2008-12-06 16:40                                                                                     ` Gerrit Renker
@ 2008-12-08  9:18                                                                                       ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:18 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:56 +0100

> Updating the NDP count feature is handled automatically now:
>  * for CCID-2 it is disabled, since the code does not use NDP counts;
>  * for CCID-3 it is enabled, as NDP counts are used to determine loss lengths.
> 
> Allowing the user to change NDP values leads to unpredictable and failing
> behaviour, since it is then possible to disable NDP counts even when they
> are needed (e.g. in CCID-3).
> 
> This means that only those user settings are sensible that agree with the
> values for Send NDP Count implied by the choice of CCID. But those settings
> are already activated by the feature negotiation (CCID dependency tracking),
> hence this form of support is redundant.
> 
> At startup the initialisation of the NDP count feature uses the default
> value of 0, which is done implicitly by the zeroing-out of the socket when
> it is allocated. If the choice of CCID or feature negotiation enables NDP
> count, this will then be updated via the NDP activation handler.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 6/7] dccp: Remove manual influence on NDP Count feature
@ 2008-12-08  9:18                                                                                       ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:18 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:56 +0100

> Updating the NDP count feature is handled automatically now:
>  * for CCID-2 it is disabled, since the code does not use NDP counts;
>  * for CCID-3 it is enabled, as NDP counts are used to determine loss lengths.
> 
> Allowing the user to change NDP values leads to unpredictable and failing
> behaviour, since it is then possible to disable NDP counts even when they
> are needed (e.g. in CCID-3).
> 
> This means that only those user settings are sensible that agree with the
> values for Send NDP Count implied by the choice of CCID. But those settings
> are already activated by the feature negotiation (CCID dependency tracking),
> hence this form of support is redundant.
> 
> At startup the initialisation of the NDP count feature uses the default
> value of 0, which is done implicitly by the zeroing-out of the socket when
> it is allocated. If the choice of CCID or feature negotiation enables NDP
> count, this will then be updated via the NDP activation handler.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Applied.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 7/7] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl
  2008-12-06 16:40                                                                                       ` Gerrit Renker
@ 2008-12-08  9:19                                                                                         ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:19 UTC (permalink / raw)
  To: gerrit; +Cc: dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:57 +0100

> This removes the use of the sysctl and the minisock variable for the Send Ack
> Vector feature, as it now is handled fully dynamically via feature negotiation
> (i.e. when CCID-2 is enabled, Ack Vectors are automatically enabled as per
>  RFC 4341, 4.).
> 
> Using a sysctl in parallel to this implementation would open the door to
> crashes, since much of the code relies on tests of the boolean minisock /
> sysctl variable. Thus, this patch replaces all tests of type
> 
> 	if (dccp_msk(sk)->dccpms_send_ack_vector)
> 		/* ... */
> with
> 	if (dp->dccps_hc_rx_ackvec != NULL)
> 		/* ... */
> 
> The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
> negotiation concluded that Ack Vectors are to be used on the half-connection.
> Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
> so that the test is a valid one.
> 
> The activation handler for Ack Vectors is called as soon as the feature
> negotiation has concluded at the
>  * server when the Ack marking the transition RESPOND => OPEN arrives;
>  * client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.
> 
> Adding the sequence number of the Response packet to the Ack Vector has been
> removed, since
>  (a) connection establishment implies that the Response has been received;
>  (b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
>      this entry will always be ignored;
>  (c) it can not be used for anything useful - to detect loss for instance, only
>      packets received after the loss can serve as pseudo-dupacks.
> 
> There was a FIXME to change the error code when dccp_ackvec_add() fails.
> I removed this after finding out that:
>  * the check whether ackno < ISN is already made earlier,
>  * this Response is likely the 1st packet with an Ackno that the client gets,
>  * so when dccp_ackvec_add() fails, the reason is likely not a packet error.
> 
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Also applied, thanks Gerrit.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 7/7] dccp ccid-2: Phase out the use of boolean Ack
@ 2008-12-08  9:19                                                                                         ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-08  9:19 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Sat,  6 Dec 2008 17:40:57 +0100

> This removes the use of the sysctl and the minisock variable for the Send Ack
> Vector feature, as it now is handled fully dynamically via feature negotiation
> (i.e. when CCID-2 is enabled, Ack Vectors are automatically enabled as per
>  RFC 4341, 4.).
> 
> Using a sysctl in parallel to this implementation would open the door to
> crashes, since much of the code relies on tests of the boolean minisock /
> sysctl variable. Thus, this patch replaces all tests of type
> 
> 	if (dccp_msk(sk)->dccpms_send_ack_vector)
> 		/* ... */
> with
> 	if (dp->dccps_hc_rx_ackvec != NULL)
> 		/* ... */
> 
> The dccps_hc_rx_ackvec is allocated by the dccp_hdlr_ackvec() when feature
> negotiation concluded that Ack Vectors are to be used on the half-connection.
> Otherwise, it is NULL (due to dccp_init_sock/dccp_create_openreq_child),
> so that the test is a valid one.
> 
> The activation handler for Ack Vectors is called as soon as the feature
> negotiation has concluded at the
>  * server when the Ack marking the transition RESPOND => OPEN arrives;
>  * client after it has sent its ACK, marking the transition REQUEST => PARTOPEN.
> 
> Adding the sequence number of the Response packet to the Ack Vector has been
> removed, since
>  (a) connection establishment implies that the Response has been received;
>  (b) the CCIDs only look at packets received in the (PART)OPEN state, i.e.
>      this entry will always be ignored;
>  (c) it can not be used for anything useful - to detect loss for instance, only
>      packets received after the loss can serve as pseudo-dupacks.
> 
> There was a FIXME to change the error code when dccp_ackvec_add() fails.
> I removed this after finding out that:
>  * the check whether ackno < ISN is already made earlier,
>  * this Response is likely the 1st packet with an Ackno that the client gets,
>  * so when dccp_ackvec_add() fails, the reason is likely not a packet error.
> 
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>

Also applied, thanks Gerrit.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/5] dccp: Feature negotiation part III -- complete
  2008-11-15 12:11                                                                     ` Gerrit Renker
@ 2008-12-13 13:41                                                                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev

Hi Dave,

please find enclosed the last set, completing the feature negotiation
implementation. I have checked these to compile individually. 

Gerrit


Commit summary:
---------------
This is the final set out of an ongoing submission to provide feature and 
capability negotiation for DCCP endpoints (RFC 4340 - 4342, RFC 5348).

The whole set is structured into 3 main blocks - (1) basis, (2) core, (3)
integration and cleanup.

This set is the final in block (3) and implements the initialization of
feature-negotiation state. This includes picking up the global defaults
set via sysctls and to auto-load the CCID modules before announcing
available CCID modules as negotiable candidates to the peer.


List of patches in this set:
----------------------------
Patch #1: Initialisation framework for the supported features.
Patch #2: Auto-loading of CCID modules so that the modules are available
          when the negotiation is completed.
Patch #3: Adds full support for local/remote Sequence Window.
Patch #4: Initialisation and type-checking of involved sysctls.
Patch #5: A set of (useful) debugging/printing helper functions.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p=dccp_exp.git;a=commitdiff;h=913ef8fac15e3704794360c0862ad65a11f833ae


Patch stats:
------------
 Documentation/networking/dccp.txt |    3 
 include/linux/dccp.h              |   51 -------
 net/dccp/ccid.c                   |   39 ++++--
 net/dccp/ccid.h                   |    1 
 net/dccp/dccp.h                   |   21 +--
 net/dccp/feat.c                   |  247 ++++++++++++++++++++++++++++----------
 net/dccp/feat.h                   |   23 +--
 net/dccp/minisocks.c              |   11 -
 net/dccp/options.c                |    8 -
 net/dccp/proto.c                  |    2 
 net/dccp/sysctl.c                 |   43 ++++--
 11 files changed, 271 insertions(+), 178 deletions(-)

^ permalink raw reply	[flat|nested] 484+ messages in thread

* net-next-2.6 [PATCH 0/5] dccp: Feature negotiation part III -- complete
@ 2008-12-13 13:41                                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: dccp

Hi Dave,

please find enclosed the last set, completing the feature negotiation
implementation. I have checked these to compile individually. 

Gerrit


Commit summary:
---------------
This is the final set out of an ongoing submission to provide feature and 
capability negotiation for DCCP endpoints (RFC 4340 - 4342, RFC 5348).

The whole set is structured into 3 main blocks - (1) basis, (2) core, (3)
integration and cleanup.

This set is the final in block (3) and implements the initialization of
feature-negotiation state. This includes picking up the global defaults
set via sysctls and to auto-load the CCID modules before announcing
available CCID modules as negotiable candidates to the peer.


List of patches in this set:
----------------------------
Patch #1: Initialisation framework for the supported features.
Patch #2: Auto-loading of CCID modules so that the modules are available
          when the negotiation is completed.
Patch #3: Adds full support for local/remote Sequence Window.
Patch #4: Initialisation and type-checking of involved sysctls.
Patch #5: A set of (useful) debugging/printing helper functions.

The set is also available for viewing online, beginning at
http://eden-feed.erg.abdn.ac.uk/cgi-bin/gitweb.cgi?p‹cp_exp.git;a=commitdiff;hë3ef8fac15e3704794360c0862ad65a11f833ae


Patch stats:
------------
 Documentation/networking/dccp.txt |    3 
 include/linux/dccp.h              |   51 -------
 net/dccp/ccid.c                   |   39 ++++--
 net/dccp/ccid.h                   |    1 
 net/dccp/dccp.h                   |   21 +--
 net/dccp/feat.c                   |  247 ++++++++++++++++++++++++++++----------
 net/dccp/feat.h                   |   23 +--
 net/dccp/minisocks.c              |   11 -
 net/dccp/options.c                |    8 -
 net/dccp/proto.c                  |    2 
 net/dccp/sysctl.c                 |   43 ++++--
 11 files changed, 271 insertions(+), 178 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Initialisation framework for feature negotiation
@ 2008-12-13 13:41                                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This initialises feature negotiation from two tables, which are initialised
from sysctls.

As a novel feature, specifics of the implementation (e.g. currently short
seqnos and ECN are not supported) are advertised for robustness.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |   19 --------------
 net/dccp/feat.h      |    2 +-
 net/dccp/feat.c      |   65 +++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 57 insertions(+), 29 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -369,28 +369,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_pending - List of features being negotiated
-  * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	struct list_head	dccpms_pending;
-	struct list_head	dccpms_conf;
-};
-
-struct dccp_opt_conf {
-	__u8			*dccpoc_val;
-	__u8			dccpoc_len;
-};
-
-struct dccp_opt_pend {
-	struct list_head	dccpop_node;
-	__u8			dccpop_type;
-	__u8			dccpop_feat;
-	__u8		        *dccpop_val;
-	__u8			dccpop_len;
-	int			dccpop_conf;
-	struct dccp_opt_conf    *dccpop_sc;
 };
 
 extern void dccp_minisock_init(struct dccp_minisock *dmsk);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -113,13 +113,13 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
+extern int  dccp_feat_init(struct sock *sk);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct sock *sk);
 
 /*
  * Encoding variable-length options and their maximum length.
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1115,23 +1115,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 	return 0;	/* ignore FN options in all other states */
 }
 
+/**
+ * dccp_feat_init  -  Seed feature negotiation with host-specific defaults
+ * This initialises global defaults, depending on the value of the sysctls.
+ * These can later be overridden by registering changes via setsockopt calls.
+ * The last link in the chain is finalise_settings, to make sure that between
+ * here and the start of actual feature negotiation no inconsistencies enter.
+ *
+ * All features not appearing below use either defaults or are otherwise
+ * later adjusted through dccp_feat_finalise_settings().
+ */
 int dccp_feat_init(struct sock *sk)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
+	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+	u8 on = 1, off = 0;
 	int rc;
+	struct {
+		u8 *val;
+		u8 len;
+	} tx, rx;
+
+	/* Non-negotiable (NN) features */
+	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
+				    sysctl_dccp_feat_sequence_window);
+	if (rc)
+		return rc;
+
+	/* Server-priority (SP) features */
+
+	/* Advertise that short seqnos are not supported (7.6.1) */
+	rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
+	if (rc)
+		return rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
+	/* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
+	rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
+	if (rc)
+		return rc;
+
+	/*
+	 * We advertise the available list of CCIDs and reorder according to
+	 * preferences, to avoid failure resulting from negotiating different
+	 * singleton values (which always leads to failure).
+	 * These settings can still (later) be overridden via sockopts.
+	 */
+	if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
+	    ccid_get_builtin_ccids(&rx.val, &rx.len))
+		return -ENOBUFS;
 
-	/* Ack ratio */
-	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dp->dccps_l_ack_ratio);
+	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
+	if (rc)
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
+
+free_ccid_lists:
+	kfree(tx.val);
+	kfree(rx.val);
 	return rc;
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_init);
-
 int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 {
 	struct dccp_sock *dp = dccp_sk(sk);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 1/5] dccp: Initialisation framework for feature negotiation
@ 2008-12-13 13:41                                                                                             ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: dccp

This initialises feature negotiation from two tables, which are initialised
from sysctls.

As a novel feature, specifics of the implementation (e.g. currently short
seqnos and ECN are not supported) are advertised for robustness.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |   19 --------------
 net/dccp/feat.h      |    2 +-
 net/dccp/feat.c      |   65 +++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 57 insertions(+), 29 deletions(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -369,28 +369,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
   * Will be used to pass the state from dccp_request_sock to dccp_sock.
   *
   * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  * @dccpms_pending - List of features being negotiated
-  * @dccpms_conf -
   */
 struct dccp_minisock {
 	__u64			dccpms_sequence_window;
-	struct list_head	dccpms_pending;
-	struct list_head	dccpms_conf;
-};
-
-struct dccp_opt_conf {
-	__u8			*dccpoc_val;
-	__u8			dccpoc_len;
-};
-
-struct dccp_opt_pend {
-	struct list_head	dccpop_node;
-	__u8			dccpop_type;
-	__u8			dccpop_feat;
-	__u8		        *dccpop_val;
-	__u8			dccpop_len;
-	int			dccpop_conf;
-	struct dccp_opt_conf    *dccpop_sc;
 };
 
 extern void dccp_minisock_init(struct dccp_minisock *dmsk);
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -113,13 +113,13 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #define dccp_feat_debug(type, feat, val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
+extern int  dccp_feat_init(struct sock *sk);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
 extern int  dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
 				    u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
 extern int  dccp_feat_clone_list(struct list_head const *, struct list_head *);
-extern int  dccp_feat_init(struct sock *sk);
 
 /*
  * Encoding variable-length options and their maximum length.
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1115,23 +1115,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
 	return 0;	/* ignore FN options in all other states */
 }
 
+/**
+ * dccp_feat_init  -  Seed feature negotiation with host-specific defaults
+ * This initialises global defaults, depending on the value of the sysctls.
+ * These can later be overridden by registering changes via setsockopt calls.
+ * The last link in the chain is finalise_settings, to make sure that between
+ * here and the start of actual feature negotiation no inconsistencies enter.
+ *
+ * All features not appearing below use either defaults or are otherwise
+ * later adjusted through dccp_feat_finalise_settings().
+ */
 int dccp_feat_init(struct sock *sk)
 {
-	struct dccp_sock *dp = dccp_sk(sk);
-	struct dccp_minisock *dmsk = dccp_msk(sk);
+	struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
+	u8 on = 1, off = 0;
 	int rc;
+	struct {
+		u8 *val;
+		u8 len;
+	} tx, rx;
+
+	/* Non-negotiable (NN) features */
+	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
+				    sysctl_dccp_feat_sequence_window);
+	if (rc)
+		return rc;
+
+	/* Server-priority (SP) features */
+
+	/* Advertise that short seqnos are not supported (7.6.1) */
+	rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
+	if (rc)
+		return rc;
 
-	INIT_LIST_HEAD(&dmsk->dccpms_pending);	/* XXX no longer used */
-	INIT_LIST_HEAD(&dmsk->dccpms_conf);	/* XXX no longer used */
+	/* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
+	rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
+	if (rc)
+		return rc;
+
+	/*
+	 * We advertise the available list of CCIDs and reorder according to
+	 * preferences, to avoid failure resulting from negotiating different
+	 * singleton values (which always leads to failure).
+	 * These settings can still (later) be overridden via sockopts.
+	 */
+	if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
+	    ccid_get_builtin_ccids(&rx.val, &rx.len))
+		return -ENOBUFS;
 
-	/* Ack ratio */
-	rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
-				dp->dccps_l_ack_ratio);
+	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
+	if (rc)
+		goto free_ccid_lists;
+
+	rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
+
+free_ccid_lists:
+	kfree(tx.val);
+	kfree(rx.val);
 	return rc;
 }
 
-EXPORT_SYMBOL_GPL(dccp_feat_init);
-
 int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 {
 	struct dccp_sock *dp = dccp_sk(sk);

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-12-13 13:41                                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This adds auto-loading of CCIDs (when module loading is enabled)
for the purpose of feature negotiation.

The problem with loading the CCIDs at the end of feature negotiation is
that this would happen in software interrupt context. Besides, if the host
advertises CCIDs during negotiation, it should have them ready to use, in
case an agreeing peer wants to use it for the connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h |    1 +
 net/dccp/ccid.c |   39 +++++++++++++++++++++++++++++----------
 net/dccp/feat.c |    5 +++++
 3 files changed, 35 insertions(+), 10 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -108,6 +108,7 @@ extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
 extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 					  char __user *, int __user *);
 
+extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops)
 
 EXPORT_SYMBOL_GPL(ccid_unregister);
 
+/**
+ * ccid_request_module  -  Pre-load CCID module for later use
+ * This should be called only from process context (e.g. during connection
+ * setup) and is necessary for later calls to ccid_new (typically in software
+ * interrupt), so that it has the modules available when they are needed.
+ */
+static int ccid_request_module(u8 id)
+{
+	if (!in_atomic()) {
+		ccids_read_lock();
+		if (ccids[id] == NULL) {
+			ccids_read_unlock();
+			return request_module("net-dccp-ccid-%d", id);
+		}
+		ccids_read_unlock();
+	}
+	return 0;
+}
+
+int ccid_request_modules(u8 const *ccid_array, u8 array_len)
+{
+#ifdef CONFIG_MODULES
+	while (array_len--)
+		if (ccid_request_module(ccid_array[array_len]))
+			return -1;
+#endif
+	return 0;
+}
+
 struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 {
 	struct ccid_operations *ccid_ops;
 	struct ccid *ccid = NULL;
 
 	ccids_read_lock();
-#ifdef CONFIG_MODULES
-	if (ccids[id] == NULL) {
-		/* We only try to load if in process context */
-		ccids_read_unlock();
-		if (gfp & GFP_ATOMIC)
-			goto out;
-		request_module("net-dccp-ccid-%d", id);
-		ccids_read_lock();
-	}
-#endif
 	ccid_ops = ccids[id];
 	if (ccid_ops == NULL)
 		goto out_unlock;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1163,6 +1163,11 @@ int dccp_feat_init(struct sock *sk)
 	    ccid_get_builtin_ccids(&rx.val, &rx.len))
 		return -ENOBUFS;
 
+	/* Pre-load all CCID modules that are going to be advertised */
+	rc = -EUNATCH;
+	if (ccid_request_modules(tx.val, tx.len))
+		goto free_ccid_lists;
+
 	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
 	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-12-13 13:41                                                                                               ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: dccp

This adds auto-loading of CCIDs (when module loading is enabled)
for the purpose of feature negotiation.

The problem with loading the CCIDs at the end of feature negotiation is
that this would happen in software interrupt context. Besides, if the host
advertises CCIDs during negotiation, it should have them ready to use, in
case an agreeing peer wants to use it for the connection.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/ccid.h |    1 +
 net/dccp/ccid.c |   39 +++++++++++++++++++++++++++++----------
 net/dccp/feat.c |    5 +++++
 3 files changed, 35 insertions(+), 10 deletions(-)

--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -108,6 +108,7 @@ extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
 extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
 					  char __user *, int __user *);
 
+extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
 extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
 			     gfp_t gfp);
 
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops)
 
 EXPORT_SYMBOL_GPL(ccid_unregister);
 
+/**
+ * ccid_request_module  -  Pre-load CCID module for later use
+ * This should be called only from process context (e.g. during connection
+ * setup) and is necessary for later calls to ccid_new (typically in software
+ * interrupt), so that it has the modules available when they are needed.
+ */
+static int ccid_request_module(u8 id)
+{
+	if (!in_atomic()) {
+		ccids_read_lock();
+		if (ccids[id] = NULL) {
+			ccids_read_unlock();
+			return request_module("net-dccp-ccid-%d", id);
+		}
+		ccids_read_unlock();
+	}
+	return 0;
+}
+
+int ccid_request_modules(u8 const *ccid_array, u8 array_len)
+{
+#ifdef CONFIG_MODULES
+	while (array_len--)
+		if (ccid_request_module(ccid_array[array_len]))
+			return -1;
+#endif
+	return 0;
+}
+
 struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
 {
 	struct ccid_operations *ccid_ops;
 	struct ccid *ccid = NULL;
 
 	ccids_read_lock();
-#ifdef CONFIG_MODULES
-	if (ccids[id] = NULL) {
-		/* We only try to load if in process context */
-		ccids_read_unlock();
-		if (gfp & GFP_ATOMIC)
-			goto out;
-		request_module("net-dccp-ccid-%d", id);
-		ccids_read_lock();
-	}
-#endif
 	ccid_ops = ccids[id];
 	if (ccid_ops = NULL)
 		goto out_unlock;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1163,6 +1163,11 @@ int dccp_feat_init(struct sock *sk)
 	    ccid_get_builtin_ccids(&rx.val, &rx.len))
 		return -ENOBUFS;
 
+	/* Pre-load all CCID modules that are going to be advertised */
+	rc = -EUNATCH;
+	if (ccid_request_modules(tx.val, tx.len))
+		goto free_ccid_lists;
+
 	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
 	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: Implement both feature-local and feature-remote Sequence Window feature
@ 2008-12-13 13:41                                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This adds full support for local/remote Sequence Window feature, from which the
  * sequence-number-validity (W) and
  * acknowledgment-number-validity (W') windows
derive as specified in RFC 4340, 7.5.3.

Specifically, the following changes are introduced:
  * integrated new socket fields into dccp_sk;
  * updated the update_gsr/gss routines with regard to these fields;
  * updated handler code: the Sequence Window feature is located at the TX side,
    so the local feature is meant if the handler-rx flag is false;
  * the initialisation of `rcv_wnd' in reqsk is removed, since
    - rcv_wnd is not used by the code anywhere;
    - sequence number checks are not done in the LISTEN state (cf. 7.5.3);
    - dccp_check_req checks the Ack number validity more rigorously;
  * the `struct dccp_minisock' became empty and is now removed.

Until the handshake completes with activating negotiated values, the local/remote
Sequence-Window values are undefined and thus can not reliably be estimated.
This issue is addressed in a separate patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ++-
 include/linux/dccp.h              |   24 ++++--------------------
 net/dccp/dccp.h                   |   16 +++++++---------
 net/dccp/feat.c                   |   13 +++++++++++--
 net/dccp/minisocks.c              |   11 -----------
 net/dccp/proto.c                  |    2 --
 6 files changed, 24 insertions(+), 45 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -141,7 +141,8 @@ rx_ccid = 2
 	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
-	The initial sequence window (sec. 7.5.2).
+	The initial sequence window (sec. 7.5.2) of the sender. This influences
+	the local ackno validity and the remote seqno validity windows (7.5.1).
 
 tx_qlen = 5
 	The size of the transmit buffer in packets. A value of 0 corresponds
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -409,23 +409,21 @@ static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
 static inline void dccp_update_gsr(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	dp->dccps_gsr = seq;
-	dccp_set_seqno(&dp->dccps_swl,
-		       dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
-	dccp_set_seqno(&dp->dccps_swh,
-		       dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
+	/* Sequence validity window depends on remote Sequence Window (7.5.1) */
+	dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
+	dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
 }
 
 static inline void dccp_update_gss(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	dp->dccps_awh = dp->dccps_gss = seq;
-	dccp_set_seqno(&dp->dccps_awl,
-		       (dp->dccps_gss -
-			dccp_msk(sk)->dccpms_sequence_window + 1));
+	dp->dccps_gss = seq;
+	/* Ack validity window depends on local Sequence Window value (7.5.1) */
+	dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
+	dp->dccps_awh = dp->dccps_gss;
 }
 
 static inline int dccp_ack_pending(const struct sock *sk)
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -51,8 +51,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
 
 static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
 {
-	if (!rx)
-		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		dp->dccps_r_seq_win = seq_win;
+		/* propagate changes to update SWL/SWH */
+		dccp_update_gsr(sk, dp->dccps_gsr);
+	} else {
+		dp->dccps_l_seq_win = seq_win;
+		/* propagate changes to update AWL */
+		dccp_update_gss(sk, dp->dccps_gss);
+	}
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -42,11 +42,6 @@ struct inet_timewait_death_row dccp_death_row = {
 
 EXPORT_SYMBOL_GPL(dccp_death_row);
 
-void dccp_minisock_init(struct dccp_minisock *dmsk)
-{
-	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-}
-
 void dccp_time_wait(struct sock *sk, int state, int timeo)
 {
 	struct inet_timewait_sock *tw = NULL;
@@ -110,7 +105,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
-		struct dccp_minisock *newdmsk = dccp_msk(newsk);
 
 		newdp->dccps_role	    = DCCP_ROLE_SERVER;
 		newdp->dccps_hc_rx_ackvec   = NULL;
@@ -128,10 +122,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		 *    Initialize S.GAR := S.ISS
 		 *    Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
 		 */
-
-		/* See dccp_v4_conn_request */
-		newdmsk->dccpms_sequence_window = req->rcv_wnd;
-
 		newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
 		dccp_update_gss(newsk, dreq->dreq_iss);
 
@@ -290,7 +280,6 @@ int dccp_reqsk_init(struct request_sock *req,
 	inet_rsk(req)->rmt_port	  = dccp_hdr(skb)->dccph_sport;
 	inet_rsk(req)->loc_port	  = dccp_hdr(skb)->dccph_dport;
 	inet_rsk(req)->acked	  = 0;
-	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
 
 	/* inherit feature negotiation options from listening socket */
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -364,19 +364,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
 /**
-  * struct dccp_minisock - Minimal DCCP connection representation
-  *
-  * Will be used to pass the state from dccp_request_sock to dccp_sock.
-  *
-  * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  */
-struct dccp_minisock {
-	__u64			dccpms_sequence_window;
-};
-
-extern void dccp_minisock_init(struct dccp_minisock *dmsk);
-
-/**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
@@ -464,13 +451,14 @@ struct dccp_ackvec;
  * @dccps_timestamp_time - time of receiving latest @dccps_timestamp_echo
  * @dccps_l_ack_ratio - feature-local Ack Ratio
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
+ * @dccps_l_seq_win - local Sequence Window (influences ack number validity)
+ * @dccps_r_seq_win - remote Sequence Window (influences seq number validity)
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
  * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
- * @dccps_minisock - associated minisock (accessed via dccp_msk)
  * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
@@ -504,12 +492,13 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
+	__u64				dccps_l_seq_win:48;
+	__u64				dccps_r_seq_win:48;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
 	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
-	struct dccp_minisock		dccps_minisock;
 	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
@@ -527,11 +516,6 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
 	return (struct dccp_sock *)sk;
 }
 
-static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
-{
-	return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
-}
-
 static inline const char *dccp_role(const struct sock *sk)
 {
 	switch (dccp_sk(sk)->dccps_role) {
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -180,8 +180,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	dccp_minisock_init(&dp->dccps_minisock);
-
 	icsk->icsk_rto		= DCCP_TIMEOUT_INIT;
 	icsk->icsk_syn_retries	= sysctl_dccp_request_retries;
 	sk->sk_state		= DCCP_CLOSED;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 3/5] dccp: Implement both feature-local and feature-remote Sequence Window feature
@ 2008-12-13 13:41                                                                                                 ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: dccp

This adds full support for local/remote Sequence Window feature, from which the
  * sequence-number-validity (W) and
  * acknowledgment-number-validity (W') windows
derive as specified in RFC 4340, 7.5.3.

Specifically, the following changes are introduced:
  * integrated new socket fields into dccp_sk;
  * updated the update_gsr/gss routines with regard to these fields;
  * updated handler code: the Sequence Window feature is located at the TX side,
    so the local feature is meant if the handler-rx flag is false;
  * the initialisation of `rcv_wnd' in reqsk is removed, since
    - rcv_wnd is not used by the code anywhere;
    - sequence number checks are not done in the LISTEN state (cf. 7.5.3);
    - dccp_check_req checks the Ack number validity more rigorously;
  * the `struct dccp_minisock' became empty and is now removed.

Until the handshake completes with activating negotiated values, the local/remote
Sequence-Window values are undefined and thus can not reliably be estimated.
This issue is addressed in a separate patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 Documentation/networking/dccp.txt |    3 ++-
 include/linux/dccp.h              |   24 ++++--------------------
 net/dccp/dccp.h                   |   16 +++++++---------
 net/dccp/feat.c                   |   13 +++++++++++--
 net/dccp/minisocks.c              |   11 -----------
 net/dccp/proto.c                  |    2 --
 6 files changed, 24 insertions(+), 45 deletions(-)

--- a/Documentation/networking/dccp.txt
+++ b/Documentation/networking/dccp.txt
@@ -141,7 +141,8 @@ rx_ccid = 2
 	Default CCID for the receiver-sender half-connection; see tx_ccid.
 
 seq_window = 100
-	The initial sequence window (sec. 7.5.2).
+	The initial sequence window (sec. 7.5.2) of the sender. This influences
+	the local ackno validity and the remote seqno validity windows (7.5.1).
 
 tx_qlen = 5
 	The size of the transmit buffer in packets. A value of 0 corresponds
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -409,23 +409,21 @@ static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
 static inline void dccp_update_gsr(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
-	const struct dccp_minisock *dmsk = dccp_msk(sk);
 
 	dp->dccps_gsr = seq;
-	dccp_set_seqno(&dp->dccps_swl,
-		       dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
-	dccp_set_seqno(&dp->dccps_swh,
-		       dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
+	/* Sequence validity window depends on remote Sequence Window (7.5.1) */
+	dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
+	dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
 }
 
 static inline void dccp_update_gss(struct sock *sk, u64 seq)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
 
-	dp->dccps_awh = dp->dccps_gss = seq;
-	dccp_set_seqno(&dp->dccps_awl,
-		       (dp->dccps_gss -
-			dccp_msk(sk)->dccpms_sequence_window + 1));
+	dp->dccps_gss = seq;
+	/* Ack validity window depends on local Sequence Window value (7.5.1) */
+	dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
+	dp->dccps_awh = dp->dccps_gss;
 }
 
 static inline int dccp_ack_pending(const struct sock *sk)
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -51,8 +51,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
 
 static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
 {
-	if (!rx)
-		dccp_msk(sk)->dccpms_sequence_window = seq_win;
+	struct dccp_sock *dp = dccp_sk(sk);
+
+	if (rx) {
+		dp->dccps_r_seq_win = seq_win;
+		/* propagate changes to update SWL/SWH */
+		dccp_update_gsr(sk, dp->dccps_gsr);
+	} else {
+		dp->dccps_l_seq_win = seq_win;
+		/* propagate changes to update AWL */
+		dccp_update_gss(sk, dp->dccps_gss);
+	}
 	return 0;
 }
 
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -42,11 +42,6 @@ struct inet_timewait_death_row dccp_death_row = {
 
 EXPORT_SYMBOL_GPL(dccp_death_row);
 
-void dccp_minisock_init(struct dccp_minisock *dmsk)
-{
-	dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
-}
-
 void dccp_time_wait(struct sock *sk, int state, int timeo)
 {
 	struct inet_timewait_sock *tw = NULL;
@@ -110,7 +105,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		struct dccp_request_sock *dreq = dccp_rsk(req);
 		struct inet_connection_sock *newicsk = inet_csk(newsk);
 		struct dccp_sock *newdp = dccp_sk(newsk);
-		struct dccp_minisock *newdmsk = dccp_msk(newsk);
 
 		newdp->dccps_role	    = DCCP_ROLE_SERVER;
 		newdp->dccps_hc_rx_ackvec   = NULL;
@@ -128,10 +122,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
 		 *    Initialize S.GAR := S.ISS
 		 *    Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
 		 */
-
-		/* See dccp_v4_conn_request */
-		newdmsk->dccpms_sequence_window = req->rcv_wnd;
-
 		newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
 		dccp_update_gss(newsk, dreq->dreq_iss);
 
@@ -290,7 +280,6 @@ int dccp_reqsk_init(struct request_sock *req,
 	inet_rsk(req)->rmt_port	  = dccp_hdr(skb)->dccph_sport;
 	inet_rsk(req)->loc_port	  = dccp_hdr(skb)->dccph_dport;
 	inet_rsk(req)->acked	  = 0;
-	req->rcv_wnd		  = sysctl_dccp_feat_sequence_window;
 	dreq->dreq_timestamp_echo = 0;
 
 	/* inherit feature negotiation options from listening socket */
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -364,19 +364,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 #define DCCPF_INITIAL_SEND_NDP_COUNT		1
 
 /**
-  * struct dccp_minisock - Minimal DCCP connection representation
-  *
-  * Will be used to pass the state from dccp_request_sock to dccp_sock.
-  *
-  * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2)
-  */
-struct dccp_minisock {
-	__u64			dccpms_sequence_window;
-};
-
-extern void dccp_minisock_init(struct dccp_minisock *dmsk);
-
-/**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
  * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1)
@@ -464,13 +451,14 @@ struct dccp_ackvec;
  * @dccps_timestamp_time - time of receiving latest @dccps_timestamp_echo
  * @dccps_l_ack_ratio - feature-local Ack Ratio
  * @dccps_r_ack_ratio - feature-remote Ack Ratio
+ * @dccps_l_seq_win - local Sequence Window (influences ack number validity)
+ * @dccps_r_seq_win - remote Sequence Window (influences seq number validity)
  * @dccps_pcslen - sender   partial checksum coverage (via sockopt)
  * @dccps_pcrlen - receiver partial checksum coverage (via sockopt)
  * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2)
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_mss_cache - current value of MSS (path MTU minus header sizes)
  * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4)
- * @dccps_minisock - associated minisock (accessed via dccp_msk)
  * @dccps_featneg - tracks feature-negotiation state (mostly during handshake)
  * @dccps_hc_rx_ackvec - rx half connection ack vector
  * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection)
@@ -504,12 +492,13 @@ struct dccp_sock {
 	__u32				dccps_timestamp_time;
 	__u16				dccps_l_ack_ratio;
 	__u16				dccps_r_ack_ratio;
+	__u64				dccps_l_seq_win:48;
+	__u64				dccps_r_seq_win:48;
 	__u8				dccps_pcslen:4;
 	__u8				dccps_pcrlen:4;
 	__u8				dccps_send_ndp_count:1;
 	__u64				dccps_ndp_count:48;
 	unsigned long			dccps_rate_last;
-	struct dccp_minisock		dccps_minisock;
 	struct list_head		dccps_featneg;
 	struct dccp_ackvec		*dccps_hc_rx_ackvec;
 	struct ccid			*dccps_hc_rx_ccid;
@@ -527,11 +516,6 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk)
 	return (struct dccp_sock *)sk;
 }
 
-static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
-{
-	return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
-}
-
 static inline const char *dccp_role(const struct sock *sk)
 {
 	switch (dccp_sk(sk)->dccps_role) {
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -180,8 +180,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
 	struct dccp_sock *dp = dccp_sk(sk);
 	struct inet_connection_sock *icsk = inet_csk(sk);
 
-	dccp_minisock_init(&dp->dccps_minisock);
-
 	icsk->icsk_rto		= DCCP_TIMEOUT_INIT;
 	icsk->icsk_syn_retries	= sysctl_dccp_request_retries;
 	sk->sk_state		= DCCP_CLOSED;

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls
@ 2008-12-13 13:41                                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

This patch takes care of initialising and type-checking sysctls related to
feature negotiation. Type checking is important since some of the sysctls
now directly act on the feature-negotiation process.

The sysctls are initialised with the known default values for each feature.
For the type-checking the value constraints from RFC 4340 are used:

 * Sequence Window uses the specified Wmin=32, the maximum is ulong (4 bytes),
   tested and confirmed that it works up to 4294967295 - for Gbps speed;
 * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
 * CCIDs are between 0 .. 255;
 * request_retries, retries1, retries2 also between 0..255 for good measure;
 * tx_qlen is checked to be non-negative;
 * sync_ratelimit remains as before.

Further changes:
----------------
Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    8 --------
 net/dccp/dccp.h      |    3 ---
 net/dccp/feat.c      |   11 ++++++++---
 net/dccp/feat.h      |    8 ++++++++
 net/dccp/options.c   |    4 ----
 net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
 6 files changed, 46 insertions(+), 31 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -100,6 +100,13 @@ struct ccid_dependency {
 	u8	val;
 };
 
+/*
+ * Sysctls to seed defaults for feature negotiation
+ */
+extern unsigned long sysctl_dccp_sequence_window;
+extern int	     sysctl_dccp_rx_ccid;
+extern int	     sysctl_dccp_tx_ccid;
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
 extern int  dccp_feat_init(struct sock *sk);
+extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,6 +25,11 @@
 #include "ccid.h"
 #include "feat.h"
 
+/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
+unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
+int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
+		sysctl_dccp_tx_ccid	    __read_mostly = 2;
+
 /*
  * Feature activation handlers.
  *
@@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Non-negotiable (NN) features */
 	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
-				    sysctl_dccp_feat_sequence_window);
+				    sysctl_dccp_sequence_window);
 	if (rc)
 		return rc;
 
@@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
 	if (ccid_request_modules(tx.val, tx.len))
 		goto free_ccid_lists;
 
-	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
-	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;
 
 	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 extern int  sysctl_dccp_request_retries;
 extern int  sysctl_dccp_retries1;
 extern int  sysctl_dccp_retries2;
-extern int  sysctl_dccp_feat_sequence_window;
-extern int  sysctl_dccp_feat_rx_ccid;
-extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 	return __dccp_hdr_len(dccp_hdr(skb));
 }
 
-
-/* initial values for each feature */
-#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-#define DCCPF_INITIAL_ACK_RATIO			2
-#define DCCPF_INITIAL_CCID			DCCPC_CCID2
-/* FIXME: for now we're default to 1 but it should really be 0 */
-#define DCCPF_INITIAL_SEND_NDP_COUNT		1
-
 /**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -23,10 +23,6 @@
 #include "dccp.h"
 #include "feat.h"
 
-int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
-int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
 	u64 value = 0;
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -18,55 +18,72 @@
 #error This file should not be compiled without CONFIG_SYSCTL defined
 #endif
 
+/* Boundary values */
+static int		zero     = 0,
+			u8_max   = 0xFF;
+static unsigned long	seqw_min = 32;
+
 static struct ctl_table dccp_default_table[] = {
 	{
 		.procname	= "seq_window",
-		.data		= &sysctl_dccp_feat_sequence_window,
-		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
+		.data		= &sysctl_dccp_sequence_window,
+		.maxlen		= sizeof(sysctl_dccp_sequence_window),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_doulongvec_minmax,
+		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
 	},
 	{
 		.procname	= "rx_ccid",
-		.data		= &sysctl_dccp_feat_rx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
+		.data		= &sysctl_dccp_rx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "tx_ccid",
-		.data		= &sysctl_dccp_feat_tx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
+		.data		= &sysctl_dccp_tx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries1",
 		.data		= &sysctl_dccp_retries1,
 		.maxlen		= sizeof(sysctl_dccp_retries1),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries2",
 		.data		= &sysctl_dccp_retries2,
 		.maxlen		= sizeof(sysctl_dccp_retries2),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "tx_qlen",
 		.data		= &sysctl_dccp_tx_qlen,
 		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
 	},
 	{
 		.procname	= "sync_ratelimit",

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls
@ 2008-12-13 13:41                                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: dccp

This patch takes care of initialising and type-checking sysctls related to
feature negotiation. Type checking is important since some of the sysctls
now directly act on the feature-negotiation process.

The sysctls are initialised with the known default values for each feature.
For the type-checking the value constraints from RFC 4340 are used:

 * Sequence Window uses the specified Wmin2, the maximum is ulong (4 bytes),
   tested and confirmed that it works up to 4294967295 - for Gbps speed;
 * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
 * CCIDs are between 0 .. 255;
 * request_retries, retries1, retries2 also between 0..255 for good measure;
 * tx_qlen is checked to be non-negative;
 * sync_ratelimit remains as before.

Further changes:
----------------
Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 include/linux/dccp.h |    8 --------
 net/dccp/dccp.h      |    3 ---
 net/dccp/feat.c      |   11 ++++++++---
 net/dccp/feat.h      |    8 ++++++++
 net/dccp/options.c   |    4 ----
 net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
 6 files changed, 46 insertions(+), 31 deletions(-)

--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -100,6 +100,13 @@ struct ccid_dependency {
 	u8	val;
 };
 
+/*
+ * Sysctls to seed defaults for feature negotiation
+ */
+extern unsigned long sysctl_dccp_sequence_window;
+extern int	     sysctl_dccp_rx_ccid;
+extern int	     sysctl_dccp_tx_ccid;
+
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern const char *dccp_feat_typename(const u8 type);
 extern const char *dccp_feat_name(const u8 feat);
@@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
 #endif /* CONFIG_IP_DCCP_DEBUG */
 
 extern int  dccp_feat_init(struct sock *sk);
+extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
 				  u8 const *list, u8 len);
 extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -25,6 +25,11 @@
 #include "ccid.h"
 #include "feat.h"
 
+/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
+unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
+int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
+		sysctl_dccp_tx_ccid	    __read_mostly = 2;
+
 /*
  * Feature activation handlers.
  *
@@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
 
 	/* Non-negotiable (NN) features */
 	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
-				    sysctl_dccp_feat_sequence_window);
+				    sysctl_dccp_sequence_window);
 	if (rc)
 		return rc;
 
@@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
 	if (ccid_request_modules(tx.val, tx.len))
 		goto free_ccid_lists;
 
-	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
-	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
+	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
+	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
 		goto free_ccid_lists;
 
 	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
 extern int  sysctl_dccp_request_retries;
 extern int  sysctl_dccp_retries1;
 extern int  sysctl_dccp_retries2;
-extern int  sysctl_dccp_feat_sequence_window;
-extern int  sysctl_dccp_feat_rx_ccid;
-extern int  sysctl_dccp_feat_tx_ccid;
 extern int  sysctl_dccp_tx_qlen;
 extern int  sysctl_dccp_sync_ratelimit;
 
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
 	return __dccp_hdr_len(dccp_hdr(skb));
 }
 
-
-/* initial values for each feature */
-#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
-#define DCCPF_INITIAL_ACK_RATIO			2
-#define DCCPF_INITIAL_CCID			DCCPC_CCID2
-/* FIXME: for now we're default to 1 but it should really be 0 */
-#define DCCPF_INITIAL_SEND_NDP_COUNT		1
-
 /**
  * struct dccp_request_sock  -  represent DCCP-specific connection request
  * @dreq_inet_rsk: structure inherited from
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -23,10 +23,6 @@
 #include "dccp.h"
 #include "feat.h"
 
-int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
-int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
-int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
-
 u64 dccp_decode_value_var(const u8 *bf, const u8 len)
 {
 	u64 value = 0;
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -18,55 +18,72 @@
 #error This file should not be compiled without CONFIG_SYSCTL defined
 #endif
 
+/* Boundary values */
+static int		zero     = 0,
+			u8_max   = 0xFF;
+static unsigned long	seqw_min = 32;
+
 static struct ctl_table dccp_default_table[] = {
 	{
 		.procname	= "seq_window",
-		.data		= &sysctl_dccp_feat_sequence_window,
-		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
+		.data		= &sysctl_dccp_sequence_window,
+		.maxlen		= sizeof(sysctl_dccp_sequence_window),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_doulongvec_minmax,
+		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
 	},
 	{
 		.procname	= "rx_ccid",
-		.data		= &sysctl_dccp_feat_rx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
+		.data		= &sysctl_dccp_rx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "tx_ccid",
-		.data		= &sysctl_dccp_feat_tx_ccid,
-		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
+		.data		= &sysctl_dccp_tx_ccid,
+		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,		/* RFC 4340, 10. */
 	},
 	{
 		.procname	= "request_retries",
 		.data		= &sysctl_dccp_request_retries,
 		.maxlen		= sizeof(sysctl_dccp_request_retries),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries1",
 		.data		= &sysctl_dccp_retries1,
 		.maxlen		= sizeof(sysctl_dccp_retries1),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "retries2",
 		.data		= &sysctl_dccp_retries2,
 		.maxlen		= sizeof(sysctl_dccp_retries2),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
+		.extra2		= &u8_max,
 	},
 	{
 		.procname	= "tx_qlen",
 		.data		= &sysctl_dccp_tx_qlen,
 		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= &zero,
 	},
 	{
 		.procname	= "sync_ratelimit",

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Debugging functions for feature negotiation
@ 2008-12-13 13:41                                                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: davem; +Cc: dccp, netdev, Gerrit Renker

Since all feature-negotiation processing now takes place in feat.c, functions
for producing verbose debugging output are concentrated there.

New functions to print out values, entry records, and options are provided,
and also a macro is defined to not always have the function name in the
output line.

Thanks to Wei Yongjun and Giuseppe Galeota for help ironing out errors in an
earlier revision of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h    |    2 +
 net/dccp/feat.c    |  153 ++++++++++++++++++++++++++++++++++++----------------
 net/dccp/feat.h    |   13 -----
 net/dccp/options.c |    4 --
 4 files changed, 109 insertions(+), 63 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -42,9 +42,11 @@
 extern int dccp_debug;
 #define dccp_pr_debug(format, a...)	  DCCP_PR_DEBUG(dccp_debug, format, ##a)
 #define dccp_pr_debug_cat(format, a...)   DCCP_PRINTK(dccp_debug, format, ##a)
+#define dccp_debug(fmt, a...)		  dccp_pr_debug_cat(KERN_DEBUG fmt, ##a)
 #else
 #define dccp_pr_debug(format, a...)
 #define dccp_pr_debug_cat(format, a...)
+#define dccp_debug(format, a...)
 #endif
 
 extern struct inet_hashinfo dccp_hashinfo;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -208,6 +208,100 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
+/*
+ *	Debugging and verbose-printing section
+ */
+static const char *dccp_feat_fname(const u8 feat)
+{
+	static const char *feature_names[] = {
+		[DCCPF_RESERVED]	= "Reserved",
+		[DCCPF_CCID]		= "CCID",
+		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
+		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
+		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
+		[DCCPF_ACK_RATIO]	= "Ack Ratio",
+		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
+		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
+		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
+		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
+	};
+	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
+		return feature_names[DCCPF_RESERVED];
+
+	if (feat ==  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
+	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
+		return "CCID-specific";
+
+	return feature_names[feat];
+}
+
+static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
+					 "UNSTABLE", "STABLE" };
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+static const char *dccp_feat_oname(const u8 opt)
+{
+	switch (opt) {
+	case DCCPO_CHANGE_L:  return "Change_L";
+	case DCCPO_CONFIRM_L: return "Confirm_L";
+	case DCCPO_CHANGE_R:  return "Change_R";
+	case DCCPO_CONFIRM_R: return "Confirm_R";
+	}
+	return NULL;
+}
+
+static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
+{
+	u8 i, type = dccp_feat_type(feat_num);
+
+	if (val == NULL || (type == FEAT_SP && val->sp.vec == NULL))
+		dccp_pr_debug_cat("(NULL)");
+	else if (type == FEAT_SP)
+		for (i = 0; i < val->sp.len; i++)
+			dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
+	else if (type == FEAT_NN)
+		dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
+	else
+		dccp_pr_debug_cat("unknown type %u", type);
+}
+
+static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
+{
+	u8 type = dccp_feat_type(feat_num);
+	dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
+
+	if (type == FEAT_NN)
+		fval.nn = dccp_decode_value_var(list, len);
+	dccp_feat_printval(feat_num, &fval);
+}
+
+static void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
+{
+	dccp_debug("   * %s %s = ", entry->is_local ? "local" : "remote",
+				    dccp_feat_fname(entry->feat_num));
+	dccp_feat_printval(entry->feat_num, &entry->val);
+	dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
+			  entry->needs_confirm ? "(Confirm pending)" : "");
+}
+
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)	do {	      \
+	dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
+	dccp_feat_printvals(feat, val, len);				      \
+	dccp_pr_debug_cat(") %s\n", mandatory ? "!" : "");	} while (0)
+
+#define dccp_feat_print_fnlist(fn_list)  {		\
+	const struct dccp_feat_entry *___entry;		\
+							\
+	dccp_pr_debug("List Dump:\n");			\
+	list_for_each_entry(___entry, fn_list, node)	\
+		dccp_feat_print_entry(___entry);	\
+}
+#else	/* ! CONFIG_IP_DCCP_DEBUG */
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
+#define dccp_feat_print_fnlist(fn_list)
+#endif
+
 static int __dccp_feat_activate(struct sock *sk, const int idx,
 				const bool is_local, dccp_feat_val const *fval)
 {
@@ -240,6 +334,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
 	/* Location is RX if this is a local-RX or remote-TX feature */
 	rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
 
+	dccp_debug("   -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
+		   dccp_feat_fname(dccp_feat_table[idx].feat_num),
+		   fval ? "" : "default ",  (unsigned long long)val);
+
 	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
 }
 
@@ -544,6 +642,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
 				return -1;
 			}
 		}
+		dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
 
 		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
 			return -1;
@@ -797,6 +896,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	while (i--)
 		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
 			return -1;
+	dccp_feat_print_fnlist(fn);
 	return 0;
 }
 
@@ -915,6 +1015,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	if (len == 0 || type == FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
 		goto unknown_feature_or_value;
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	/*
 	 *	Negotiation of NN features: Change R is invalid, so there is no
 	 *	simultaneous negotiation; hence we do not look up in the list.
@@ -1020,6 +1122,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	const bool local = (opt == DCCPO_CONFIRM_R);
 	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	if (entry == NULL) {	/* nothing queued: ignore or handle error */
 		if (is_mandatory && type == FEAT_UNKNOWN)
 			return DCCP_RESET_CODE_MANDATORY_ERROR;
@@ -1222,9 +1326,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 			goto activation_failed;
 		}
 		if (cur->state != FEAT_STABLE) {
-			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+			DCCP_CRIT("Negotiation of %s %s failed in state %s",
 				  cur->is_local ? "local" : "remote",
-				  cur->feat_num, cur->state);
+				  dccp_feat_fname(cur->feat_num),
+				  dccp_feat_sname[cur->state]);
 			goto activation_failed;
 		}
 		fvals[idx][cur->is_local] = &cur->val;
@@ -1265,47 +1370,3 @@ activation_failed:
 	dp->dccps_hc_rx_ackvec = NULL;
 	return -1;
 }
-
-#ifdef CONFIG_IP_DCCP_DEBUG
-const char *dccp_feat_typename(const u8 type)
-{
-	switch(type) {
-	case DCCPO_CHANGE_L:  return("ChangeL");
-	case DCCPO_CONFIRM_L: return("ConfirmL");
-	case DCCPO_CHANGE_R:  return("ChangeR");
-	case DCCPO_CONFIRM_R: return("ConfirmR");
-	/* the following case must not appear in feature negotation  */
-	default:	      dccp_pr_debug("unknown type %d [BUG!]\n", type);
-	}
-	return NULL;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_typename);
-
-const char *dccp_feat_name(const u8 feat)
-{
-	static const char *feature_names[] = {
-		[DCCPF_RESERVED]	= "Reserved",
-		[DCCPF_CCID]		= "CCID",
-		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
-		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
-		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
-		[DCCPF_ACK_RATIO]	= "Ack Ratio",
-		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
-		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
-		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
-		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
-	};
-	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
-		return feature_names[DCCPF_RESERVED];
-
-	if (feat ==  DCCPF_SEND_LEV_RATE)
-		return "Send Loss Event Rate";
-	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
-		return "CCID-specific";
-
-	return feature_names[feat];
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_name);
-#endif /* CONFIG_IP_DCCP_DEBUG */
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -107,19 +107,6 @@ extern unsigned long sysctl_dccp_sequence_window;
 extern int	     sysctl_dccp_rx_ccid;
 extern int	     sysctl_dccp_tx_ccid;
 
-#ifdef CONFIG_IP_DCCP_DEBUG
-extern const char *dccp_feat_typename(const u8 type);
-extern const char *dccp_feat_name(const u8 feat);
-
-static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
-{
-	dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type),
-					   dccp_feat_name(feat), feat, val);
-}
-#else
-#define dccp_feat_debug(type, feat, val)
-#endif /* CONFIG_IP_DCCP_DEBUG */
-
 extern int  dccp_feat_init(struct sock *sk);
 extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -498,10 +498,6 @@ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
 		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
-
-	dccp_pr_debug("%s(%s (%d), ...), length %d\n",
-		      dccp_feat_typename(type),
-		      dccp_feat_name(feat), feat, len);
 	return 0;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* [PATCH 5/5] dccp: Debugging functions for feature negotiation
@ 2008-12-13 13:41                                                                                                     ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 13:41 UTC (permalink / raw)
  To: dccp

Since all feature-negotiation processing now takes place in feat.c, functions
for producing verbose debugging output are concentrated there.

New functions to print out values, entry records, and options are provided,
and also a macro is defined to not always have the function name in the
output line.

Thanks to Wei Yongjun and Giuseppe Galeota for help ironing out errors in an
earlier revision of this patch.

Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
---
 net/dccp/dccp.h    |    2 +
 net/dccp/feat.c    |  153 ++++++++++++++++++++++++++++++++++++----------------
 net/dccp/feat.h    |   13 -----
 net/dccp/options.c |    4 --
 4 files changed, 109 insertions(+), 63 deletions(-)

--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -42,9 +42,11 @@
 extern int dccp_debug;
 #define dccp_pr_debug(format, a...)	  DCCP_PR_DEBUG(dccp_debug, format, ##a)
 #define dccp_pr_debug_cat(format, a...)   DCCP_PRINTK(dccp_debug, format, ##a)
+#define dccp_debug(fmt, a...)		  dccp_pr_debug_cat(KERN_DEBUG fmt, ##a)
 #else
 #define dccp_pr_debug(format, a...)
 #define dccp_pr_debug_cat(format, a...)
+#define dccp_debug(format, a...)
 #endif
 
 extern struct inet_hashinfo dccp_hashinfo;
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -208,6 +208,100 @@ static int dccp_feat_default_value(u8 feat_num)
 	return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
 }
 
+/*
+ *	Debugging and verbose-printing section
+ */
+static const char *dccp_feat_fname(const u8 feat)
+{
+	static const char *feature_names[] = {
+		[DCCPF_RESERVED]	= "Reserved",
+		[DCCPF_CCID]		= "CCID",
+		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
+		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
+		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
+		[DCCPF_ACK_RATIO]	= "Ack Ratio",
+		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
+		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
+		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
+		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
+	};
+	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
+		return feature_names[DCCPF_RESERVED];
+
+	if (feat =  DCCPF_SEND_LEV_RATE)
+		return "Send Loss Event Rate";
+	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
+		return "CCID-specific";
+
+	return feature_names[feat];
+}
+
+static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
+					 "UNSTABLE", "STABLE" };
+
+#ifdef CONFIG_IP_DCCP_DEBUG
+static const char *dccp_feat_oname(const u8 opt)
+{
+	switch (opt) {
+	case DCCPO_CHANGE_L:  return "Change_L";
+	case DCCPO_CONFIRM_L: return "Confirm_L";
+	case DCCPO_CHANGE_R:  return "Change_R";
+	case DCCPO_CONFIRM_R: return "Confirm_R";
+	}
+	return NULL;
+}
+
+static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
+{
+	u8 i, type = dccp_feat_type(feat_num);
+
+	if (val = NULL || (type = FEAT_SP && val->sp.vec = NULL))
+		dccp_pr_debug_cat("(NULL)");
+	else if (type = FEAT_SP)
+		for (i = 0; i < val->sp.len; i++)
+			dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
+	else if (type = FEAT_NN)
+		dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
+	else
+		dccp_pr_debug_cat("unknown type %u", type);
+}
+
+static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
+{
+	u8 type = dccp_feat_type(feat_num);
+	dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
+
+	if (type = FEAT_NN)
+		fval.nn = dccp_decode_value_var(list, len);
+	dccp_feat_printval(feat_num, &fval);
+}
+
+static void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
+{
+	dccp_debug("   * %s %s = ", entry->is_local ? "local" : "remote",
+				    dccp_feat_fname(entry->feat_num));
+	dccp_feat_printval(entry->feat_num, &entry->val);
+	dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
+			  entry->needs_confirm ? "(Confirm pending)" : "");
+}
+
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)	do {	      \
+	dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
+	dccp_feat_printvals(feat, val, len);				      \
+	dccp_pr_debug_cat(") %s\n", mandatory ? "!" : "");	} while (0)
+
+#define dccp_feat_print_fnlist(fn_list)  {		\
+	const struct dccp_feat_entry *___entry;		\
+							\
+	dccp_pr_debug("List Dump:\n");			\
+	list_for_each_entry(___entry, fn_list, node)	\
+		dccp_feat_print_entry(___entry);	\
+}
+#else	/* ! CONFIG_IP_DCCP_DEBUG */
+#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
+#define dccp_feat_print_fnlist(fn_list)
+#endif
+
 static int __dccp_feat_activate(struct sock *sk, const int idx,
 				const bool is_local, dccp_feat_val const *fval)
 {
@@ -240,6 +334,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
 	/* Location is RX if this is a local-RX or remote-TX feature */
 	rx = (is_local = (dccp_feat_table[idx].rxtx = FEAT_AT_RX));
 
+	dccp_debug("   -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
+		   dccp_feat_fname(dccp_feat_table[idx].feat_num),
+		   fval ? "" : "default ",  (unsigned long long)val);
+
 	return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
 }
 
@@ -544,6 +642,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
 				return -1;
 			}
 		}
+		dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
 
 		if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
 			return -1;
@@ -797,6 +896,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
 	while (i--)
 		if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
 			return -1;
+	dccp_feat_print_fnlist(fn);
 	return 0;
 }
 
@@ -915,6 +1015,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	if (len = 0 || type = FEAT_UNKNOWN)		/* 6.1 and 6.6.8 */
 		goto unknown_feature_or_value;
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	/*
 	 *	Negotiation of NN features: Change R is invalid, so there is no
 	 *	simultaneous negotiation; hence we do not look up in the list.
@@ -1020,6 +1122,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
 	const bool local = (opt = DCCPO_CONFIRM_R);
 	struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
 
+	dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
+
 	if (entry = NULL) {	/* nothing queued: ignore or handle error */
 		if (is_mandatory && type = FEAT_UNKNOWN)
 			return DCCP_RESET_CODE_MANDATORY_ERROR;
@@ -1222,9 +1326,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
 			goto activation_failed;
 		}
 		if (cur->state != FEAT_STABLE) {
-			DCCP_CRIT("Negotiation of %s %u failed in state %u",
+			DCCP_CRIT("Negotiation of %s %s failed in state %s",
 				  cur->is_local ? "local" : "remote",
-				  cur->feat_num, cur->state);
+				  dccp_feat_fname(cur->feat_num),
+				  dccp_feat_sname[cur->state]);
 			goto activation_failed;
 		}
 		fvals[idx][cur->is_local] = &cur->val;
@@ -1265,47 +1370,3 @@ activation_failed:
 	dp->dccps_hc_rx_ackvec = NULL;
 	return -1;
 }
-
-#ifdef CONFIG_IP_DCCP_DEBUG
-const char *dccp_feat_typename(const u8 type)
-{
-	switch(type) {
-	case DCCPO_CHANGE_L:  return("ChangeL");
-	case DCCPO_CONFIRM_L: return("ConfirmL");
-	case DCCPO_CHANGE_R:  return("ChangeR");
-	case DCCPO_CONFIRM_R: return("ConfirmR");
-	/* the following case must not appear in feature negotation  */
-	default:	      dccp_pr_debug("unknown type %d [BUG!]\n", type);
-	}
-	return NULL;
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_typename);
-
-const char *dccp_feat_name(const u8 feat)
-{
-	static const char *feature_names[] = {
-		[DCCPF_RESERVED]	= "Reserved",
-		[DCCPF_CCID]		= "CCID",
-		[DCCPF_SHORT_SEQNOS]	= "Allow Short Seqnos",
-		[DCCPF_SEQUENCE_WINDOW]	= "Sequence Window",
-		[DCCPF_ECN_INCAPABLE]	= "ECN Incapable",
-		[DCCPF_ACK_RATIO]	= "Ack Ratio",
-		[DCCPF_SEND_ACK_VECTOR]	= "Send ACK Vector",
-		[DCCPF_SEND_NDP_COUNT]	= "Send NDP Count",
-		[DCCPF_MIN_CSUM_COVER]	= "Min. Csum Coverage",
-		[DCCPF_DATA_CHECKSUM]	= "Send Data Checksum",
-	};
-	if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
-		return feature_names[DCCPF_RESERVED];
-
-	if (feat =  DCCPF_SEND_LEV_RATE)
-		return "Send Loss Event Rate";
-	if (feat >= DCCPF_MIN_CCID_SPECIFIC)
-		return "CCID-specific";
-
-	return feature_names[feat];
-}
-
-EXPORT_SYMBOL_GPL(dccp_feat_name);
-#endif /* CONFIG_IP_DCCP_DEBUG */
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -107,19 +107,6 @@ extern unsigned long sysctl_dccp_sequence_window;
 extern int	     sysctl_dccp_rx_ccid;
 extern int	     sysctl_dccp_tx_ccid;
 
-#ifdef CONFIG_IP_DCCP_DEBUG
-extern const char *dccp_feat_typename(const u8 type);
-extern const char *dccp_feat_name(const u8 feat);
-
-static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
-{
-	dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type),
-					   dccp_feat_name(feat), feat, val);
-}
-#else
-#define dccp_feat_debug(type, feat, val)
-#endif /* CONFIG_IP_DCCP_DEBUG */
-
 extern int  dccp_feat_init(struct sock *sk);
 extern void dccp_feat_initialise_sysctls(void);
 extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -498,10 +498,6 @@ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
 		*to++ = *val;
 	if (len)
 		memcpy(to, val, len);
-
-	dccp_pr_debug("%s(%s (%d), ...), length %d\n",
-		      dccp_feat_typename(type),
-		      dccp_feat_name(feat), feat, len);
 	return 0;
 }
 

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-13 13:55                                                                                                 ` Michał Mirosław
  -1 siblings, 0 replies; 484+ messages in thread
From: Michał Mirosław @ 2008-12-13 13:55 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev

2008/12/13 Gerrit Renker <gerrit@erg.abdn.ac.uk>:
> +/**
> + * ccid_request_module  -  Pre-load CCID module for later use
> + * This should be called only from process context (e.g. during connection
> + * setup) and is necessary for later calls to ccid_new (typically in software
> + * interrupt), so that it has the modules available when they are needed.
> + */
> +static int ccid_request_module(u8 id)
> +{
> +       if (!in_atomic()) {
> +               ccids_read_lock();
> +               if (ccids[id] == NULL) {
> +                       ccids_read_unlock();
> +                       return request_module("net-dccp-ccid-%d", id);
> +               }
> +               ccids_read_unlock();
> +       }
> +       return 0;
> +}

Just a random thought: does this lock really do anything useful here?

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-12-13 13:55                                                                                                 ` Michał Mirosław
  0 siblings, 0 replies; 484+ messages in thread
From: Michał Mirosław @ 2008-12-13 13:55 UTC (permalink / raw)
  To: dccp

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 959 bytes --]

2008/12/13 Gerrit Renker <gerrit@erg.abdn.ac.uk>:
> +/**
> + * ccid_request_module  -  Pre-load CCID module for later use
> + * This should be called only from process context (e.g. during connection
> + * setup) and is necessary for later calls to ccid_new (typically in software
> + * interrupt), so that it has the modules available when they are needed.
> + */
> +static int ccid_request_module(u8 id)
> +{
> +       if (!in_atomic()) {
> +               ccids_read_lock();
> +               if (ccids[id] = NULL) {
> +                       ccids_read_unlock();
> +                       return request_module("net-dccp-ccid-%d", id);
> +               }
> +               ccids_read_unlock();
> +       }
> +       return 0;
> +}

Just a random thought: does this lock really do anything useful here?

Best Regards,
Micha³ Miros³aw
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·qÊÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-13 14:56                                                                                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 14:56 UTC (permalink / raw)
  To: Micha? Miros?aw; +Cc: davem, dccp, netdev

| > +static int ccid_request_module(u8 id)
| > +{
| > +       if (!in_atomic()) {
| > +               ccids_read_lock();
| > +               if (ccids[id] == NULL) {
| > +                       ccids_read_unlock();
| > +                       return request_module("net-dccp-ccid-%d", id);
| > +               }
| > +               ccids_read_unlock();
| > +       }
| > +       return 0;
| > +}
| 
| Just a random thought: does this lock really do anything useful here?
| 
Reading the (shared) 'ccids' array is the solution chosen to check whether
the module for CCID with number 'id' is already loaded.

It would be bad to call request_module() each time a new DCCP socket is
opened. Using the 'ccids' array may not be the only way to check whether
a given module (whose name depends on the value of 'id') is loaded. 

But if this solution is chosen, then it requires to protect the read
access to 'ccids', which is shared among all DCCP sockets.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-13 14:56                                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-13 14:56 UTC (permalink / raw)
  To: dccp

| > +static int ccid_request_module(u8 id)
| > +{
| > +       if (!in_atomic()) {
| > +               ccids_read_lock();
| > +               if (ccids[id] = NULL) {
| > +                       ccids_read_unlock();
| > +                       return request_module("net-dccp-ccid-%d", id);
| > +               }
| > +               ccids_read_unlock();
| > +       }
| > +       return 0;
| > +}
| 
| Just a random thought: does this lock really do anything useful here?
| 
Reading the (shared) 'ccids' array is the solution chosen to check whether
the module for CCID with number 'id' is already loaded.

It would be bad to call request_module() each time a new DCCP socket is
opened. Using the 'ccids' array may not be the only way to check whether
a given module (whose name depends on the value of 'id') is loaded. 

But if this solution is chosen, then it requires to protect the read
access to 'ccids', which is shared among all DCCP sockets.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-14 14:50                                                                                                     ` Michał Mirosław
  -1 siblings, 0 replies; 484+ messages in thread
From: Michał Mirosław @ 2008-12-14 14:50 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev

2008/12/13 Gerrit Renker <gerrit@erg.abdn.ac.uk>:
> | > +static int ccid_request_module(u8 id)
> | > +{
> | > +       if (!in_atomic()) {
> | > +               ccids_read_lock();
> | > +               if (ccids[id] == NULL) {
> | > +                       ccids_read_unlock();
> | > +                       return request_module("net-dccp-ccid-%d", id);
> | > +               }
> | > +               ccids_read_unlock();
> | > +       }
> | > +       return 0;
> | > +}
> |
> | Just a random thought: does this lock really do anything useful here?
> |
> Reading the (shared) 'ccids' array is the solution chosen to check whether
> the module for CCID with number 'id' is already loaded.
>
> It would be bad to call request_module() each time a new DCCP socket is
> opened. Using the 'ccids' array may not be the only way to check whether
> a given module (whose name depends on the value of 'id') is loaded.
>
> But if this solution is chosen, then it requires to protect the read
> access to 'ccids', which is shared among all DCCP sockets.

Since the lock is dropped after checking ccids[id] then there's
a window where multiple request_module()s can be called if multiple
applications create a DCCP socket at a same time. The code below
should do the same without a lock (ccids is a static array,
so ccids[N] is always at the same place).

static int ccid_request_module(u8 id)
{
       if (!in_atomic()) {
               rmb();
               if (ccids[id] == NULL)
                       return request_module("net-dccp-ccid-%d", id);
       }
       return 0;
}

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-12-14 14:50                                                                                                     ` Michał Mirosław
  0 siblings, 0 replies; 484+ messages in thread
From: Michał Mirosław @ 2008-12-14 14:50 UTC (permalink / raw)
  To: dccp

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 1718 bytes --]

2008/12/13 Gerrit Renker <gerrit@erg.abdn.ac.uk>:
> | > +static int ccid_request_module(u8 id)
> | > +{
> | > +       if (!in_atomic()) {
> | > +               ccids_read_lock();
> | > +               if (ccids[id] = NULL) {
> | > +                       ccids_read_unlock();
> | > +                       return request_module("net-dccp-ccid-%d", id);
> | > +               }
> | > +               ccids_read_unlock();
> | > +       }
> | > +       return 0;
> | > +}
> |
> | Just a random thought: does this lock really do anything useful here?
> |
> Reading the (shared) 'ccids' array is the solution chosen to check whether
> the module for CCID with number 'id' is already loaded.
>
> It would be bad to call request_module() each time a new DCCP socket is
> opened. Using the 'ccids' array may not be the only way to check whether
> a given module (whose name depends on the value of 'id') is loaded.
>
> But if this solution is chosen, then it requires to protect the read
> access to 'ccids', which is shared among all DCCP sockets.

Since the lock is dropped after checking ccids[id] then there's
a window where multiple request_module()s can be called if multiple
applications create a DCCP socket at a same time. The code below
should do the same without a lock (ccids is a static array,
so ccids[N] is always at the same place).

static int ccid_request_module(u8 id)
{
       if (!in_atomic()) {
               rmb();
               if (ccids[id] = NULL)
                       return request_module("net-dccp-ccid-%d", id);
       }
       return 0;
}

Best Regards,
Micha³ Miros³aw
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·qÊÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-15 13:48                                                                                                 ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-15 13:48 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev

Em Sat, Dec 13, 2008 at 02:41:22PM +0100, Gerrit Renker escreveu:
> This adds auto-loading of CCIDs (when module loading is enabled)
> for the purpose of feature negotiation.
> 
> The problem with loading the CCIDs at the end of feature negotiation is
> that this would happen in software interrupt context. Besides, if the host
> advertises CCIDs during negotiation, it should have them ready to use, in
> case an agreeing peer wants to use it for the connection.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ccid.h |    1 +
>  net/dccp/ccid.c |   39 +++++++++++++++++++++++++++++----------
>  net/dccp/feat.c |    5 +++++
>  3 files changed, 35 insertions(+), 10 deletions(-)
> 
> --- a/net/dccp/ccid.h
> +++ b/net/dccp/ccid.h
> @@ -108,6 +108,7 @@ extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
>  extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
>  					  char __user *, int __user *);
>  
> +extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
>  extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
>  			     gfp_t gfp);
>  
> --- a/net/dccp/ccid.c
> +++ b/net/dccp/ccid.c
> @@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops)
>  
>  EXPORT_SYMBOL_GPL(ccid_unregister);
>  
> +/**
> + * ccid_request_module  -  Pre-load CCID module for later use
> + * This should be called only from process context (e.g. during connection
> + * setup) and is necessary for later calls to ccid_new (typically in software
> + * interrupt), so that it has the modules available when they are needed.
> + */
> +static int ccid_request_module(u8 id)
> +{
> +	if (!in_atomic()) {

Shouldn't the above be in a BUG_ON? It looks strange to simply refuse to
do that and return OK. 

> +		ccids_read_lock();
> +		if (ccids[id] == NULL) {
> +			ccids_read_unlock();
> +			return request_module("net-dccp-ccid-%d", id);
> +		}
> +		ccids_read_unlock();
> +	}
> +	return 0;
> +}
> +
> +int ccid_request_modules(u8 const *ccid_array, u8 array_len)
> +{
> +#ifdef CONFIG_MODULES
> +	while (array_len--)
> +		if (ccid_request_module(ccid_array[array_len]))
> +			return -1;
> +#endif
> +	return 0;
> +}
> +
>  struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
>  {
>  	struct ccid_operations *ccid_ops;
>  	struct ccid *ccid = NULL;
>  
>  	ccids_read_lock();
> -#ifdef CONFIG_MODULES
> -	if (ccids[id] == NULL) {
> -		/* We only try to load if in process context */
> -		ccids_read_unlock();
> -		if (gfp & GFP_ATOMIC)
> -			goto out;
> -		request_module("net-dccp-ccid-%d", id);
> -		ccids_read_lock();
> -	}
> -#endif
>  	ccid_ops = ccids[id];
>  	if (ccid_ops == NULL)
>  		goto out_unlock;
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -1163,6 +1163,11 @@ int dccp_feat_init(struct sock *sk)
>  	    ccid_get_builtin_ccids(&rx.val, &rx.len))
>  		return -ENOBUFS;
>  
> +	/* Pre-load all CCID modules that are going to be advertised */
> +	rc = -EUNATCH;
> +	if (ccid_request_modules(tx.val, tx.len))
> +		goto free_ccid_lists;
> +
>  	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
>  	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
>  		goto free_ccid_lists;
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-15 13:48                                                                                                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-15 13:48 UTC (permalink / raw)
  To: dccp

Em Sat, Dec 13, 2008 at 02:41:22PM +0100, Gerrit Renker escreveu:
> This adds auto-loading of CCIDs (when module loading is enabled)
> for the purpose of feature negotiation.
> 
> The problem with loading the CCIDs at the end of feature negotiation is
> that this would happen in software interrupt context. Besides, if the host
> advertises CCIDs during negotiation, it should have them ready to use, in
> case an agreeing peer wants to use it for the connection.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Signed-off-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  net/dccp/ccid.h |    1 +
>  net/dccp/ccid.c |   39 +++++++++++++++++++++++++++++----------
>  net/dccp/feat.c |    5 +++++
>  3 files changed, 35 insertions(+), 10 deletions(-)
> 
> --- a/net/dccp/ccid.h
> +++ b/net/dccp/ccid.h
> @@ -108,6 +108,7 @@ extern int  ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len);
>  extern int  ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
>  					  char __user *, int __user *);
>  
> +extern int    ccid_request_modules(u8 const *ccid_array, u8 array_len);
>  extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx,
>  			     gfp_t gfp);
>  
> --- a/net/dccp/ccid.c
> +++ b/net/dccp/ccid.c
> @@ -196,22 +196,41 @@ int ccid_unregister(struct ccid_operations *ccid_ops)
>  
>  EXPORT_SYMBOL_GPL(ccid_unregister);
>  
> +/**
> + * ccid_request_module  -  Pre-load CCID module for later use
> + * This should be called only from process context (e.g. during connection
> + * setup) and is necessary for later calls to ccid_new (typically in software
> + * interrupt), so that it has the modules available when they are needed.
> + */
> +static int ccid_request_module(u8 id)
> +{
> +	if (!in_atomic()) {

Shouldn't the above be in a BUG_ON? It looks strange to simply refuse to
do that and return OK. 

> +		ccids_read_lock();
> +		if (ccids[id] = NULL) {
> +			ccids_read_unlock();
> +			return request_module("net-dccp-ccid-%d", id);
> +		}
> +		ccids_read_unlock();
> +	}
> +	return 0;
> +}
> +
> +int ccid_request_modules(u8 const *ccid_array, u8 array_len)
> +{
> +#ifdef CONFIG_MODULES
> +	while (array_len--)
> +		if (ccid_request_module(ccid_array[array_len]))
> +			return -1;
> +#endif
> +	return 0;
> +}
> +
>  struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp)
>  {
>  	struct ccid_operations *ccid_ops;
>  	struct ccid *ccid = NULL;
>  
>  	ccids_read_lock();
> -#ifdef CONFIG_MODULES
> -	if (ccids[id] = NULL) {
> -		/* We only try to load if in process context */
> -		ccids_read_unlock();
> -		if (gfp & GFP_ATOMIC)
> -			goto out;
> -		request_module("net-dccp-ccid-%d", id);
> -		ccids_read_lock();
> -	}
> -#endif
>  	ccid_ops = ccids[id];
>  	if (ccid_ops = NULL)
>  		goto out_unlock;
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -1163,6 +1163,11 @@ int dccp_feat_init(struct sock *sk)
>  	    ccid_get_builtin_ccids(&rx.val, &rx.len))
>  		return -ENOBUFS;
>  
> +	/* Pre-load all CCID modules that are going to be advertised */
> +	rc = -EUNATCH;
> +	if (ccid_request_modules(tx.val, tx.len))
> +		goto free_ccid_lists;
> +
>  	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
>  	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
>  		goto free_ccid_lists;
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls
  2008-12-13 13:41                                                                                                   ` Gerrit Renker
  (?)
@ 2008-12-15 14:15                                                                                                     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-15 14:15 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev, Kernel Janitors

Em Sat, Dec 13, 2008 at 02:41:24PM +0100, Gerrit Renker escreveu:
> This patch takes care of initialising and type-checking sysctls related to
> feature negotiation. Type checking is important since some of the sysctls
> now directly act on the feature-negotiation process.
> 
> The sysctls are initialised with the known default values for each feature.
> For the type-checking the value constraints from RFC 4340 are used:
> 
>  * Sequence Window uses the specified Wmin=32, the maximum is ulong (4 bytes),
>    tested and confirmed that it works up to 4294967295 - for Gbps speed;
>  * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
>  * CCIDs are between 0 .. 255;
>  * request_retries, retries1, retries2 also between 0..255 for good measure;
>  * tx_qlen is checked to be non-negative;
>  * sync_ratelimit remains as before.
> 
> Further changes:
> ----------------
> Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    8 --------
>  net/dccp/dccp.h      |    3 ---
>  net/dccp/feat.c      |   11 ++++++++---
>  net/dccp/feat.h      |    8 ++++++++
>  net/dccp/options.c   |    4 ----
>  net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
>  6 files changed, 46 insertions(+), 31 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -100,6 +100,13 @@ struct ccid_dependency {
>  	u8	val;
>  };
>  
> +/*
> + * Sysctls to seed defaults for feature negotiation
> + */
> +extern unsigned long sysctl_dccp_sequence_window;
> +extern int	     sysctl_dccp_rx_ccid;
> +extern int	     sysctl_dccp_tx_ccid;
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  extern const char *dccp_feat_typename(const u8 type);
>  extern const char *dccp_feat_name(const u8 feat);
> @@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
>  #endif /* CONFIG_IP_DCCP_DEBUG */
>  
>  extern int  dccp_feat_init(struct sock *sk);
> +extern void dccp_feat_initialise_sysctls(void);
>  extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
>  				  u8 const *list, u8 len);
>  extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -25,6 +25,11 @@
>  #include "ccid.h"
>  #include "feat.h"
>  
> +/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
> +unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
> +int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
> +		sysctl_dccp_tx_ccid	    __read_mostly = 2;
> +
>  /*
>   * Feature activation handlers.
>   *
> @@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
>  
>  	/* Non-negotiable (NN) features */
>  	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
> -				    sysctl_dccp_feat_sequence_window);
> +				    sysctl_dccp_sequence_window);
>  	if (rc)
>  		return rc;
>  
> @@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
>  	if (ccid_request_modules(tx.val, tx.len))
>  		goto free_ccid_lists;
>  
> -	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
> -	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
> +	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
> +	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
>  		goto free_ccid_lists;
>  
>  	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
>  extern int  sysctl_dccp_request_retries;
>  extern int  sysctl_dccp_retries1;
>  extern int  sysctl_dccp_retries2;
> -extern int  sysctl_dccp_feat_sequence_window;
> -extern int  sysctl_dccp_feat_rx_ccid;
> -extern int  sysctl_dccp_feat_tx_ccid;
>  extern int  sysctl_dccp_tx_qlen;
>  extern int  sysctl_dccp_sync_ratelimit;
>  
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>  	return __dccp_hdr_len(dccp_hdr(skb));
>  }
>  
> -
> -/* initial values for each feature */
> -#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
> -#define DCCPF_INITIAL_ACK_RATIO			2
> -#define DCCPF_INITIAL_CCID			DCCPC_CCID2
> -/* FIXME: for now we're default to 1 but it should really be 0 */
> -#define DCCPF_INITIAL_SEND_NDP_COUNT		1
> -
>  /**
>   * struct dccp_request_sock  -  represent DCCP-specific connection request
>   * @dreq_inet_rsk: structure inherited from
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -23,10 +23,6 @@
>  #include "dccp.h"
>  #include "feat.h"
>  
> -int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
> -int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
> -int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
> -
>  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>  {
>  	u64 value = 0;
> --- a/net/dccp/sysctl.c
> +++ b/net/dccp/sysctl.c
> @@ -18,55 +18,72 @@
>  #error This file should not be compiled without CONFIG_SYSCTL defined
>  #endif
>  
> +/* Boundary values */
> +static int		zero     = 0,
> +			u8_max   = 0xFF;

I wonder if these aren't available for wider use... some files have it:

./kernel/sysctl.c
./fs/inotify_user.c
./net/sunrpc/xprtrdma/transport.c
./net/ipv4/ip_fragment.c
./net/ipv4/sysctl_net_ipv4.c
./net/sctp/sysctl.c (well, this one also does the not needed '= 0' :) */

static int zero;

Some others, such as ./net/netrom/sysctl_net_netrom.c, could also use it

And one, etc, and it seems some people are even more crazy about saving
some bytes:

/* Constants used for minimum and  maximum */
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
static int one = 1;
#endif

Unsure if the cost of exporting this to modules will do us good tho...

Perhaps some janitor may be interested in doing some measurements and
looking at u8_max (int_max, etc) too? :-)

Other than that:

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

- Arnaldo

> +static unsigned long	seqw_min = 32;
> +
>  static struct ctl_table dccp_default_table[] = {
>  	{
>  		.procname	= "seq_window",
> -		.data		= &sysctl_dccp_feat_sequence_window,
> -		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
> +		.data		= &sysctl_dccp_sequence_window,
> +		.maxlen		= sizeof(sysctl_dccp_sequence_window),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_doulongvec_minmax,
> +		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
>  	},
>  	{
>  		.procname	= "rx_ccid",
> -		.data		= &sysctl_dccp_feat_rx_ccid,
> -		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
> +		.data		= &sysctl_dccp_rx_ccid,
> +		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,		/* RFC 4340, 10. */
>  	},
>  	{
>  		.procname	= "tx_ccid",
> -		.data		= &sysctl_dccp_feat_tx_ccid,
> -		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
> +		.data		= &sysctl_dccp_tx_ccid,
> +		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,		/* RFC 4340, 10. */
>  	},
>  	{
>  		.procname	= "request_retries",
>  		.data		= &sysctl_dccp_request_retries,
>  		.maxlen		= sizeof(sysctl_dccp_request_retries),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "retries1",
>  		.data		= &sysctl_dccp_retries1,
>  		.maxlen		= sizeof(sysctl_dccp_retries1),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "retries2",
>  		.data		= &sysctl_dccp_retries2,
>  		.maxlen		= sizeof(sysctl_dccp_retries2),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "tx_qlen",
>  		.data		= &sysctl_dccp_tx_qlen,
>  		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
>  	},
>  	{
>  		.procname	= "sync_ratelimit",
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Initialisation and type-checking of feature
@ 2008-12-15 14:15                                                                                                     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-15 14:15 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev, Kernel Janitors

Em Sat, Dec 13, 2008 at 02:41:24PM +0100, Gerrit Renker escreveu:
> This patch takes care of initialising and type-checking sysctls related to
> feature negotiation. Type checking is important since some of the sysctls
> now directly act on the feature-negotiation process.
> 
> The sysctls are initialised with the known default values for each feature.
> For the type-checking the value constraints from RFC 4340 are used:
> 
>  * Sequence Window uses the specified Wmin2, the maximum is ulong (4 bytes),
>    tested and confirmed that it works up to 4294967295 - for Gbps speed;
>  * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
>  * CCIDs are between 0 .. 255;
>  * request_retries, retries1, retries2 also between 0..255 for good measure;
>  * tx_qlen is checked to be non-negative;
>  * sync_ratelimit remains as before.
> 
> Further changes:
> ----------------
> Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    8 --------
>  net/dccp/dccp.h      |    3 ---
>  net/dccp/feat.c      |   11 ++++++++---
>  net/dccp/feat.h      |    8 ++++++++
>  net/dccp/options.c   |    4 ----
>  net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
>  6 files changed, 46 insertions(+), 31 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -100,6 +100,13 @@ struct ccid_dependency {
>  	u8	val;
>  };
>  
> +/*
> + * Sysctls to seed defaults for feature negotiation
> + */
> +extern unsigned long sysctl_dccp_sequence_window;
> +extern int	     sysctl_dccp_rx_ccid;
> +extern int	     sysctl_dccp_tx_ccid;
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  extern const char *dccp_feat_typename(const u8 type);
>  extern const char *dccp_feat_name(const u8 feat);
> @@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
>  #endif /* CONFIG_IP_DCCP_DEBUG */
>  
>  extern int  dccp_feat_init(struct sock *sk);
> +extern void dccp_feat_initialise_sysctls(void);
>  extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
>  				  u8 const *list, u8 len);
>  extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -25,6 +25,11 @@
>  #include "ccid.h"
>  #include "feat.h"
>  
> +/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
> +unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
> +int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
> +		sysctl_dccp_tx_ccid	    __read_mostly = 2;
> +
>  /*
>   * Feature activation handlers.
>   *
> @@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
>  
>  	/* Non-negotiable (NN) features */
>  	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
> -				    sysctl_dccp_feat_sequence_window);
> +				    sysctl_dccp_sequence_window);
>  	if (rc)
>  		return rc;
>  
> @@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
>  	if (ccid_request_modules(tx.val, tx.len))
>  		goto free_ccid_lists;
>  
> -	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
> -	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
> +	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
> +	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
>  		goto free_ccid_lists;
>  
>  	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
>  extern int  sysctl_dccp_request_retries;
>  extern int  sysctl_dccp_retries1;
>  extern int  sysctl_dccp_retries2;
> -extern int  sysctl_dccp_feat_sequence_window;
> -extern int  sysctl_dccp_feat_rx_ccid;
> -extern int  sysctl_dccp_feat_tx_ccid;
>  extern int  sysctl_dccp_tx_qlen;
>  extern int  sysctl_dccp_sync_ratelimit;
>  
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>  	return __dccp_hdr_len(dccp_hdr(skb));
>  }
>  
> -
> -/* initial values for each feature */
> -#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
> -#define DCCPF_INITIAL_ACK_RATIO			2
> -#define DCCPF_INITIAL_CCID			DCCPC_CCID2
> -/* FIXME: for now we're default to 1 but it should really be 0 */
> -#define DCCPF_INITIAL_SEND_NDP_COUNT		1
> -
>  /**
>   * struct dccp_request_sock  -  represent DCCP-specific connection request
>   * @dreq_inet_rsk: structure inherited from
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -23,10 +23,6 @@
>  #include "dccp.h"
>  #include "feat.h"
>  
> -int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
> -int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
> -int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
> -
>  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>  {
>  	u64 value = 0;
> --- a/net/dccp/sysctl.c
> +++ b/net/dccp/sysctl.c
> @@ -18,55 +18,72 @@
>  #error This file should not be compiled without CONFIG_SYSCTL defined
>  #endif
>  
> +/* Boundary values */
> +static int		zero     = 0,
> +			u8_max   = 0xFF;

I wonder if these aren't available for wider use... some files have it:

./kernel/sysctl.c
./fs/inotify_user.c
./net/sunrpc/xprtrdma/transport.c
./net/ipv4/ip_fragment.c
./net/ipv4/sysctl_net_ipv4.c
./net/sctp/sysctl.c (well, this one also does the not needed '= 0' :) */

static int zero;

Some others, such as ./net/netrom/sysctl_net_netrom.c, could also use it

And one, etc, and it seems some people are even more crazy about saving
some bytes:

/* Constants used for minimum and  maximum */
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
static int one = 1;
#endif

Unsure if the cost of exporting this to modules will do us good tho...

Perhaps some janitor may be interested in doing some measurements and
looking at u8_max (int_max, etc) too? :-)

Other than that:

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

- Arnaldo

> +static unsigned long	seqw_min = 32;
> +
>  static struct ctl_table dccp_default_table[] = {
>  	{
>  		.procname	= "seq_window",
> -		.data		= &sysctl_dccp_feat_sequence_window,
> -		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
> +		.data		= &sysctl_dccp_sequence_window,
> +		.maxlen		= sizeof(sysctl_dccp_sequence_window),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_doulongvec_minmax,
> +		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
>  	},
>  	{
>  		.procname	= "rx_ccid",
> -		.data		= &sysctl_dccp_feat_rx_ccid,
> -		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
> +		.data		= &sysctl_dccp_rx_ccid,
> +		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,		/* RFC 4340, 10. */
>  	},
>  	{
>  		.procname	= "tx_ccid",
> -		.data		= &sysctl_dccp_feat_tx_ccid,
> -		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
> +		.data		= &sysctl_dccp_tx_ccid,
> +		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,		/* RFC 4340, 10. */
>  	},
>  	{
>  		.procname	= "request_retries",
>  		.data		= &sysctl_dccp_request_retries,
>  		.maxlen		= sizeof(sysctl_dccp_request_retries),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "retries1",
>  		.data		= &sysctl_dccp_retries1,
>  		.maxlen		= sizeof(sysctl_dccp_retries1),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "retries2",
>  		.data		= &sysctl_dccp_retries2,
>  		.maxlen		= sizeof(sysctl_dccp_retries2),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "tx_qlen",
>  		.data		= &sysctl_dccp_tx_qlen,
>  		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
>  	},
>  	{
>  		.procname	= "sync_ratelimit",
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Initialisation and type-checking of feature
@ 2008-12-15 14:15                                                                                                     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-15 14:15 UTC (permalink / raw)
  To: dccp

Em Sat, Dec 13, 2008 at 02:41:24PM +0100, Gerrit Renker escreveu:
> This patch takes care of initialising and type-checking sysctls related to
> feature negotiation. Type checking is important since some of the sysctls
> now directly act on the feature-negotiation process.
> 
> The sysctls are initialised with the known default values for each feature.
> For the type-checking the value constraints from RFC 4340 are used:
> 
>  * Sequence Window uses the specified Wmin2, the maximum is ulong (4 bytes),
>    tested and confirmed that it works up to 4294967295 - for Gbps speed;
>  * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
>  * CCIDs are between 0 .. 255;
>  * request_retries, retries1, retries2 also between 0..255 for good measure;
>  * tx_qlen is checked to be non-negative;
>  * sync_ratelimit remains as before.
> 
> Further changes:
> ----------------
> Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.
> 
> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
> ---
>  include/linux/dccp.h |    8 --------
>  net/dccp/dccp.h      |    3 ---
>  net/dccp/feat.c      |   11 ++++++++---
>  net/dccp/feat.h      |    8 ++++++++
>  net/dccp/options.c   |    4 ----
>  net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
>  6 files changed, 46 insertions(+), 31 deletions(-)
> 
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -100,6 +100,13 @@ struct ccid_dependency {
>  	u8	val;
>  };
>  
> +/*
> + * Sysctls to seed defaults for feature negotiation
> + */
> +extern unsigned long sysctl_dccp_sequence_window;
> +extern int	     sysctl_dccp_rx_ccid;
> +extern int	     sysctl_dccp_tx_ccid;
> +
>  #ifdef CONFIG_IP_DCCP_DEBUG
>  extern const char *dccp_feat_typename(const u8 type);
>  extern const char *dccp_feat_name(const u8 feat);
> @@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
>  #endif /* CONFIG_IP_DCCP_DEBUG */
>  
>  extern int  dccp_feat_init(struct sock *sk);
> +extern void dccp_feat_initialise_sysctls(void);
>  extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
>  				  u8 const *list, u8 len);
>  extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
> --- a/net/dccp/feat.c
> +++ b/net/dccp/feat.c
> @@ -25,6 +25,11 @@
>  #include "ccid.h"
>  #include "feat.h"
>  
> +/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
> +unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
> +int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
> +		sysctl_dccp_tx_ccid	    __read_mostly = 2;
> +
>  /*
>   * Feature activation handlers.
>   *
> @@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
>  
>  	/* Non-negotiable (NN) features */
>  	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
> -				    sysctl_dccp_feat_sequence_window);
> +				    sysctl_dccp_sequence_window);
>  	if (rc)
>  		return rc;
>  
> @@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
>  	if (ccid_request_modules(tx.val, tx.len))
>  		goto free_ccid_lists;
>  
> -	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
> -	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
> +	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
> +	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
>  		goto free_ccid_lists;
>  
>  	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
> --- a/net/dccp/dccp.h
> +++ b/net/dccp/dccp.h
> @@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
>  extern int  sysctl_dccp_request_retries;
>  extern int  sysctl_dccp_retries1;
>  extern int  sysctl_dccp_retries2;
> -extern int  sysctl_dccp_feat_sequence_window;
> -extern int  sysctl_dccp_feat_rx_ccid;
> -extern int  sysctl_dccp_feat_tx_ccid;
>  extern int  sysctl_dccp_tx_qlen;
>  extern int  sysctl_dccp_sync_ratelimit;
>  
> --- a/include/linux/dccp.h
> +++ b/include/linux/dccp.h
> @@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>  	return __dccp_hdr_len(dccp_hdr(skb));
>  }
>  
> -
> -/* initial values for each feature */
> -#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
> -#define DCCPF_INITIAL_ACK_RATIO			2
> -#define DCCPF_INITIAL_CCID			DCCPC_CCID2
> -/* FIXME: for now we're default to 1 but it should really be 0 */
> -#define DCCPF_INITIAL_SEND_NDP_COUNT		1
> -
>  /**
>   * struct dccp_request_sock  -  represent DCCP-specific connection request
>   * @dreq_inet_rsk: structure inherited from
> --- a/net/dccp/options.c
> +++ b/net/dccp/options.c
> @@ -23,10 +23,6 @@
>  #include "dccp.h"
>  #include "feat.h"
>  
> -int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
> -int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
> -int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
> -
>  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>  {
>  	u64 value = 0;
> --- a/net/dccp/sysctl.c
> +++ b/net/dccp/sysctl.c
> @@ -18,55 +18,72 @@
>  #error This file should not be compiled without CONFIG_SYSCTL defined
>  #endif
>  
> +/* Boundary values */
> +static int		zero     = 0,
> +			u8_max   = 0xFF;

I wonder if these aren't available for wider use... some files have it:

./kernel/sysctl.c
./fs/inotify_user.c
./net/sunrpc/xprtrdma/transport.c
./net/ipv4/ip_fragment.c
./net/ipv4/sysctl_net_ipv4.c
./net/sctp/sysctl.c (well, this one also does the not needed '= 0' :) */

static int zero;

Some others, such as ./net/netrom/sysctl_net_netrom.c, could also use it

And one, etc, and it seems some people are even more crazy about saving
some bytes:

/* Constants used for minimum and  maximum */
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
static int one = 1;
#endif

Unsure if the cost of exporting this to modules will do us good tho...

Perhaps some janitor may be interested in doing some measurements and
looking at u8_max (int_max, etc) too? :-)

Other than that:

Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>

- Arnaldo

> +static unsigned long	seqw_min = 32;
> +
>  static struct ctl_table dccp_default_table[] = {
>  	{
>  		.procname	= "seq_window",
> -		.data		= &sysctl_dccp_feat_sequence_window,
> -		.maxlen		= sizeof(sysctl_dccp_feat_sequence_window),
> +		.data		= &sysctl_dccp_sequence_window,
> +		.maxlen		= sizeof(sysctl_dccp_sequence_window),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_doulongvec_minmax,
> +		.extra1		= &seqw_min,		/* RFC 4340, 7.5.2 */
>  	},
>  	{
>  		.procname	= "rx_ccid",
> -		.data		= &sysctl_dccp_feat_rx_ccid,
> -		.maxlen		= sizeof(sysctl_dccp_feat_rx_ccid),
> +		.data		= &sysctl_dccp_rx_ccid,
> +		.maxlen		= sizeof(sysctl_dccp_rx_ccid),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,		/* RFC 4340, 10. */
>  	},
>  	{
>  		.procname	= "tx_ccid",
> -		.data		= &sysctl_dccp_feat_tx_ccid,
> -		.maxlen		= sizeof(sysctl_dccp_feat_tx_ccid),
> +		.data		= &sysctl_dccp_tx_ccid,
> +		.maxlen		= sizeof(sysctl_dccp_tx_ccid),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,		/* RFC 4340, 10. */
>  	},
>  	{
>  		.procname	= "request_retries",
>  		.data		= &sysctl_dccp_request_retries,
>  		.maxlen		= sizeof(sysctl_dccp_request_retries),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "retries1",
>  		.data		= &sysctl_dccp_retries1,
>  		.maxlen		= sizeof(sysctl_dccp_retries1),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "retries2",
>  		.data		= &sysctl_dccp_retries2,
>  		.maxlen		= sizeof(sysctl_dccp_retries2),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
> +		.extra2		= &u8_max,
>  	},
>  	{
>  		.procname	= "tx_qlen",
>  		.data		= &sysctl_dccp_tx_qlen,
>  		.maxlen		= sizeof(sysctl_dccp_tx_qlen),
>  		.mode		= 0644,
> -		.proc_handler	= proc_dointvec,
> +		.proc_handler	= proc_dointvec_minmax,
> +		.extra1		= &zero,
>  	},
>  	{
>  		.procname	= "sync_ratelimit",
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls
  2008-12-15 14:15                                                                                                     ` Arnaldo Carvalho de Melo
  (?)
@ 2008-12-15 14:23                                                                                                       ` walter harms
  -1 siblings, 0 replies; 484+ messages in thread
From: walter harms @ 2008-12-15 14:23 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Gerrit Renker, davem, dccp, netdev,
	Kernel Janitors



Arnaldo Carvalho de Melo schrieb:
> Em Sat, Dec 13, 2008 at 02:41:24PM +0100, Gerrit Renker escreveu:
>> This patch takes care of initialising and type-checking sysctls related to
>> feature negotiation. Type checking is important since some of the sysctls
>> now directly act on the feature-negotiation process.
>>
>> The sysctls are initialised with the known default values for each feature.
>> For the type-checking the value constraints from RFC 4340 are used:
>>
>>  * Sequence Window uses the specified Wmin=32, the maximum is ulong (4 bytes),
>>    tested and confirmed that it works up to 4294967295 - for Gbps speed;
>>  * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
>>  * CCIDs are between 0 .. 255;
>>  * request_retries, retries1, retries2 also between 0..255 for good measure;
>>  * tx_qlen is checked to be non-negative;
>>  * sync_ratelimit remains as before.
>>
>> Further changes:
>> ----------------
>> Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.
>>
>> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
>> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
>> ---
>>  include/linux/dccp.h |    8 --------
>>  net/dccp/dccp.h      |    3 ---
>>  net/dccp/feat.c      |   11 ++++++++---
>>  net/dccp/feat.h      |    8 ++++++++
>>  net/dccp/options.c   |    4 ----
>>  net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
>>  6 files changed, 46 insertions(+), 31 deletions(-)
>>
>> --- a/net/dccp/feat.h
>> +++ b/net/dccp/feat.h
>> @@ -100,6 +100,13 @@ struct ccid_dependency {
>>  	u8	val;
>>  };
>>  
>> +/*
>> + * Sysctls to seed defaults for feature negotiation
>> + */
>> +extern unsigned long sysctl_dccp_sequence_window;
>> +extern int	     sysctl_dccp_rx_ccid;
>> +extern int	     sysctl_dccp_tx_ccid;
>> +
>>  #ifdef CONFIG_IP_DCCP_DEBUG
>>  extern const char *dccp_feat_typename(const u8 type);
>>  extern const char *dccp_feat_name(const u8 feat);
>> @@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
>>  #endif /* CONFIG_IP_DCCP_DEBUG */
>>  
>>  extern int  dccp_feat_init(struct sock *sk);
>> +extern void dccp_feat_initialise_sysctls(void);
>>  extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
>>  				  u8 const *list, u8 len);
>>  extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
>> --- a/net/dccp/feat.c
>> +++ b/net/dccp/feat.c
>> @@ -25,6 +25,11 @@
>>  #include "ccid.h"
>>  #include "feat.h"
>>  
>> +/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
>> +unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
>> +int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
>> +		sysctl_dccp_tx_ccid	    __read_mostly = 2;
>> +
>>  /*
>>   * Feature activation handlers.
>>   *
>> @@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
>>  
>>  	/* Non-negotiable (NN) features */
>>  	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
>> -				    sysctl_dccp_feat_sequence_window);
>> +				    sysctl_dccp_sequence_window);
>>  	if (rc)
>>  		return rc;
>>  
>> @@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
>>  	if (ccid_request_modules(tx.val, tx.len))
>>  		goto free_ccid_lists;
>>  
>> -	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
>> -	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
>> +	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
>> +	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
>>  		goto free_ccid_lists;
>>  
>>  	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
>> --- a/net/dccp/dccp.h
>> +++ b/net/dccp/dccp.h
>> @@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
>>  extern int  sysctl_dccp_request_retries;
>>  extern int  sysctl_dccp_retries1;
>>  extern int  sysctl_dccp_retries2;
>> -extern int  sysctl_dccp_feat_sequence_window;
>> -extern int  sysctl_dccp_feat_rx_ccid;
>> -extern int  sysctl_dccp_feat_tx_ccid;
>>  extern int  sysctl_dccp_tx_qlen;
>>  extern int  sysctl_dccp_sync_ratelimit;
>>  
>> --- a/include/linux/dccp.h
>> +++ b/include/linux/dccp.h
>> @@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>>  	return __dccp_hdr_len(dccp_hdr(skb));
>>  }
>>  
>> -
>> -/* initial values for each feature */
>> -#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
>> -#define DCCPF_INITIAL_ACK_RATIO			2
>> -#define DCCPF_INITIAL_CCID			DCCPC_CCID2
>> -/* FIXME: for now we're default to 1 but it should really be 0 */
>> -#define DCCPF_INITIAL_SEND_NDP_COUNT		1
>> -
>>  /**
>>   * struct dccp_request_sock  -  represent DCCP-specific connection request
>>   * @dreq_inet_rsk: structure inherited from
>> --- a/net/dccp/options.c
>> +++ b/net/dccp/options.c
>> @@ -23,10 +23,6 @@
>>  #include "dccp.h"
>>  #include "feat.h"
>>  
>> -int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
>> -int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
>> -int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
>> -
>>  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>>  {
>>  	u64 value = 0;
>> --- a/net/dccp/sysctl.c
>> +++ b/net/dccp/sysctl.c
>> @@ -18,55 +18,72 @@
>>  #error This file should not be compiled without CONFIG_SYSCTL defined
>>  #endif
>>  
>> +/* Boundary values */
>> +static int		zero     = 0,
>> +			u8_max   = 0xFF;
> 
> I wonder if these aren't available for wider use... some files have it:
> 
> ./kernel/sysctl.c
> ./fs/inotify_user.c
> ./net/sunrpc/xprtrdma/transport.c
> ./net/ipv4/ip_fragment.c
> ./net/ipv4/sysctl_net_ipv4.c
> ./net/sctp/sysctl.c (well, this one also does the not needed '= 0' :) */
> 
> static int zero;
> 
> Some others, such as ./net/netrom/sysctl_net_netrom.c, could also use it
> 
> And one, etc, and it seems some people are even more crazy about saving
> some bytes:
> 
> /* Constants used for minimum and  maximum */
> #if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
> static int one = 1;
> #endif
> 
> Unsure if the cost of exporting this to modules will do us good tho...
> 
> Perhaps some janitor may be interested in doing some measurements and
> looking at u8_max (int_max, etc) too? :-)
> 
> Other than that:
> 

busybox has replace static int with enum's to save bytes. i guess this is the way to save bytes :)

re,
 wh

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Initialisation and type-checking of feature
@ 2008-12-15 14:23                                                                                                       ` walter harms
  0 siblings, 0 replies; 484+ messages in thread
From: walter harms @ 2008-12-15 14:23 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Gerrit Renker, davem, dccp, netdev



Arnaldo Carvalho de Melo schrieb:
> Em Sat, Dec 13, 2008 at 02:41:24PM +0100, Gerrit Renker escreveu:
>> This patch takes care of initialising and type-checking sysctls related to
>> feature negotiation. Type checking is important since some of the sysctls
>> now directly act on the feature-negotiation process.
>>
>> The sysctls are initialised with the known default values for each feature.
>> For the type-checking the value constraints from RFC 4340 are used:
>>
>>  * Sequence Window uses the specified Wmin2, the maximum is ulong (4 bytes),
>>    tested and confirmed that it works up to 4294967295 - for Gbps speed;
>>  * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
>>  * CCIDs are between 0 .. 255;
>>  * request_retries, retries1, retries2 also between 0..255 for good measure;
>>  * tx_qlen is checked to be non-negative;
>>  * sync_ratelimit remains as before.
>>
>> Further changes:
>> ----------------
>> Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.
>>
>> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
>> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
>> ---
>>  include/linux/dccp.h |    8 --------
>>  net/dccp/dccp.h      |    3 ---
>>  net/dccp/feat.c      |   11 ++++++++---
>>  net/dccp/feat.h      |    8 ++++++++
>>  net/dccp/options.c   |    4 ----
>>  net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
>>  6 files changed, 46 insertions(+), 31 deletions(-)
>>
>> --- a/net/dccp/feat.h
>> +++ b/net/dccp/feat.h
>> @@ -100,6 +100,13 @@ struct ccid_dependency {
>>  	u8	val;
>>  };
>>  
>> +/*
>> + * Sysctls to seed defaults for feature negotiation
>> + */
>> +extern unsigned long sysctl_dccp_sequence_window;
>> +extern int	     sysctl_dccp_rx_ccid;
>> +extern int	     sysctl_dccp_tx_ccid;
>> +
>>  #ifdef CONFIG_IP_DCCP_DEBUG
>>  extern const char *dccp_feat_typename(const u8 type);
>>  extern const char *dccp_feat_name(const u8 feat);
>> @@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
>>  #endif /* CONFIG_IP_DCCP_DEBUG */
>>  
>>  extern int  dccp_feat_init(struct sock *sk);
>> +extern void dccp_feat_initialise_sysctls(void);
>>  extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
>>  				  u8 const *list, u8 len);
>>  extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
>> --- a/net/dccp/feat.c
>> +++ b/net/dccp/feat.c
>> @@ -25,6 +25,11 @@
>>  #include "ccid.h"
>>  #include "feat.h"
>>  
>> +/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
>> +unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
>> +int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
>> +		sysctl_dccp_tx_ccid	    __read_mostly = 2;
>> +
>>  /*
>>   * Feature activation handlers.
>>   *
>> @@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
>>  
>>  	/* Non-negotiable (NN) features */
>>  	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
>> -				    sysctl_dccp_feat_sequence_window);
>> +				    sysctl_dccp_sequence_window);
>>  	if (rc)
>>  		return rc;
>>  
>> @@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
>>  	if (ccid_request_modules(tx.val, tx.len))
>>  		goto free_ccid_lists;
>>  
>> -	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
>> -	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
>> +	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
>> +	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
>>  		goto free_ccid_lists;
>>  
>>  	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
>> --- a/net/dccp/dccp.h
>> +++ b/net/dccp/dccp.h
>> @@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
>>  extern int  sysctl_dccp_request_retries;
>>  extern int  sysctl_dccp_retries1;
>>  extern int  sysctl_dccp_retries2;
>> -extern int  sysctl_dccp_feat_sequence_window;
>> -extern int  sysctl_dccp_feat_rx_ccid;
>> -extern int  sysctl_dccp_feat_tx_ccid;
>>  extern int  sysctl_dccp_tx_qlen;
>>  extern int  sysctl_dccp_sync_ratelimit;
>>  
>> --- a/include/linux/dccp.h
>> +++ b/include/linux/dccp.h
>> @@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>>  	return __dccp_hdr_len(dccp_hdr(skb));
>>  }
>>  
>> -
>> -/* initial values for each feature */
>> -#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
>> -#define DCCPF_INITIAL_ACK_RATIO			2
>> -#define DCCPF_INITIAL_CCID			DCCPC_CCID2
>> -/* FIXME: for now we're default to 1 but it should really be 0 */
>> -#define DCCPF_INITIAL_SEND_NDP_COUNT		1
>> -
>>  /**
>>   * struct dccp_request_sock  -  represent DCCP-specific connection request
>>   * @dreq_inet_rsk: structure inherited from
>> --- a/net/dccp/options.c
>> +++ b/net/dccp/options.c
>> @@ -23,10 +23,6 @@
>>  #include "dccp.h"
>>  #include "feat.h"
>>  
>> -int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
>> -int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
>> -int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
>> -
>>  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>>  {
>>  	u64 value = 0;
>> --- a/net/dccp/sysctl.c
>> +++ b/net/dccp/sysctl.c
>> @@ -18,55 +18,72 @@
>>  #error This file should not be compiled without CONFIG_SYSCTL defined
>>  #endif
>>  
>> +/* Boundary values */
>> +static int		zero     = 0,
>> +			u8_max   = 0xFF;
> 
> I wonder if these aren't available for wider use... some files have it:
> 
> ./kernel/sysctl.c
> ./fs/inotify_user.c
> ./net/sunrpc/xprtrdma/transport.c
> ./net/ipv4/ip_fragment.c
> ./net/ipv4/sysctl_net_ipv4.c
> ./net/sctp/sysctl.c (well, this one also does the not needed '= 0' :) */
> 
> static int zero;
> 
> Some others, such as ./net/netrom/sysctl_net_netrom.c, could also use it
> 
> And one, etc, and it seems some people are even more crazy about saving
> some bytes:
> 
> /* Constants used for minimum and  maximum */
> #if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
> static int one = 1;
> #endif
> 
> Unsure if the cost of exporting this to modules will do us good tho...
> 
> Perhaps some janitor may be interested in doing some measurements and
> looking at u8_max (int_max, etc) too? :-)
> 
> Other than that:
> 

busybox has replace static int with enum's to save bytes. i guess this is the way to save bytes :)

re,
 wh

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 4/5] dccp: Initialisation and type-checking of feature
@ 2008-12-15 14:23                                                                                                       ` walter harms
  0 siblings, 0 replies; 484+ messages in thread
From: walter harms @ 2008-12-15 14:23 UTC (permalink / raw)
  To: dccp



Arnaldo Carvalho de Melo schrieb:
> Em Sat, Dec 13, 2008 at 02:41:24PM +0100, Gerrit Renker escreveu:
>> This patch takes care of initialising and type-checking sysctls related to
>> feature negotiation. Type checking is important since some of the sysctls
>> now directly act on the feature-negotiation process.
>>
>> The sysctls are initialised with the known default values for each feature.
>> For the type-checking the value constraints from RFC 4340 are used:
>>
>>  * Sequence Window uses the specified Wmin2, the maximum is ulong (4 bytes),
>>    tested and confirmed that it works up to 4294967295 - for Gbps speed;
>>  * Ack Ratio is between 0 .. 0xffff (2-byte unsigned integer);
>>  * CCIDs are between 0 .. 255;
>>  * request_retries, retries1, retries2 also between 0..255 for good measure;
>>  * tx_qlen is checked to be non-negative;
>>  * sync_ratelimit remains as before.
>>
>> Further changes:
>> ----------------
>> Performed s@sysctl_dccp_feat@sysctl_dccp@g since the sysctls are now in feat.c.
>>
>> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
>> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
>> ---
>>  include/linux/dccp.h |    8 --------
>>  net/dccp/dccp.h      |    3 ---
>>  net/dccp/feat.c      |   11 ++++++++---
>>  net/dccp/feat.h      |    8 ++++++++
>>  net/dccp/options.c   |    4 ----
>>  net/dccp/sysctl.c    |   43 ++++++++++++++++++++++++++++++-------------
>>  6 files changed, 46 insertions(+), 31 deletions(-)
>>
>> --- a/net/dccp/feat.h
>> +++ b/net/dccp/feat.h
>> @@ -100,6 +100,13 @@ struct ccid_dependency {
>>  	u8	val;
>>  };
>>  
>> +/*
>> + * Sysctls to seed defaults for feature negotiation
>> + */
>> +extern unsigned long sysctl_dccp_sequence_window;
>> +extern int	     sysctl_dccp_rx_ccid;
>> +extern int	     sysctl_dccp_tx_ccid;
>> +
>>  #ifdef CONFIG_IP_DCCP_DEBUG
>>  extern const char *dccp_feat_typename(const u8 type);
>>  extern const char *dccp_feat_name(const u8 feat);
>> @@ -114,6 +121,7 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
>>  #endif /* CONFIG_IP_DCCP_DEBUG */
>>  
>>  extern int  dccp_feat_init(struct sock *sk);
>> +extern void dccp_feat_initialise_sysctls(void);
>>  extern int  dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
>>  				  u8 const *list, u8 len);
>>  extern int  dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
>> --- a/net/dccp/feat.c
>> +++ b/net/dccp/feat.c
>> @@ -25,6 +25,11 @@
>>  #include "ccid.h"
>>  #include "feat.h"
>>  
>> +/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
>> +unsigned long	sysctl_dccp_sequence_window __read_mostly = 100;
>> +int		sysctl_dccp_rx_ccid	    __read_mostly = 2,
>> +		sysctl_dccp_tx_ccid	    __read_mostly = 2;
>> +
>>  /*
>>   * Feature activation handlers.
>>   *
>> @@ -1146,7 +1151,7 @@ int dccp_feat_init(struct sock *sk)
>>  
>>  	/* Non-negotiable (NN) features */
>>  	rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
>> -				    sysctl_dccp_feat_sequence_window);
>> +				    sysctl_dccp_sequence_window);
>>  	if (rc)
>>  		return rc;
>>  
>> @@ -1177,8 +1182,8 @@ int dccp_feat_init(struct sock *sk)
>>  	if (ccid_request_modules(tx.val, tx.len))
>>  		goto free_ccid_lists;
>>  
>> -	if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) ||
>> -	    !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len))
>> +	if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
>> +	    !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
>>  		goto free_ccid_lists;
>>  
>>  	rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
>> --- a/net/dccp/dccp.h
>> +++ b/net/dccp/dccp.h
>> @@ -95,9 +95,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
>>  extern int  sysctl_dccp_request_retries;
>>  extern int  sysctl_dccp_retries1;
>>  extern int  sysctl_dccp_retries2;
>> -extern int  sysctl_dccp_feat_sequence_window;
>> -extern int  sysctl_dccp_feat_rx_ccid;
>> -extern int  sysctl_dccp_feat_tx_ccid;
>>  extern int  sysctl_dccp_tx_qlen;
>>  extern int  sysctl_dccp_sync_ratelimit;
>>  
>> --- a/include/linux/dccp.h
>> +++ b/include/linux/dccp.h
>> @@ -355,14 +355,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
>>  	return __dccp_hdr_len(dccp_hdr(skb));
>>  }
>>  
>> -
>> -/* initial values for each feature */
>> -#define DCCPF_INITIAL_SEQUENCE_WINDOW		100
>> -#define DCCPF_INITIAL_ACK_RATIO			2
>> -#define DCCPF_INITIAL_CCID			DCCPC_CCID2
>> -/* FIXME: for now we're default to 1 but it should really be 0 */
>> -#define DCCPF_INITIAL_SEND_NDP_COUNT		1
>> -
>>  /**
>>   * struct dccp_request_sock  -  represent DCCP-specific connection request
>>   * @dreq_inet_rsk: structure inherited from
>> --- a/net/dccp/options.c
>> +++ b/net/dccp/options.c
>> @@ -23,10 +23,6 @@
>>  #include "dccp.h"
>>  #include "feat.h"
>>  
>> -int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
>> -int sysctl_dccp_feat_rx_ccid	      = DCCPF_INITIAL_CCID;
>> -int sysctl_dccp_feat_tx_ccid	      = DCCPF_INITIAL_CCID;
>> -
>>  u64 dccp_decode_value_var(const u8 *bf, const u8 len)
>>  {
>>  	u64 value = 0;
>> --- a/net/dccp/sysctl.c
>> +++ b/net/dccp/sysctl.c
>> @@ -18,55 +18,72 @@
>>  #error This file should not be compiled without CONFIG_SYSCTL defined
>>  #endif
>>  
>> +/* Boundary values */
>> +static int		zero     = 0,
>> +			u8_max   = 0xFF;
> 
> I wonder if these aren't available for wider use... some files have it:
> 
> ./kernel/sysctl.c
> ./fs/inotify_user.c
> ./net/sunrpc/xprtrdma/transport.c
> ./net/ipv4/ip_fragment.c
> ./net/ipv4/sysctl_net_ipv4.c
> ./net/sctp/sysctl.c (well, this one also does the not needed '= 0' :) */
> 
> static int zero;
> 
> Some others, such as ./net/netrom/sysctl_net_netrom.c, could also use it
> 
> And one, etc, and it seems some people are even more crazy about saving
> some bytes:
> 
> /* Constants used for minimum and  maximum */
> #if defined(CONFIG_HIGHMEM) || defined(CONFIG_DETECT_SOFTLOCKUP)
> static int one = 1;
> #endif
> 
> Unsure if the cost of exporting this to modules will do us good tho...
> 
> Perhaps some janitor may be interested in doing some measurements and
> looking at u8_max (int_max, etc) too? :-)
> 
> Other than that:
> 

busybox has replace static int with enum's to save bytes. i guess this is the way to save bytes :)

re,
 wh

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-15 16:25                                                                                                       ` gerrit
  -1 siblings, 0 replies; 484+ messages in thread
From: gerrit @ 2008-12-15 16:25 UTC (permalink / raw)
  To: Micha³ Miros³aw, acme; +Cc: Gerrit Renker, davem, dccp, netdev

> Since the lock is dropped after checking ccids[id] then there's
> a window where multiple request_module()s can be called if multiple
> applications create a DCCP socket at a same time. The code below
> should do the same without a lock (ccids is a static array,
> so ccids[N] is always at the same place).
>
> static int ccid_request_module(u8 id)
> {
>        if (!in_atomic()) {
>                rmb();
>                if (ccids[id] == NULL)
>                        return request_module("net-dccp-ccid-%d", id);
>        }
>        return 0;
> }
>
I think that the code (not yours) is in general misleading. It stems from
an earlier phase of the DCCP development. Now, with the present patch set,
the rationale is
 * all CCIDs that are advertised must be loaded
 * this is a subset of the configured CCIDs and contains at least one CCID
 * the request_module is only ever executed once, when the first DCCP
   application tries to pre-load the CCIDs it wants to advertise

Hence I think we have a chance by going completely lockless here, by
loading all configured CCIDs at runtime. In this manner the per-connection
check "are all advertised CCIDs are loaded?" falls under the table, we
do not need to worry about concurrent access, and loading DCCP implies that
all needed CCIDs are there.

Arnaldo would you be okay with such an approach ? I would be willing to
revise the patch set accordingly.

Gerrit


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-15 16:25                                                                                                       ` gerrit
  0 siblings, 0 replies; 484+ messages in thread
From: gerrit @ 2008-12-15 16:25 UTC (permalink / raw)
  To: dccp

> Since the lock is dropped after checking ccids[id] then there's
> a window where multiple request_module()s can be called if multiple
> applications create a DCCP socket at a same time. The code below
> should do the same without a lock (ccids is a static array,
> so ccids[N] is always at the same place).
>
> static int ccid_request_module(u8 id)
> {
>        if (!in_atomic()) {
>                rmb();
>                if (ccids[id] = NULL)
>                        return request_module("net-dccp-ccid-%d", id);
>        }
>        return 0;
> }
>
I think that the code (not yours) is in general misleading. It stems from
an earlier phase of the DCCP development. Now, with the present patch set,
the rationale is
 * all CCIDs that are advertised must be loaded
 * this is a subset of the configured CCIDs and contains at least one CCID
 * the request_module is only ever executed once, when the first DCCP
   application tries to pre-load the CCIDs it wants to advertise

Hence I think we have a chance by going completely lockless here, by
loading all configured CCIDs at runtime. In this manner the per-connection
check "are all advertised CCIDs are loaded?" falls under the table, we
do not need to worry about concurrent access, and loading DCCP implies that
all needed CCIDs are there.

Arnaldo would you be okay with such an approach ? I would be willing to
revise the patch set accordingly.

Gerrit


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16  5:29                                                                                                         ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-16  5:29 UTC (permalink / raw)
  To: Micha? Miros?aw, acme; +Cc: davem, dccp, netdev

| Hence I think we have a chance by going completely lockless here, by
| loading all configured CCIDs at runtime. In this manner the per-connection
| check "are all advertised CCIDs are loaded?" falls under the table, we
| do not need to worry about concurrent access, and loading DCCP implies that
| all needed CCIDs are there.
Unfortunately this won't work since the CCIDs depend on dccp.ko being
fully loaded, so requiring that CCID module are loaded during the
loading process of dccp.ko creates a cyclic dependency.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16  5:29                                                                                                         ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-16  5:29 UTC (permalink / raw)
  To: dccp

| Hence I think we have a chance by going completely lockless here, by
| loading all configured CCIDs at runtime. In this manner the per-connection
| check "are all advertised CCIDs are loaded?" falls under the table, we
| do not need to worry about concurrent access, and loading DCCP implies that
| all needed CCIDs are there.
Unfortunately this won't work since the CCIDs depend on dccp.ko being
fully loaded, so requiring that CCID module are loaded during the
loading process of dccp.ko creates a cyclic dependency.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16  5:44                                                                                                   ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-16  5:44 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, davem, dccp, netdev

| > +/**
| > + * ccid_request_module  -  Pre-load CCID module for later use
| > + * This should be called only from process context (e.g. during connection
| > + * setup) and is necessary for later calls to ccid_new (typically in software
| > + * interrupt), so that it has the modules available when they are needed.
| > + */
| > +static int ccid_request_module(u8 id)
| > +{
| > +	if (!in_atomic()) {
| 
| Shouldn't the above be in a BUG_ON? It looks strange to simply refuse to
| do that and return OK. 
| 
| > +		ccids_read_lock();
| > +		if (ccids[id] == NULL) {
| > +			ccids_read_unlock();
| > +			return request_module("net-dccp-ccid-%d", id);
| > +		}
| > +		ccids_read_unlock();
| > +	}
| > +	return 0;
| > +}
We can do this if you want, but in a way this is a suggestion for the
existing code, compare with the original from ccid_new() below

	ccids_read_lock();
#ifdef CONFIG_MODULES
	if (ccids[id] == NULL) {
		/* We only try to load if in process context */
		ccids_read_unlock();
		if (gfp & GFP_ATOMIC)
			goto out;
		request_module("net-dccp-ccid-%d", id);
		ccids_read_lock();
	}
#endif

==> gfp is atomic when called from dccp_feat_update_ccid(), which is why
    in the previous feature-negotiation code DCCP crashed when trying to
    negotiate any CCID module that had not been loaded:
    
	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);

    meant that the module would not be reloaded.

==> On the other hand, when called via ccid_hc_{rx,tx}_new(), gfp=GFP_KERNEL
    and so an attempted module load would succeed. This explains why loading
    worked when starting with the default (non-negotiated) CCIDs.



==> So how do we remain? I am ok turning the above into a BUG_ON.
    As an alternative, since the function is only called in a single
    place (the initialisation of feat.c), we could consider removing the
    function entirely and merge its contents into dccp_feat_init().
    Would that be better?

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16  5:44                                                                                                   ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-16  5:44 UTC (permalink / raw)
  To: dccp

| > +/**
| > + * ccid_request_module  -  Pre-load CCID module for later use
| > + * This should be called only from process context (e.g. during connection
| > + * setup) and is necessary for later calls to ccid_new (typically in software
| > + * interrupt), so that it has the modules available when they are needed.
| > + */
| > +static int ccid_request_module(u8 id)
| > +{
| > +	if (!in_atomic()) {
| 
| Shouldn't the above be in a BUG_ON? It looks strange to simply refuse to
| do that and return OK. 
| 
| > +		ccids_read_lock();
| > +		if (ccids[id] = NULL) {
| > +			ccids_read_unlock();
| > +			return request_module("net-dccp-ccid-%d", id);
| > +		}
| > +		ccids_read_unlock();
| > +	}
| > +	return 0;
| > +}
We can do this if you want, but in a way this is a suggestion for the
existing code, compare with the original from ccid_new() below

	ccids_read_lock();
#ifdef CONFIG_MODULES
	if (ccids[id] = NULL) {
		/* We only try to load if in process context */
		ccids_read_unlock();
		if (gfp & GFP_ATOMIC)
			goto out;
		request_module("net-dccp-ccid-%d", id);
		ccids_read_lock();
	}
#endif

=> gfp is atomic when called from dccp_feat_update_ccid(), which is why
    in the previous feature-negotiation code DCCP crashed when trying to
    negotiate any CCID module that had not been loaded:
    
	new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);

    meant that the module would not be reloaded.

=> On the other hand, when called via ccid_hc_{rx,tx}_new(), gfp=GFP_KERNEL
    and so an attempted module load would succeed. This explains why loading
    worked when starting with the default (non-negotiated) CCIDs.



=> So how do we remain? I am ok turning the above into a BUG_ON.
    As an alternative, since the function is only called in a single
    place (the initialisation of feat.c), we could consider removing the
    function entirely and merge its contents into dccp_feat_init().
    Would that be better?

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16  5:55                                                                                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-16  5:55 UTC (permalink / raw)
  To: Micha? Miros?aw; +Cc: davem, dccp, netdev

| > | > +static int ccid_request_module(u8 id)
| > | > +{
| > | > +       if (!in_atomic()) {
| > | > +               ccids_read_lock();
| > | > +               if (ccids[id] == NULL) {
| > | > +                       ccids_read_unlock();
| > | > +                       return request_module("net-dccp-ccid-%d", id);
| > | > +               }
| > | > +               ccids_read_unlock();
| > | > +       }
| > | > +       return 0;
| > | > +}
| > |
| > | Just a random thought: does this lock really do anything useful here?
| > |
| > Reading the (shared) 'ccids' array is the solution chosen to check whether
| > the module for CCID with number 'id' is already loaded.
| >
| > It would be bad to call request_module() each time a new DCCP socket is
| > opened. Using the 'ccids' array may not be the only way to check whether
| > a given module (whose name depends on the value of 'id') is loaded.
| >
| > But if this solution is chosen, then it requires to protect the read
| > access to 'ccids', which is shared among all DCCP sockets.
| 
| Since the lock is dropped after checking ccids[id] then there's
| a window where multiple request_module()s can be called if multiple
| applications create a DCCP socket at a same time. The code below
| should do the same without a lock (ccids is a static array,
| so ccids[N] is always at the same place).
| 
| static int ccid_request_module(u8 id)
| {
|        if (!in_atomic()) {
|                rmb();
|                if (ccids[id] == NULL)
|                        return request_module("net-dccp-ccid-%d", id);
|        }
|        return 0;
| }
| 
Sorry Michael, but this is really just a "random thought". What you are
in effect saying is that reader/writer locks can be replaced with just a
read memory barrier.

Please have a more detailed look at net/dccp/ccid.c. I also checked how
other subsystems handle comparable situations of module loading: the 
implementation details differ, but the principle is the same: there are
mutexes, semaphores, and spinlocks in use to protect those shared
structures that are related to the loaded module.

Hence your suggestion does not improve the code. I maintain that it is
correct. And it has proven to work in the test tree for more than one
year, including tests with up to 100 parallel (iperf) connections.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16  5:55                                                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-16  5:55 UTC (permalink / raw)
  To: dccp

| > | > +static int ccid_request_module(u8 id)
| > | > +{
| > | > +       if (!in_atomic()) {
| > | > +               ccids_read_lock();
| > | > +               if (ccids[id] = NULL) {
| > | > +                       ccids_read_unlock();
| > | > +                       return request_module("net-dccp-ccid-%d", id);
| > | > +               }
| > | > +               ccids_read_unlock();
| > | > +       }
| > | > +       return 0;
| > | > +}
| > |
| > | Just a random thought: does this lock really do anything useful here?
| > |
| > Reading the (shared) 'ccids' array is the solution chosen to check whether
| > the module for CCID with number 'id' is already loaded.
| >
| > It would be bad to call request_module() each time a new DCCP socket is
| > opened. Using the 'ccids' array may not be the only way to check whether
| > a given module (whose name depends on the value of 'id') is loaded.
| >
| > But if this solution is chosen, then it requires to protect the read
| > access to 'ccids', which is shared among all DCCP sockets.
| 
| Since the lock is dropped after checking ccids[id] then there's
| a window where multiple request_module()s can be called if multiple
| applications create a DCCP socket at a same time. The code below
| should do the same without a lock (ccids is a static array,
| so ccids[N] is always at the same place).
| 
| static int ccid_request_module(u8 id)
| {
|        if (!in_atomic()) {
|                rmb();
|                if (ccids[id] = NULL)
|                        return request_module("net-dccp-ccid-%d", id);
|        }
|        return 0;
| }
| 
Sorry Michael, but this is really just a "random thought". What you are
in effect saying is that reader/writer locks can be replaced with just a
read memory barrier.

Please have a more detailed look at net/dccp/ccid.c. I also checked how
other subsystems handle comparable situations of module loading: the 
implementation details differ, but the principle is the same: there are
mutexes, semaphores, and spinlocks in use to protect those shared
structures that are related to the loaded module.

Hence your suggestion does not improve the code. I maintain that it is
correct. And it has proven to work in the test tree for more than one
year, including tests with up to 100 parallel (iperf) connections.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16  9:40                                                                                                           ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-16  9:40 UTC (permalink / raw)
  To: gerrit; +Cc: mirqus, acme, dccp, netdev

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 16 Dec 2008 06:29:54 +0100

> | Hence I think we have a chance by going completely lockless here, by
> | loading all configured CCIDs at runtime. In this manner the per-connection
> | check "are all advertised CCIDs are loaded?" falls under the table, we
> | do not need to worry about concurrent access, and loading DCCP implies that
> | all needed CCIDs are there.
> Unfortunately this won't work since the CCIDs depend on dccp.ko being
> fully loaded, so requiring that CCID module are loaded during the
> loading process of dccp.ko creates a cyclic dependency.

I don't like this stuff at all.

Every new connection you're going to loop over the CCID
table and grab that CCID read lock N times.

The first time it will do something meaningful, and then
%99.999999999999 of subsequent calls will do nothing.

What kind of overhead is deserved by that access pattern?

And, if the first thing the first connection is going to do
is load all the modules, there is ZERO reason to make them
modular.  It's just useless seperation and it adds all of
this rediculious synchronization.

If it's modular "for the sake of development" I'm sure you
can simply reload the dccp.ko module when you make some
CCID algorithm change.

I'm tossing this patch set until we get something better
in this area.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16  9:40                                                                                                           ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-16  9:40 UTC (permalink / raw)
  To: dccp

From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Date: Tue, 16 Dec 2008 06:29:54 +0100

> | Hence I think we have a chance by going completely lockless here, by
> | loading all configured CCIDs at runtime. In this manner the per-connection
> | check "are all advertised CCIDs are loaded?" falls under the table, we
> | do not need to worry about concurrent access, and loading DCCP implies that
> | all needed CCIDs are there.
> Unfortunately this won't work since the CCIDs depend on dccp.ko being
> fully loaded, so requiring that CCID module are loaded during the
> loading process of dccp.ko creates a cyclic dependency.

I don't like this stuff at all.

Every new connection you're going to loop over the CCID
table and grab that CCID read lock N times.

The first time it will do something meaningful, and then
%99.999999999999 of subsequent calls will do nothing.

What kind of overhead is deserved by that access pattern?

And, if the first thing the first connection is going to do
is load all the modules, there is ZERO reason to make them
modular.  It's just useless seperation and it adds all of
this rediculious synchronization.

If it's modular "for the sake of development" I'm sure you
can simply reload the dccp.ko module when you make some
CCID algorithm change.

I'm tossing this patch set until we get something better
in this area.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16 11:19                                                                                                             ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-16 11:19 UTC (permalink / raw)
  To: David Miller; +Cc: gerrit, mirqus, dccp, netdev

Em Tue, Dec 16, 2008 at 01:40:45AM -0800, David Miller escreveu:
> From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Date: Tue, 16 Dec 2008 06:29:54 +0100
> 
> > | Hence I think we have a chance by going completely lockless here, by
> > | loading all configured CCIDs at runtime. In this manner the per-connection
> > | check "are all advertised CCIDs are loaded?" falls under the table, we
> > | do not need to worry about concurrent access, and loading DCCP implies that
> > | all needed CCIDs are there.
> > Unfortunately this won't work since the CCIDs depend on dccp.ko being
> > fully loaded, so requiring that CCID module are loaded during the
> > loading process of dccp.ko creates a cyclic dependency.
> 
> I don't like this stuff at all.
> 
> Every new connection you're going to loop over the CCID
> table and grab that CCID read lock N times.
> 
> The first time it will do something meaningful, and then
> %99.999999999999 of subsequent calls will do nothing.
> 
> What kind of overhead is deserved by that access pattern?
> 
> And, if the first thing the first connection is going to do
> is load all the modules, there is ZERO reason to make them
> modular.  It's just useless seperation and it adds all of
> this rediculious synchronization.
> 
> If it's modular "for the sake of development" I'm sure you
> can simply reload the dccp.ko module when you make some
> CCID algorithm change.
> 
> I'm tossing this patch set until we get something better
> in this area.

I guess that looking at tcp_set_congestion_control() could be a good
start. 8-)

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16 11:19                                                                                                             ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-16 11:19 UTC (permalink / raw)
  To: dccp

Em Tue, Dec 16, 2008 at 01:40:45AM -0800, David Miller escreveu:
> From: Gerrit Renker <gerrit@erg.abdn.ac.uk>
> Date: Tue, 16 Dec 2008 06:29:54 +0100
> 
> > | Hence I think we have a chance by going completely lockless here, by
> > | loading all configured CCIDs at runtime. In this manner the per-connection
> > | check "are all advertised CCIDs are loaded?" falls under the table, we
> > | do not need to worry about concurrent access, and loading DCCP implies that
> > | all needed CCIDs are there.
> > Unfortunately this won't work since the CCIDs depend on dccp.ko being
> > fully loaded, so requiring that CCID module are loaded during the
> > loading process of dccp.ko creates a cyclic dependency.
> 
> I don't like this stuff at all.
> 
> Every new connection you're going to loop over the CCID
> table and grab that CCID read lock N times.
> 
> The first time it will do something meaningful, and then
> %99.999999999999 of subsequent calls will do nothing.
> 
> What kind of overhead is deserved by that access pattern?
> 
> And, if the first thing the first connection is going to do
> is load all the modules, there is ZERO reason to make them
> modular.  It's just useless seperation and it adds all of
> this rediculious synchronization.
> 
> If it's modular "for the sake of development" I'm sure you
> can simply reload the dccp.ko module when you make some
> CCID algorithm change.
> 
> I'm tossing this patch set until we get something better
> in this area.

I guess that looking at tcp_set_congestion_control() could be a good
start. 8-)

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16 11:31                                                                                                         ` Michał Mirosław
  -1 siblings, 0 replies; 484+ messages in thread
From: Michał Mirosław @ 2008-12-16 11:31 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: davem, dccp, netdev

2008/12/16 Gerrit Renker <gerrit@erg.abdn.ac.uk>:
> | Since the lock is dropped after checking ccids[id] then there's
> | a window where multiple request_module()s can be called if multiple
> | applications create a DCCP socket at a same time. The code below
> | should do the same without a lock (ccids is a static array,
> | so ccids[N] is always at the same place).
> |
> | static int ccid_request_module(u8 id)
> | {
> |        if (!in_atomic()) {
> |                rmb();
> |                if (ccids[id] == NULL)
> |                        return request_module("net-dccp-ccid-%d", id);
> |        }
> |        return 0;
> | }
> |
> Sorry Michael, but this is really just a "random thought". What you are
> in effect saying is that reader/writer locks can be replaced with just a
> read memory barrier.

> Please have a more detailed look at net/dccp/ccid.c. I also checked how
> other subsystems handle comparable situations of module loading: the
> implementation details differ, but the principle is the same: there are
> mutexes, semaphores, and spinlocks in use to protect those shared
> structures that are related to the loaded module.
>
> Hence your suggestion does not improve the code. I maintain that it is
> correct. And it has proven to work in the test tree for more than one
> year, including tests with up to 100 parallel (iperf) connections.

The read-lock is just a memory barrier here (not a read memory barrier
as I wrote
before) and it's not needed here. If I read the code correctly you are
testing a single
pointer to be NULL and don't really care about ordering wrt module
initialization.

You can actually annotate ccids[] as read_mostly (it's changed only on module
load/unload) and protect it with RCU instead of the home-grown rwlock
you are using.

Best Regards,
Michał Mirosław

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-12-16 11:31                                                                                                         ` Michał Mirosław
  0 siblings, 0 replies; 484+ messages in thread
From: Michał Mirosław @ 2008-12-16 11:31 UTC (permalink / raw)
  To: dccp

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 1935 bytes --]

2008/12/16 Gerrit Renker <gerrit@erg.abdn.ac.uk>:
> | Since the lock is dropped after checking ccids[id] then there's
> | a window where multiple request_module()s can be called if multiple
> | applications create a DCCP socket at a same time. The code below
> | should do the same without a lock (ccids is a static array,
> | so ccids[N] is always at the same place).
> |
> | static int ccid_request_module(u8 id)
> | {
> |        if (!in_atomic()) {
> |                rmb();
> |                if (ccids[id] = NULL)
> |                        return request_module("net-dccp-ccid-%d", id);
> |        }
> |        return 0;
> | }
> |
> Sorry Michael, but this is really just a "random thought". What you are
> in effect saying is that reader/writer locks can be replaced with just a
> read memory barrier.

> Please have a more detailed look at net/dccp/ccid.c. I also checked how
> other subsystems handle comparable situations of module loading: the
> implementation details differ, but the principle is the same: there are
> mutexes, semaphores, and spinlocks in use to protect those shared
> structures that are related to the loaded module.
>
> Hence your suggestion does not improve the code. I maintain that it is
> correct. And it has proven to work in the test tree for more than one
> year, including tests with up to 100 parallel (iperf) connections.

The read-lock is just a memory barrier here (not a read memory barrier
as I wrote
before) and it's not needed here. If I read the code correctly you are
testing a single
pointer to be NULL and don't really care about ordering wrt module
initialization.

You can actually annotate ccids[] as read_mostly (it's changed only on module
load/unload) and protect it with RCU instead of the home-grown rwlock
you are using.

Best Regards,
Micha³ Miros³aw
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·qÊÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16 21:32                                                                                                               ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-16 21:32 UTC (permalink / raw)
  To: acme; +Cc: gerrit, mirqus, dccp, netdev

From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Tue, 16 Dec 2008 09:19:08 -0200

> I guess that looking at tcp_set_congestion_control() could be a good
> start. 8-)

Certainly.

But it seems to me we are dealing with a different situation here
in DCCP.

On the TCP side we have:

1) A default congestion control module, already loaded and
   which has been selected by the admin via a sysctl setting.

2) A socket option facility to select a non-default congestion
   control algorithm to use.

These are both outside of the fast path.

Whereas the DCCP case is right in the connection creation fast path
and unconditionally executes, because it is trying to figure out what
CCID algorithms it can advertise.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16 21:32                                                                                                               ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-16 21:32 UTC (permalink / raw)
  To: dccp

From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Tue, 16 Dec 2008 09:19:08 -0200

> I guess that looking at tcp_set_congestion_control() could be a good
> start. 8-)

Certainly.

But it seems to me we are dealing with a different situation here
in DCCP.

On the TCP side we have:

1) A default congestion control module, already loaded and
   which has been selected by the admin via a sysctl setting.

2) A socket option facility to select a non-default congestion
   control algorithm to use.

These are both outside of the fast path.

Whereas the DCCP case is right in the connection creation fast path
and unconditionally executes, because it is trying to figure out what
CCID algorithms it can advertise.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16 22:25                                                                                                                 ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-16 22:25 UTC (permalink / raw)
  To: David Miller; +Cc: acme, gerrit, mirqus, dccp, netdev

Em Tue, Dec 16, 2008 at 01:32:00PM -0800, David Miller escreveu:
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
> Date: Tue, 16 Dec 2008 09:19:08 -0200
> 
> > I guess that looking at tcp_set_congestion_control() could be a good
> > start. 8-)
> 
> Certainly.
> 
> But it seems to me we are dealing with a different situation here
> in DCCP.
> 
> On the TCP side we have:
> 
> 1) A default congestion control module, already loaded and
>    which has been selected by the admin via a sysctl setting.

Which we should have in DCCP too, its even in the RFC that CCID2 should
be always available, making a good choice for a default one.
 
> 2) A socket option facility to select a non-default congestion
>    control algorithm to use.

This is the same for DCCP, i.e. the app can tell the ones it wants via
setsockopt, and if the default is all they want, no need to ask for
something to be loaded, i.e. ccid2 (or the one that we think should be
the default, like reno -> BIC -> CUBIC) should be always available.
 
> These are both outside of the fast path.
> 
> Whereas the DCCP case is right in the connection creation fast path
> and unconditionally executes, because it is trying to figure out what
> CCID algorithms it can advertise.

Well, there must be some way to locklessly advertise what was previously
loaded (and thus can't ever be unloaded).

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16 22:25                                                                                                                 ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-16 22:25 UTC (permalink / raw)
  To: dccp

Em Tue, Dec 16, 2008 at 01:32:00PM -0800, David Miller escreveu:
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
> Date: Tue, 16 Dec 2008 09:19:08 -0200
> 
> > I guess that looking at tcp_set_congestion_control() could be a good
> > start. 8-)
> 
> Certainly.
> 
> But it seems to me we are dealing with a different situation here
> in DCCP.
> 
> On the TCP side we have:
> 
> 1) A default congestion control module, already loaded and
>    which has been selected by the admin via a sysctl setting.

Which we should have in DCCP too, its even in the RFC that CCID2 should
be always available, making a good choice for a default one.
 
> 2) A socket option facility to select a non-default congestion
>    control algorithm to use.

This is the same for DCCP, i.e. the app can tell the ones it wants via
setsockopt, and if the default is all they want, no need to ask for
something to be loaded, i.e. ccid2 (or the one that we think should be
the default, like reno -> BIC -> CUBIC) should be always available.
 
> These are both outside of the fast path.
> 
> Whereas the DCCP case is right in the connection creation fast path
> and unconditionally executes, because it is trying to figure out what
> CCID algorithms it can advertise.

Well, there must be some way to locklessly advertise what was previously
loaded (and thus can't ever be unloaded).

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-16 23:11                                                                                                                   ` David Miller
  -1 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-16 23:11 UTC (permalink / raw)
  To: acme; +Cc: gerrit, mirqus, dccp, netdev

From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Tue, 16 Dec 2008 20:25:59 -0200

> Em Tue, Dec 16, 2008 at 01:32:00PM -0800, David Miller escreveu:
> > From: Arnaldo Carvalho de Melo <acme@redhat.com>
> > Date: Tue, 16 Dec 2008 09:19:08 -0200
> > 
> > Whereas the DCCP case is right in the connection creation fast path
> > and unconditionally executes, because it is trying to figure out what
> > CCID algorithms it can advertise.
> 
> Well, there must be some way to locklessly advertise what was previously
> loaded (and thus can't ever be unloaded).

This gets us back to my original objection.

Can these things be unloaded?  If not, and they get unconditionally
all loaded up on the first DCCP connection, why make them seperate
modules at all?

If they can get unloaded, then you need synchronization.

I would recommend that everything gets built into dccp.ko
and thus the table is fixed and never changes and thus no
locking nor any of this funny mod loading is needed at all.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-16 23:11                                                                                                                   ` David Miller
  0 siblings, 0 replies; 484+ messages in thread
From: David Miller @ 2008-12-16 23:11 UTC (permalink / raw)
  To: dccp

From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Tue, 16 Dec 2008 20:25:59 -0200

> Em Tue, Dec 16, 2008 at 01:32:00PM -0800, David Miller escreveu:
> > From: Arnaldo Carvalho de Melo <acme@redhat.com>
> > Date: Tue, 16 Dec 2008 09:19:08 -0200
> > 
> > Whereas the DCCP case is right in the connection creation fast path
> > and unconditionally executes, because it is trying to figure out what
> > CCID algorithms it can advertise.
> 
> Well, there must be some way to locklessly advertise what was previously
> loaded (and thus can't ever be unloaded).

This gets us back to my original objection.

Can these things be unloaded?  If not, and they get unconditionally
all loaded up on the first DCCP connection, why make them seperate
modules at all?

If they can get unloaded, then you need synchronization.

I would recommend that everything gets built into dccp.ko
and thus the table is fixed and never changes and thus no
locking nor any of this funny mod loading is needed at all.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-17 13:13                                                                                                                     ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-17 13:13 UTC (permalink / raw)
  To: David Miller; +Cc: gerrit, mirqus, dccp, netdev

Em Tue, Dec 16, 2008 at 03:11:51PM -0800, David Miller escreveu:
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
> Date: Tue, 16 Dec 2008 20:25:59 -0200
> 
> > Em Tue, Dec 16, 2008 at 01:32:00PM -0800, David Miller escreveu:
> > > From: Arnaldo Carvalho de Melo <acme@redhat.com>
> > > Date: Tue, 16 Dec 2008 09:19:08 -0200
> > > 
> > > Whereas the DCCP case is right in the connection creation fast path
> > > and unconditionally executes, because it is trying to figure out what
> > > CCID algorithms it can advertise.
> > 
> > Well, there must be some way to locklessly advertise what was previously
> > loaded (and thus can't ever be unloaded).
> 
> This gets us back to my original objection.
> 
> Can these things be unloaded?  If not, and they get unconditionally
> all loaded up on the first DCCP connection, why make them seperate
> modules at all?
> 
> If they can get unloaded, then you need synchronization.
> 
> I would recommend that everything gets built into dccp.ko
> and thus the table is fixed and never changes and thus no
> locking nor any of this funny mod loading is needed at all.

Perhaps we can have something like we have with the tcp congestion
modules: the modules that are non experimental, because they are already
in an RFC and/or the implementation was deemed stable, should be linked
with dccp.ko and would by default be advertised, i.e. they are the system
wide available CCIDs as configured at kernel build time.

But then, if the user, after he creates the socket, on the slow path,
does a setsockopt asking for a newer CCID (CCID4 is in the works, for
instance) to be advertised for this specific connection or if it asks
for some in the static set of CCIDs _not_ to be advertised, then the
feature negotiation code will advertise the selected set.

Only applications wanting newer stuff will incur the cost of the synch
at connection time while the majority will not incur such costs by
using the penguin peed static CCIDs.

I.e. a VOIP app would say that it is not interested in CCID2, wanting
only CCID3 or CCID4.

IOW we're back to my suggestion on looking at
tcp_set_congestion_control(). :-)

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-17 13:13                                                                                                                     ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-17 13:13 UTC (permalink / raw)
  To: dccp

Em Tue, Dec 16, 2008 at 03:11:51PM -0800, David Miller escreveu:
> From: Arnaldo Carvalho de Melo <acme@redhat.com>
> Date: Tue, 16 Dec 2008 20:25:59 -0200
> 
> > Em Tue, Dec 16, 2008 at 01:32:00PM -0800, David Miller escreveu:
> > > From: Arnaldo Carvalho de Melo <acme@redhat.com>
> > > Date: Tue, 16 Dec 2008 09:19:08 -0200
> > > 
> > > Whereas the DCCP case is right in the connection creation fast path
> > > and unconditionally executes, because it is trying to figure out what
> > > CCID algorithms it can advertise.
> > 
> > Well, there must be some way to locklessly advertise what was previously
> > loaded (and thus can't ever be unloaded).
> 
> This gets us back to my original objection.
> 
> Can these things be unloaded?  If not, and they get unconditionally
> all loaded up on the first DCCP connection, why make them seperate
> modules at all?
> 
> If they can get unloaded, then you need synchronization.
> 
> I would recommend that everything gets built into dccp.ko
> and thus the table is fixed and never changes and thus no
> locking nor any of this funny mod loading is needed at all.

Perhaps we can have something like we have with the tcp congestion
modules: the modules that are non experimental, because they are already
in an RFC and/or the implementation was deemed stable, should be linked
with dccp.ko and would by default be advertised, i.e. they are the system
wide available CCIDs as configured at kernel build time.

But then, if the user, after he creates the socket, on the slow path,
does a setsockopt asking for a newer CCID (CCID4 is in the works, for
instance) to be advertised for this specific connection or if it asks
for some in the static set of CCIDs _not_ to be advertised, then the
feature negotiation code will advertise the selected set.

Only applications wanting newer stuff will incur the cost of the synch
at connection time while the majority will not incur such costs by
using the penguin peed static CCIDs.

I.e. a VOIP app would say that it is not interested in CCID2, wanting
only CCID3 or CCID4.

IOW we're back to my suggestion on looking at
tcp_set_congestion_control(). :-)

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [RFC][PATCH] static builtin CCIDs was  Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
@ 2008-12-17 18:30                                                                                                                         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-17 18:30 UTC (permalink / raw)
  To: David Miller, Gerrit Renker, mirqus, dccp, netdev

Em Wed, Dec 17, 2008 at 04:20:38PM -0200, Arnaldo Carvalho de Melo escreveu:
> > IOW we're back to my suggestion on looking at
> > tcp_set_congestion_control(). :-)
> 
> I tried to test this using ttcp over loopback but the tree seems broken
> somehow, with or without this patch I'm getting:
> 
> Could not activate 0 at /home/acme/git/net-next-2.6/net/dccp/feat.c:1176
> 
> I tried doing a quick chase on this one but failed miserably, Gerrit,
> any ideas?

Well, without the patch the problem was that dccp_ccid2 was not being
autoloaded, as soon as I manually loaded it, ttcp worked. Now to see
why...

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [RFC][PATCH] static builtin CCIDs was  Re: [PATCH 2/5] dccp:
@ 2008-12-17 18:30                                                                                                                         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-17 18:30 UTC (permalink / raw)
  To: dccp

Em Wed, Dec 17, 2008 at 04:20:38PM -0200, Arnaldo Carvalho de Melo escreveu:
> > IOW we're back to my suggestion on looking at
> > tcp_set_congestion_control(). :-)
> 
> I tried to test this using ttcp over loopback but the tree seems broken
> somehow, with or without this patch I'm getting:
> 
> Could not activate 0 at /home/acme/git/net-next-2.6/net/dccp/feat.c:1176
> 
> I tried doing a quick chase on this one but failed miserably, Gerrit,
> any ideas?

Well, without the patch the problem was that dccp_ccid2 was not being
autoloaded, as soon as I manually loaded it, ttcp worked. Now to see
why...

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [RFC][PATCH] static builtin CCIDs was  Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-17 18:30                                                                                                                         ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Arnaldo Carvalho de Melo
@ 2008-12-18  5:41                                                                                                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-18  5:41 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, David Miller, mirqus, dccp, netdev

Quoting Arnaldo:
| Em Wed, Dec 17, 2008 at 04:20:38PM -0200, Arnaldo Carvalho de Melo escreveu:
| > > IOW we're back to my suggestion on looking at
| > > tcp_set_congestion_control(). :-)
| > 
| > I tried to test this using ttcp over loopback but the tree seems broken
| > somehow, with or without this patch I'm getting:
| > 
| > Could not activate 0 at /home/acme/git/net-next-2.6/net/dccp/feat.c:1176
| > 
| > I tried doing a quick chase on this one but failed miserably, Gerrit,
| > any ideas?
| 
| Well, without the patch the problem was that dccp_ccid2 was not being
| autoloaded, as soon as I manually loaded it, ttcp worked. Now to see
| why...
I have acked your patch but haven't had time to compile and test it.
Will do this in due course and integrate it into the test tree. 

With regard to the error message, this says that the feature with index 0
could not be activated. According to table 6.4 in RFC 4340 this is a bug
because it tries to activate a reserved feature.

Will do in-depth testing later on today.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [RFC][PATCH] static builtin CCIDs was  Re: [PATCH 2/5] dccp:
@ 2008-12-18  5:41                                                                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-18  5:41 UTC (permalink / raw)
  To: dccp

Quoting Arnaldo:
| Em Wed, Dec 17, 2008 at 04:20:38PM -0200, Arnaldo Carvalho de Melo escreveu:
| > > IOW we're back to my suggestion on looking at
| > > tcp_set_congestion_control(). :-)
| > 
| > I tried to test this using ttcp over loopback but the tree seems broken
| > somehow, with or without this patch I'm getting:
| > 
| > Could not activate 0 at /home/acme/git/net-next-2.6/net/dccp/feat.c:1176
| > 
| > I tried doing a quick chase on this one but failed miserably, Gerrit,
| > any ideas?
| 
| Well, without the patch the problem was that dccp_ccid2 was not being
| autoloaded, as soon as I manually loaded it, ttcp worked. Now to see
| why...
I have acked your patch but haven't had time to compile and test it.
Will do this in due course and integrate it into the test tree. 

With regard to the error message, this says that the feature with index 0
could not be activated. According to table 6.4 in RFC 4340 this is a bug
because it tries to activate a reserved feature.

Will do in-depth testing later on today.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-18  5:46                                                                                                                       ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-18  5:46 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, David Miller, mirqus, dccp, netdev

[Sorry for being late in replying, this is the answer from yesterday]

I think that if we look too much into the direction of TCP we
might miss some of the notable differences.

In TCP the congestion module stays the same for the lifetime of a
connection and there is no real negotiation. If the TCP congestion
control module is a sender-side only modification then that even
works transparently for any unmodified standard TCP client.

In DCCP the negotiation is more like SIP where both endpoints compare
their capabilities and make a hanshake to vote for a common value.

(Although it is not supported by the current implementation, it
 is in theory possible to re-negotiate a CCID in the middle of
 a connection.  This could for example make sense when
  * a satellite connection suddenly changes, e.g. reduced
    bandwidth due to rain fading;
  * a mobile IP device makes a handoff from Ethernet to WiFi.)



Before a connection, a user can specify/select candidates:

 * he can advertise simply just "everything that is there";
 * the other extreme is to use just a single CCID (where 
   connection might fail due to lack of alternatives).		 

Only the CCIDs requested currently by the users on a system need
to be loaded, but it would make life much simpler if the configured
modules were already loaded.


With regard to "experimental versus standardised" CCIDs, it takes 
actually quite long before a RFC becomes sufficiently standardised.

For the experimental CCIDs I think that David's suggestion is  preferable:

 * for the sake of development we can create a special way of integrating
   whatever kind of new CCID we are testing;
 * instead of complicating the mainline mechanism by implementing answers
   for all (including pathological) possible cases.

Thinking ahead, if in a few years there is suddenly an abundant choice of
practically useful/useable CCIDs then it may make sense to divide CCIDs
into separate modules again, after conquering their implementation.


>From both of your answers I see consensus that at least the standardised
CCIDs should be integrated with dccp.ko. And there is already Arnaldo's
patch to realise this, which is great.

Will integrate Arnaldo's patch with the test tree and the current patch
set. Will be back once this is accomplished.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-18  5:46                                                                                                                       ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-18  5:46 UTC (permalink / raw)
  To: dccp

[Sorry for being late in replying, this is the answer from yesterday]

I think that if we look too much into the direction of TCP we
might miss some of the notable differences.

In TCP the congestion module stays the same for the lifetime of a
connection and there is no real negotiation. If the TCP congestion
control module is a sender-side only modification then that even
works transparently for any unmodified standard TCP client.

In DCCP the negotiation is more like SIP where both endpoints compare
their capabilities and make a hanshake to vote for a common value.

(Although it is not supported by the current implementation, it
 is in theory possible to re-negotiate a CCID in the middle of
 a connection.  This could for example make sense when
  * a satellite connection suddenly changes, e.g. reduced
    bandwidth due to rain fading;
  * a mobile IP device makes a handoff from Ethernet to WiFi.)



Before a connection, a user can specify/select candidates:

 * he can advertise simply just "everything that is there";
 * the other extreme is to use just a single CCID (where 
   connection might fail due to lack of alternatives).		 

Only the CCIDs requested currently by the users on a system need
to be loaded, but it would make life much simpler if the configured
modules were already loaded.


With regard to "experimental versus standardised" CCIDs, it takes 
actually quite long before a RFC becomes sufficiently standardised.

For the experimental CCIDs I think that David's suggestion is  preferable:

 * for the sake of development we can create a special way of integrating
   whatever kind of new CCID we are testing;
 * instead of complicating the mainline mechanism by implementing answers
   for all (including pathological) possible cases.

Thinking ahead, if in a few years there is suddenly an abundant choice of
practically useful/useable CCIDs then it may make sense to divide CCIDs
into separate modules again, after conquering their implementation.


From both of your answers I see consensus that at least the standardised
CCIDs should be integrated with dccp.ko. And there is already Arnaldo's
patch to realise this, which is great.

Will integrate Arnaldo's patch with the test tree and the current patch
set. Will be back once this is accomplished.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-18  5:56                                                                                                           ` Gerrit Renker
  -1 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-18  5:56 UTC (permalink / raw)
  To: Micha? Miros?aw; +Cc: davem, dccp, netdev

| > Hence your suggestion does not improve the code. I maintain that it is
| > correct. And it has proven to work in the test tree for more than one
| > year, including tests with up to 100 parallel (iperf) connections.
| 
| The read-lock is just a memory barrier here (not a read memory barrier
| as I wrote
| before) and it's not needed here. If I read the code correctly you are
| testing a single
| pointer to be NULL and don't really care about ordering wrt module
| initialization.
| 
| You can actually annotate ccids[] as read_mostly (it's changed only on module
| load/unload) and protect it with RCU instead of the home-grown rwlock
| you are using.
| 
Hm the details are not so important here. What is important is that your
observation and questioning whether the code makes sense has lead to 
finding a deeper problem. Without your posting that may not have
happened. So many thanks indeed, if you have any more observations,
please keep them coming.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-18  5:56                                                                                                           ` Gerrit Renker
  0 siblings, 0 replies; 484+ messages in thread
From: Gerrit Renker @ 2008-12-18  5:56 UTC (permalink / raw)
  To: dccp

| > Hence your suggestion does not improve the code. I maintain that it is
| > correct. And it has proven to work in the test tree for more than one
| > year, including tests with up to 100 parallel (iperf) connections.
| 
| The read-lock is just a memory barrier here (not a read memory barrier
| as I wrote
| before) and it's not needed here. If I read the code correctly you are
| testing a single
| pointer to be NULL and don't really care about ordering wrt module
| initialization.
| 
| You can actually annotate ccids[] as read_mostly (it's changed only on module
| load/unload) and protect it with RCU instead of the home-grown rwlock
| you are using.
| 
Hm the details are not so important here. What is important is that your
observation and questioning whether the code makes sense has lead to 
finding a deeper problem. Without your posting that may not have
happened. So many thanks indeed, if you have any more observations,
please keep them coming.

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [RFC][PATCH] static builtin CCIDs was  Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-17 18:30                                                                                                                         ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Arnaldo Carvalho de Melo
@ 2008-12-18 10:55                                                                                                                             ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-18 10:55 UTC (permalink / raw)
  To: Gerrit Renker, David Miller, mirqus, dccp, netdev

Em Thu, Dec 18, 2008 at 06:41:10AM +0100, Gerrit Renker escreveu:
> Quoting Arnaldo:
> | Em Wed, Dec 17, 2008 at 04:20:38PM -0200, Arnaldo Carvalho de Melo escreveu:
> | > > IOW we're back to my suggestion on looking at
> | > > tcp_set_congestion_control(). :-)
> | > 
> | > I tried to test this using ttcp over loopback but the tree seems broken
> | > somehow, with or without this patch I'm getting:
> | > 
> | > Could not activate 0 at /home/acme/git/net-next-2.6/net/dccp/feat.c:1176
> | > 
> | > I tried doing a quick chase on this one but failed miserably, Gerrit,
> | > any ideas?
> | 
> | Well, without the patch the problem was that dccp_ccid2 was not being
> | autoloaded, as soon as I manually loaded it, ttcp worked. Now to see
> | why...
> I have acked your patch but haven't had time to compile and test it.
> Will do this in due course and integrate it into the test tree. 
> 
> With regard to the error message, this says that the feature with index 0
> could not be activated. According to table 6.4 in RFC 4340 this is a bug

I figured that out later, after some more tweaking and systemtapping it
ended up with index 5 failing and that was the ackvec code that was not
being included, just the stubs that always return NULL on the allocation
routine, after that was fixed by removing CONFIG_IP_DCCP_ACKVEC, i.e.
always including that code since CCID2 now is always included, all
worked with a simple, over loopback, ttcp test.

> because it tries to activate a reserved feature.
 
> Will do in-depth testing later on today.

Thanks!

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [RFC][PATCH] static builtin CCIDs was  Re: [PATCH 2/5] dccp:
@ 2008-12-18 10:55                                                                                                                             ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-18 10:55 UTC (permalink / raw)
  To: dccp

Em Thu, Dec 18, 2008 at 06:41:10AM +0100, Gerrit Renker escreveu:
> Quoting Arnaldo:
> | Em Wed, Dec 17, 2008 at 04:20:38PM -0200, Arnaldo Carvalho de Melo escreveu:
> | > > IOW we're back to my suggestion on looking at
> | > > tcp_set_congestion_control(). :-)
> | > 
> | > I tried to test this using ttcp over loopback but the tree seems broken
> | > somehow, with or without this patch I'm getting:
> | > 
> | > Could not activate 0 at /home/acme/git/net-next-2.6/net/dccp/feat.c:1176
> | > 
> | > I tried doing a quick chase on this one but failed miserably, Gerrit,
> | > any ideas?
> | 
> | Well, without the patch the problem was that dccp_ccid2 was not being
> | autoloaded, as soon as I manually loaded it, ttcp worked. Now to see
> | why...
> I have acked your patch but haven't had time to compile and test it.
> Will do this in due course and integrate it into the test tree. 
> 
> With regard to the error message, this says that the feature with index 0
> could not be activated. According to table 6.4 in RFC 4340 this is a bug

I figured that out later, after some more tweaking and systemtapping it
ended up with index 5 failing and that was the ackvec code that was not
being included, just the stubs that always return NULL on the allocation
routine, after that was fixed by removing CONFIG_IP_DCCP_ACKVEC, i.e.
always including that code since CCID2 now is always included, all
worked with a simple, over loopback, ttcp test.

> because it tries to activate a reserved feature.
 
> Will do in-depth testing later on today.

Thanks!

- Arnaldo

^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation
  2008-12-13 13:41                                                                                               ` Gerrit Renker
@ 2008-12-18 14:01                                                                                                                         ` Arnaldo Carvalho de Melo
  -1 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-18 14:01 UTC (permalink / raw)
  To: Gerrit Renker; +Cc: David Miller, mirqus, dccp, netdev

Em Thu, Dec 18, 2008 at 06:46:31AM +0100, Gerrit Renker escreveu:
> [Sorry for being late in replying, this is the answer from yesterday]
> 
> I think that if we look too much into the direction of TCP we
> might miss some of the notable differences.

The look at TCP code was more in the sense that TCP doesn't takes the
lock always, having the default congestion control module builtin and
always "advertised"/used, but allows changing it in a slow path
function.

With the new patch this is what we have now in DCCP too.
 
> In TCP the congestion module stays the same for the lifetime of a
> connection and there is no real negotiation. If the TCP congestion
> control module is a sender-side only modification then that even
> works transparently for any unmodified standard TCP client.
> 
> In DCCP the negotiation is more like SIP where both endpoints compare
> their capabilities and make a hanshake to vote for a common value.
> 
> (Although it is not supported by the current implementation, it
>  is in theory possible to re-negotiate a CCID in the middle of
>  a connection.  This could for example make sense when
>   * a satellite connection suddenly changes, e.g. reduced
>     bandwidth due to rain fading;
>   * a mobile IP device makes a handoff from Ethernet to WiFi.)

And that, at least for CCID2 and CCID3 now can be done wihtout having to
first check if they are loaded, taking locks, etc, that was the crux of
this discussion.

> Before a connection, a user can specify/select candidates:
> 
>  * he can advertise simply just "everything that is there";
>  * the other extreme is to use just a single CCID (where 
>    connection might fail due to lack of alternatives).		 
> 
> Only the CCIDs requested currently by the users on a system need
> to be loaded, but it would make life much simpler if the configured
> modules were already loaded.
> 
> With regard to "experimental versus standardised" CCIDs, it takes 
> actually quite long before a RFC becomes sufficiently standardised.
> 
> For the experimental CCIDs I think that David's suggestion is  preferable:
> 
>  * for the sake of development we can create a special way of integrating
>    whatever kind of new CCID we are testing;
>  * instead of complicating the mainline mechanism by implementing answers
>    for all (including pathological) possible cases.

I believe that the RFCv2 patch I submitted accomplishes these two goals
with a minimal patch to the current code.

And if we look higher up in the stack, say at sock_create we can see
that we have this module loading verification all over again done at
socket creation time for all families, but there it uses RCU, etc, but
it used to be something familiar replaced by Stephen Hemminger in this
cset:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=55737fda0bc73cb20f702301d8b52938a5a43630

Looks familiar? Yes, thats is where the ccid locking scheme came from.
 
> Thinking ahead, if in a few years there is suddenly an abundant choice of
> practically useful/useable CCIDs then it may make sense to divide CCIDs
> into separate modules again, after conquering their implementation.
> 
> 
> >From both of your answers I see consensus that at least the standardised
> CCIDs should be integrated with dccp.ko. And there is already Arnaldo's
> patch to realise this, which is great.
> 
> Will integrate Arnaldo's patch with the test tree and the current patch
> set. Will be back once this is accomplished.

Thanks a lot,

- Arnaldo


^ permalink raw reply	[flat|nested] 484+ messages in thread

* Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for
@ 2008-12-18 14:01                                                                                                                         ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 484+ messages in thread
From: Arnaldo Carvalho de Melo @ 2008-12-18 14:01 UTC (permalink / raw)
  To: dccp

Em Thu, Dec 18, 2008 at 06:46:31AM +0100, Gerrit Renker escreveu:
> [Sorry for being late in replying, this is the answer from yesterday]
> 
> I think that if we look too much into the direction of TCP we
> might miss some of the notable differences.

The look at TCP code was more in the sense that TCP doesn't takes the
lock always, having the default congestion control module builtin and
always "advertised"/used, but allows changing it in a slow path
function.

With the new patch this is what we have now in DCCP too.
 
> In TCP the congestion module stays the same for the lifetime of a
> connection and there is no real negotiation. If the TCP congestion
> control module is a sender-side only modification then that even
> works transparently for any unmodified standard TCP client.
> 
> In DCCP the negotiation is more like SIP where both endpoints compare
> their capabilities and make a hanshake to vote for a common value.
> 
> (Although it is not supported by the current implementation, it
>  is in theory possible to re-negotiate a CCID in the middle of
>  a connection.  This could for example make sense when
>   * a satellite connection suddenly changes, e.g. reduced
>     bandwidth due to rain fading;
>   * a mobile IP device makes a handoff from Ethernet to WiFi.)

And that, at least for CCID2 and CCID3 now can be done wihtout having to
first check if they are loaded, taking locks, etc, that was the crux of
this discussion.

> Before a connection, a user can specify/select candidates:
> 
>  * he can advertise simply just "everything that is there";
>  * the other extreme is to use just a single CCID (where 
>    connection might fail due to lack of alternatives).		 
> 
> Only the CCIDs requested currently by the users on a system need
> to be loaded, but it would make life much simpler if the configured
> modules were already loaded.
> 
> With regard to "experimental versus standardised" CCIDs, it takes 
> actually quite long before a RFC becomes sufficiently standardised.
> 
> For the experimental CCIDs I think that David's suggestion is  preferable:
> 
>  * for the sake of development we can create a special way of integrating
>    whatever kind of new CCID we are testing;
>  * instead of complicating the mainline mechanism by implementing answers
>    for all (including pathological) possible cases.

I believe that the RFCv2 patch I submitted accomplishes these two goals
with a minimal patch to the current code.

And if we look higher up in the stack, say at sock_create we can see
that we have this module loading verification all over again done at
socket creation time for all families, but there it uses RCU, etc, but
it used to be something familiar replaced by Stephen Hemminger in this
cset:

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;hU737fda0bc73cb20f702301d8b52938a5a43630

Looks familiar? Yes, thats is where the ccid locking scheme came from.
 
> Thinking ahead, if in a few years there is suddenly an abundant choice of
> practically useful/useable CCIDs then it may make sense to divide CCIDs
> into separate modules again, after conquering their implementation.
> 
> 
> >From both of your answers I see consensus that at least the standardised
> CCIDs should be integrated with dccp.ko. And there is already Arnaldo's
> patch to realise this, which is great.
> 
> Will integrate Arnaldo's patch with the test tree and the current patch
> set. Will be back once this is accomplished.

Thanks a lot,

- Arnaldo


^ permalink raw reply	[flat|nested] 484+ messages in thread

end of thread, other threads:[~2008-12-18 14:01 UTC | newest]

Thread overview: 484+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <dccp_featneg_last_call_for_comments>
2008-08-28 17:44 ` [PATCH 0/37] dccp: Feature negotiation - last call for comments Gerrit Renker
2008-08-28 17:44   ` Gerrit Renker
2008-08-28 17:44   ` [PATCH 01/37] dccp: Basic data structure for feature negotiation Gerrit Renker
2008-08-28 17:44     ` Gerrit Renker
2008-08-28 17:44     ` [PATCH 02/37] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-08-28 17:44       ` Gerrit Renker
2008-08-28 17:44       ` [PATCH 03/37] dccp: List management for new feature negotiation Gerrit Renker
2008-08-28 17:44         ` Gerrit Renker
2008-08-28 17:44         ` [PATCH 04/37] dccp: Per-socket initialisation of " Gerrit Renker
2008-08-28 17:44           ` Gerrit Renker
2008-08-28 17:44           ` [PATCH 05/37] dccp: Cleanup routines for " Gerrit Renker
2008-08-28 17:44             ` Gerrit Renker
2008-08-28 17:44             ` [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase Gerrit Renker
2008-08-28 17:44               ` Gerrit Renker
2008-08-28 17:44               ` [PATCH 07/37] dccp: Registration routines for changing feature values Gerrit Renker
2008-08-28 17:44                 ` Gerrit Renker
2008-08-28 17:44                 ` [PATCH 08/37] dccp: Query supported CCIDs Gerrit Renker
2008-08-28 17:44                   ` Gerrit Renker
2008-08-28 17:44                   ` [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID Gerrit Renker
2008-08-28 17:44                     ` Gerrit Renker
2008-08-28 17:44                     ` [PATCH 10/37] dccp: Mechanism to resolve CCID dependencies Gerrit Renker
2008-08-28 17:44                       ` Gerrit Renker
2008-08-28 17:44                       ` [PATCH 11/37] dccp: Deprecate old setsockopt framework Gerrit Renker
2008-08-28 17:44                         ` Gerrit Renker
2008-08-28 17:44                         ` [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage Gerrit Renker
2008-08-28 17:44                           ` Gerrit Renker
2008-08-28 17:44                           ` [PATCH 13/37] dccp: Deprecate Ack Ratio sysctl Gerrit Renker
2008-08-28 17:44                             ` Gerrit Renker
2008-08-28 17:44                             ` [PATCH 14/37] dccp: Tidy up setsockopt calls Gerrit Renker
2008-08-28 17:44                               ` Gerrit Renker
2008-08-28 17:44                               ` [PATCH 15/37] dccp: Set per-connection CCIDs via socket options Gerrit Renker
2008-08-28 17:44                                 ` Gerrit Renker
2008-08-28 17:44                                 ` [PATCH 16/37] dccp: API to query the current TX/RX CCID Gerrit Renker
2008-08-28 17:44                                   ` Gerrit Renker
2008-08-28 17:44                                   ` [PATCH 17/37] dccp: Increase the scope of variable-length htonl/ntohl functions Gerrit Renker
2008-08-28 17:44                                     ` Gerrit Renker
2008-08-28 17:44                                     ` [PATCH 18/37] dccp: Support for Mandatory options Gerrit Renker
2008-08-28 17:44                                       ` Gerrit Renker
2008-08-28 17:44                                       ` [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation Gerrit Renker
2008-08-28 17:44                                         ` Gerrit Renker
2008-08-28 17:44                                         ` [PATCH 20/37] dccp: Insert feature-negotiation options into skb Gerrit Renker
2008-08-28 17:44                                           ` Gerrit Renker
2008-08-28 17:44                                           ` [PATCH 21/37] dccp: Integrate feature-negotiation insertion code Gerrit Renker
2008-08-28 17:44                                             ` Gerrit Renker
2008-08-28 17:44                                             ` [PATCH 22/37] dccp: Preference list reconciliation Gerrit Renker
2008-08-28 17:44                                               ` Gerrit Renker
2008-08-28 17:44                                               ` [PATCH 23/37] dccp: Process incoming Change feature-negotiation options Gerrit Renker
2008-08-28 17:44                                                 ` Gerrit Renker
2008-08-28 17:44                                                 ` [PATCH 24/37] dccp: Processing Confirm options Gerrit Renker
2008-08-28 17:44                                                   ` Gerrit Renker
2008-08-28 17:45                                                   ` [PATCH 25/37] dccp: Feature activation handlers Gerrit Renker
2008-08-28 17:45                                                     ` Gerrit Renker
2008-08-28 17:45                                                     ` [PATCH 26/37] dccp: Integration of dynamic feature activation - part 1 (socket setup) Gerrit Renker
2008-08-28 17:45                                                       ` Gerrit Renker
2008-08-28 17:45                                                       ` [PATCH 27/37] dccp: Integration of dynamic feature activation - part 2 (server side) Gerrit Renker
2008-08-28 17:45                                                         ` Gerrit Renker
2008-08-28 17:45                                                         ` [PATCH 28/37] dccp: Integration of dynamic feature activation - part 3 (client side) Gerrit Renker
2008-08-28 17:45                                                           ` Gerrit Renker
2008-08-28 17:45                                                           ` [PATCH 29/37] dccp: Clean up old feature-negotiation infrastructure Gerrit Renker
2008-08-28 17:45                                                             ` Gerrit Renker
2008-08-28 17:45                                                             ` [PATCH 30/37] dccp: Remove obsolete parts of the old CCID interface Gerrit Renker
2008-08-28 17:45                                                               ` Gerrit Renker
2008-08-28 17:45                                                               ` [PATCH 31/37] dccp: Remove manual influence on NDP Count feature Gerrit Renker
2008-08-28 17:45                                                                 ` Gerrit Renker
2008-08-28 17:45                                                                 ` [PATCH 32/37] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl Gerrit Renker
2008-08-28 17:45                                                                   ` Gerrit Renker
2008-08-28 17:45                                                                   ` [PATCH 33/37] dccp: Initialisation framework for feature negotiation Gerrit Renker
2008-08-28 17:45                                                                     ` Gerrit Renker
2008-08-28 17:45                                                                     ` [PATCH 34/37] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-08-28 17:45                                                                       ` Gerrit Renker
2008-08-28 17:45                                                                       ` [PATCH 35/37] dccp: Implement both feature-local and feature-remote Sequence Window feature Gerrit Renker
2008-08-28 17:45                                                                         ` Gerrit Renker
2008-08-28 17:45                                                                         ` [PATCH 36/37] dccp: Initialisation and type-checking of feature sysctls Gerrit Renker
2008-08-28 17:45                                                                           ` Gerrit Renker
2008-08-28 17:45                                                                           ` [PATCH 37/37] dccp: Debugging functions for feature negotiation Gerrit Renker
2008-08-28 17:45                                                                             ` Gerrit Renker
2008-09-02  6:34                                                     ` [PATCH 25/37] dccp: Feature activation handlers Wei Yongjun
2008-09-02  6:34                                                       ` Wei Yongjun
2008-09-03  4:38                                                       ` Gerrit Renker
2008-09-03  4:38                                                         ` Gerrit Renker
2008-09-03  5:42                                                         ` Wei Yongjun
2008-09-03  5:42                                                           ` Wei Yongjun
2008-09-04  5:12                                                           ` Gerrit Renker
2008-09-04  5:12                                                             ` Gerrit Renker
2008-09-02  5:48                                         ` [PATCH 19/37] dccp: Header option insertion routine for feature-negotiation Wei Yongjun
2008-09-02  5:48                                           ` Wei Yongjun
2008-09-03  4:40                                           ` Gerrit Renker
2008-09-03  4:40                                             ` [PATCH 19/37] dccp: Header option insertion routine for Gerrit Renker
2008-08-28 21:50                                       ` [PATCH 18/37] dccp: Support for Mandatory options Arnaldo Carvalho de Melo
2008-08-28 21:50                                         ` Arnaldo Carvalho de Melo
2008-08-28 21:48                                     ` [PATCH 17/37] dccp: Increase the scope of variable-length htonl/ntohl functions Arnaldo Carvalho de Melo
2008-08-28 21:48                                       ` [PATCH 17/37] dccp: Increase the scope of variable-length Arnaldo Carvalho de Melo
2008-08-28 21:47                                   ` [PATCH 16/37] dccp: API to query the current TX/RX CCID Arnaldo Carvalho de Melo
2008-08-28 21:47                                     ` Arnaldo Carvalho de Melo
2008-08-29  7:26                                     ` Gerrit Renker
2008-08-29  7:26                                       ` Gerrit Renker
2008-08-30 13:52                                       ` v2 " Gerrit Renker
2008-08-30 13:52                                         ` Gerrit Renker
2008-08-28 21:45                                 ` [PATCH 15/37] dccp: Set per-connection CCIDs via socket options Arnaldo Carvalho de Melo
2008-08-28 21:45                                   ` Arnaldo Carvalho de Melo
2008-08-29  7:17                                   ` Gerrit Renker
2008-08-29  7:17                                     ` Gerrit Renker
2008-08-30 13:52                                     ` v2 " Gerrit Renker
2008-08-30 13:52                                       ` Gerrit Renker
2008-08-28 21:35                               ` [PATCH 14/37] dccp: Tidy up setsockopt calls Arnaldo Carvalho de Melo
2008-08-28 21:35                                 ` Arnaldo Carvalho de Melo
2008-08-29  6:57                                 ` Gerrit Renker
2008-08-29  6:57                                   ` Gerrit Renker
2008-08-29  9:25                               ` Eugene Teo
2008-08-29  9:25                                 ` Eugene Teo
2008-08-30 13:52                                 ` Gerrit Renker
2008-08-30 13:52                                   ` Gerrit Renker
2008-08-28 21:26                             ` [PATCH 13/37] dccp: Deprecate Ack Ratio sysctl Arnaldo Carvalho de Melo
2008-08-28 21:26                               ` Arnaldo Carvalho de Melo
2008-08-28 21:25                           ` [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage Arnaldo Carvalho de Melo
2008-08-28 21:25                             ` [PATCH 12/37] dccp: Feature negotiation for Arnaldo Carvalho de Melo
2008-08-29  6:47                             ` [PATCH 12/37] dccp: Feature negotiation for minimum-checksum-coverage Gerrit Renker
2008-08-29  6:47                               ` [PATCH 12/37] dccp: Feature negotiation for Gerrit Renker
2008-08-28 21:07                     ` [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID Arnaldo Carvalho de Melo
2008-08-28 21:07                       ` [PATCH 09/37] dccp: Resolve dependencies of features on choice Arnaldo Carvalho de Melo
2008-08-29  6:34                       ` [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID Gerrit Renker
2008-08-29  6:34                         ` [PATCH 09/37] dccp: Resolve dependencies of features on choice Gerrit Renker
2008-09-03  4:51                       ` [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID Gerrit Renker
2008-09-03  4:51                         ` [PATCH 09/37] dccp: Resolve dependencies of features on choice Gerrit Renker
2008-09-04  0:59                         ` [PATCH 09/37] dccp: Resolve dependencies of features on choice of CCID Arnaldo Carvalho de Melo
2008-09-04  0:59                           ` [PATCH 09/37] dccp: Resolve dependencies of features on choice Arnaldo Carvalho de Melo
2008-08-28 21:00                   ` [PATCH 08/37] dccp: Query supported CCIDs Arnaldo Carvalho de Melo
2008-08-28 21:00                     ` Arnaldo Carvalho de Melo
2008-08-29  6:17                     ` Gerrit Renker
2008-08-29  6:17                       ` Gerrit Renker
2008-08-30 13:52                     ` Gerrit Renker
2008-08-30 13:52                       ` Gerrit Renker
2008-08-28 20:54                 ` [PATCH 07/37] dccp: Registration routines for changing feature values Arnaldo Carvalho de Melo
2008-08-28 20:54                   ` [PATCH 07/37] dccp: Registration routines for changing feature Arnaldo Carvalho de Melo
2008-08-29  6:12                   ` [PATCH 07/37] dccp: Registration routines for changing feature values Gerrit Renker
2008-08-29  6:12                     ` [PATCH 07/37] dccp: Registration routines for changing feature Gerrit Renker
2008-09-02  6:12                     ` [PATCH 07/37] dccp: Registration routines for changing feature values Wei Yongjun
2008-09-02  6:12                       ` [PATCH 07/37] dccp: Registration routines for changing feature Wei Yongjun
2008-09-03  4:46                       ` [PATCH 07/37] dccp: Registration routines for changing feature values Gerrit Renker
2008-09-03  4:46                         ` [PATCH 07/37] dccp: Registration routines for changing feature Gerrit Renker
2008-08-28 20:50               ` [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase Arnaldo Carvalho de Melo
2008-08-28 20:50                 ` [PATCH 06/37] dccp: Limit feature negotiation to connection Arnaldo Carvalho de Melo
2008-08-29  5:54                 ` [PATCH 06/37] dccp: Limit feature negotiation to connection setup phase Gerrit Renker
2008-08-29  5:54                   ` [PATCH 06/37] dccp: Limit feature negotiation to connection Gerrit Renker
2008-08-28 19:53           ` [PATCH 04/37] dccp: Per-socket initialisation of feature negotiation Arnaldo Carvalho de Melo
2008-08-28 19:53             ` [PATCH 04/37] dccp: Per-socket initialisation of feature Arnaldo Carvalho de Melo
2008-08-29  5:41             ` [PATCH 04/37] dccp: Per-socket initialisation of feature negotiation Gerrit Renker
2008-08-29  5:41               ` [PATCH 04/37] dccp: Per-socket initialisation of feature Gerrit Renker
2008-08-28 19:43         ` [PATCH 03/37] dccp: List management for new feature negotiation Arnaldo Carvalho de Melo
2008-08-28 19:43           ` Arnaldo Carvalho de Melo
2008-08-29  5:22           ` Gerrit Renker
2008-08-29  5:22             ` Gerrit Renker
2008-08-30 13:51           ` v2 " Gerrit Renker
2008-08-30 13:51             ` Gerrit Renker
2008-08-30 13:51           ` Gerrit Renker
2008-08-30 13:51             ` Gerrit Renker
2008-08-30 17:25           ` [PATCH 0/37] --- Summary of revision changes so far Gerrit Renker
2008-08-30 17:25             ` Gerrit Renker
2008-09-01 16:46             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-01 16:46               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-01 21:20               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-01 21:20                 ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-02 13:50                 ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Arnaldo Carvalho de Melo
2008-09-02 13:50                   ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Arnaldo Carvalho de Melo
2008-09-03  4:24                   ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-03  4:24                     ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-03  6:06                     ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-03  6:06                       ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-03  8:18                       ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-03  8:18                         ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-04  6:15                         ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-04  6:15                           ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-09  0:32                           ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-09  0:32                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-09  8:09                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-09  8:09                               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-09  8:57                               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-09  8:57                                 ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-09 11:59                                 ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-09 11:59                                   ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-09 12:15                                   ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-09 12:15                                     ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-10  5:01                                     ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-10  5:01                                       ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-10  5:19                                       ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-10  5:19                                         ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-11  5:41                                         ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-11  5:41                                           ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-11  5:51                                           ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-11  5:51                                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-11 14:02                                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Arnaldo Carvalho de Melo
2008-09-11 14:02                                               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Arnaldo Carvalho de Melo
2008-09-11 15:57                                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-11 15:57                                               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-11  5:45                                 ` What to do with DCCP (was: net-next-2.6 [pull-request] [PATCH 0/37]...) Gerrit Renker
2008-09-11  5:45                                   ` What to do with DCCP (was: net-next-2.6 [pull-request] [PATCH Gerrit Renker
2008-09-11  5:53                                   ` What to do with DCCP David Miller
2008-09-11  5:53                                     ` David Miller
2008-09-12  5:16                                     ` Gerrit Renker
2008-09-12  5:16                                       ` Gerrit Renker
2008-09-22  4:57                       ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-22  4:57                         ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-22  5:09                         ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-22  5:09                           ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-22  6:28                           ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches Gerrit Renker
2008-09-22  6:28                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of Gerrit Renker
2008-09-22  6:58                             ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of feature-negotiation patches David Miller
2008-09-22  6:58                               ` net-next-2.6 [pull-request] [PATCH 0/37] dccp: Revised set of David Miller
2008-09-22  7:21                               ` [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures Gerrit Renker
2008-09-22  7:21                                 ` Gerrit Renker
2008-09-22  7:21                                 ` [PATCH 1/5] dccp: Basic data structure for feature negotiation Gerrit Renker
2008-09-22  7:21                                   ` Gerrit Renker
2008-09-22  7:21                                   ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-09-22  7:21                                     ` Gerrit Renker
2008-09-22  7:21                                     ` [PATCH 3/5] dccp: List management for new feature negotiation Gerrit Renker
2008-09-22  7:21                                       ` Gerrit Renker
2008-09-22  7:21                                       ` [PATCH 4/5] dccp: Per-socket initialisation of " Gerrit Renker
2008-09-22  7:21                                         ` Gerrit Renker
2008-09-22  7:21                                         ` [PATCH 5/5] dccp: Cleanup routines for " Gerrit Renker
2008-09-22  7:21                                           ` Gerrit Renker
2008-09-22 14:21                                     ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Arnaldo Carvalho de Melo
2008-09-22 14:21                                       ` [PATCH 2/5] dccp: Implement lookup table for Arnaldo Carvalho de Melo
2008-09-22 15:45                                       ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-09-22 15:45                                         ` [PATCH 2/5] dccp: Implement lookup table for Gerrit Renker
2008-09-22 16:49                                         ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Arnaldo Carvalho de Melo
2008-09-22 16:49                                           ` [PATCH 2/5] dccp: Implement lookup table for Arnaldo Carvalho de Melo
2008-09-22 17:00                                         ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Arnaldo Carvalho de Melo
2008-09-22 17:00                                           ` [PATCH 2/5] dccp: Implement lookup table for Arnaldo Carvalho de Melo
2008-09-24  4:41                                           ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-09-24  4:41                                             ` [PATCH 2/5] dccp: Implement lookup table for Gerrit Renker
2008-09-24 13:58                                             ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Arnaldo Carvalho de Melo
2008-09-24 13:58                                               ` [PATCH 2/5] dccp: Implement lookup table for Arnaldo Carvalho de Melo
2008-09-23  3:20                                         ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information David Miller
2008-09-23  3:20                                           ` [PATCH 2/5] dccp: Implement lookup table for David Miller
2008-09-24  5:18                                           ` v2 [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-09-24  5:18                                             ` v2 [PATCH 2/5] dccp: Implement lookup table for Gerrit Renker
2008-09-24  5:23                                             ` v2 [PATCH 1/5] dccp: Basic data structure for feature negotiation Gerrit Renker
2008-09-24  5:23                                               ` Gerrit Renker
2008-09-24 13:59                                               ` Arnaldo Carvalho de Melo
2008-09-24 13:59                                                 ` v2 [PATCH 1/5] dccp: Basic data structure for feature Arnaldo Carvalho de Melo
2008-10-02  5:05                                                 ` [PATCH 0/5] dccp: First part of feature-negotiation patch set Gerrit Renker
2008-10-02  5:05                                                   ` Gerrit Renker
2008-10-02 19:52                                                   ` David Miller
2008-10-02 19:52                                                     ` David Miller
2008-10-04  9:13                                                     ` v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures Gerrit Renker
2008-10-04  9:13                                                       ` Gerrit Renker
2008-10-04  9:13                                                       ` [PATCH 1/5] dccp: Basic data structure for feature negotiation Gerrit Renker
2008-10-04  9:13                                                         ` Gerrit Renker
2008-10-04  9:13                                                         ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-10-04  9:13                                                           ` Gerrit Renker
2008-10-04  9:13                                                           ` [PATCH 3/5] dccp: List management for new feature negotiation Gerrit Renker
2008-10-04  9:13                                                             ` Gerrit Renker
2008-10-04  9:13                                                             ` [PATCH 4/5] dccp: Per-socket initialisation of " Gerrit Renker
2008-10-04  9:13                                                               ` Gerrit Renker
2008-10-04  9:13                                                               ` [PATCH 5/5] dccp: Cleanup routines for " Gerrit Renker
2008-10-04  9:13                                                                 ` Gerrit Renker
2008-10-05 16:13                                                       ` v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures David Miller
2008-10-05 16:13                                                         ` v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying David Miller
2008-10-06  4:14                                                         ` v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures Gerrit Renker
2008-10-06  4:14                                                           ` v2 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying Gerrit Renker
2008-10-11  7:31                                                         ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures Gerrit Renker
2008-10-11  7:31                                                           ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data Gerrit Renker
2008-10-11 18:07                                                           ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures David Miller
2008-10-11 18:07                                                             ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying David Miller
2008-10-13 14:58                                                             ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures Gerrit Renker
2008-10-13 14:58                                                               ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying Gerrit Renker
2008-10-13 18:50                                                               ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures David Miller
2008-10-13 18:50                                                                 ` v3 [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying David Miller
2008-11-05  6:51                                                           ` v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures Gerrit Renker
2008-11-05  6:51                                                             ` v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - Gerrit Renker
2008-11-05  7:56                                                             ` v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - Underlying data structures David Miller
2008-11-05  7:56                                                               ` v3 [Re-Send] [PATCH 0/5] dccp: Feature negotiation, Part I - David Miller
2008-11-06  5:40                                                               ` net-next-2.6 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I (basis) Gerrit Renker
2008-11-06  5:40                                                                 ` Gerrit Renker
2008-11-06  5:40                                                                 ` [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase Gerrit Renker
2008-11-06  5:40                                                                   ` Gerrit Renker
2008-11-06  5:40                                                                   ` [PATCH 2/4] dccp: Registration routines for changing feature values Gerrit Renker
2008-11-06  5:40                                                                     ` Gerrit Renker
2008-11-06  5:40                                                                     ` [PATCH 3/4] dccp: Query supported CCIDs Gerrit Renker
2008-11-06  5:40                                                                       ` Gerrit Renker
2008-11-06  5:40                                                                       ` [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID Gerrit Renker
2008-11-06  5:40                                                                         ` Gerrit Renker
2008-11-10 21:17                                                                         ` David Miller
2008-11-10 21:17                                                                           ` [PATCH 4/4] dccp: Resolve dependencies of features on choice David Miller
2008-11-10 21:20                                                                           ` [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID David Miller
2008-11-10 21:20                                                                             ` [PATCH 4/4] dccp: Resolve dependencies of features on choice David Miller
2008-11-12  6:14                                                                             ` [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID Gerrit Renker
2008-11-12  6:14                                                                               ` [PATCH 4/4] dccp: Resolve dependencies of features on choice Gerrit Renker
2008-11-12  6:37                                                                         ` v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID Gerrit Renker
2008-11-12  6:37                                                                           ` v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of Gerrit Renker
2008-11-12  8:49                                                                           ` v2 [PATCH 4/4] dccp: Resolve dependencies of features on choice of CCID David Miller
2008-11-12  8:49                                                                             ` v2 [PATCH 4/4] dccp: Resolve dependencies of features on David Miller
2008-11-10 21:16                                                                       ` [PATCH 3/4] dccp: Query supported CCIDs David Miller
2008-11-10 21:16                                                                         ` David Miller
2008-11-12  6:37                                                                       ` v2 " Gerrit Renker
2008-11-12  6:37                                                                         ` Gerrit Renker
2008-11-12  8:49                                                                         ` David Miller
2008-11-12  8:49                                                                           ` David Miller
2008-11-10 21:16                                                                     ` [PATCH 2/4] dccp: Registration routines for changing feature values David Miller
2008-11-10 21:16                                                                       ` [PATCH 2/4] dccp: Registration routines for changing feature David Miller
2008-11-12  6:37                                                                     ` v2 [PATCH 2/4] dccp: Registration routines for changing feature values Gerrit Renker
2008-11-12  6:37                                                                       ` v2 [PATCH 2/4] dccp: Registration routines for changing feature Gerrit Renker
2008-11-12  8:49                                                                       ` v2 [PATCH 2/4] dccp: Registration routines for changing feature values David Miller
2008-11-12  8:49                                                                         ` v2 [PATCH 2/4] dccp: Registration routines for changing David Miller
2008-11-10 21:15                                                                   ` [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase David Miller
2008-11-10 21:15                                                                     ` [PATCH 1/4] dccp: Limit feature negotiation to connection David Miller
2008-11-12  6:37                                                                   ` v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase Gerrit Renker
2008-11-12  6:37                                                                     ` v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup Gerrit Renker
2008-11-12  8:49                                                                     ` v2 [PATCH 1/4] dccp: Limit feature negotiation to connection setup phase David Miller
2008-11-12  8:49                                                                       ` v2 [PATCH 1/4] dccp: Limit feature negotiation to connection David Miller
2008-11-12  6:36                                                                 ` v2 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I (basis) Gerrit Renker
2008-11-12  6:36                                                                   ` v2 [PATCH 0/4] dccp: Feature negotiation - conclusion of Part I Gerrit Renker
2008-11-15 12:11                                                                   ` net-next-2.6 [PATCH 0/5] dccp: Feature negotiation - begin of Part II (core) Gerrit Renker
2008-11-15 12:11                                                                     ` Gerrit Renker
2008-11-15 12:11                                                                     ` [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies Gerrit Renker
2008-11-15 12:11                                                                       ` Gerrit Renker
2008-11-15 12:11                                                                       ` [PATCH 2/5] dccp: Deprecate old setsockopt framework Gerrit Renker
2008-11-15 12:11                                                                         ` Gerrit Renker
2008-11-15 12:11                                                                         ` [PATCH 3/5] dccp: Feature negotiation for minimum-checksum-coverage Gerrit Renker
2008-11-15 12:11                                                                           ` Gerrit Renker
2008-11-15 12:11                                                                           ` [PATCH 4/5] dccp: Deprecate Ack Ratio sysctl Gerrit Renker
2008-11-15 12:11                                                                             ` Gerrit Renker
2008-11-15 12:11                                                                             ` [PATCH 5/5] dccp: Tidy up setsockopt calls Gerrit Renker
2008-11-15 12:11                                                                               ` Gerrit Renker
2008-11-17  6:57                                                                               ` David Miller
2008-11-17  6:57                                                                                 ` David Miller
2008-11-17  6:56                                                                             ` [PATCH 4/5] dccp: Deprecate Ack Ratio sysctl David Miller
2008-11-17  6:56                                                                               ` David Miller
2008-11-17  6:53                                                                           ` [PATCH 3/5] dccp: Feature negotiation for minimum-checksum-coverage David Miller
2008-11-17  6:53                                                                             ` [PATCH 3/5] dccp: Feature negotiation for David Miller
2008-11-17  6:53                                                                         ` [PATCH 2/5] dccp: Deprecate old setsockopt framework David Miller
2008-11-17  6:53                                                                           ` David Miller
2008-11-17 15:31                                                                           ` Gerrit Renker
2008-11-17 15:31                                                                             ` Gerrit Renker
2008-11-17  6:50                                                                       ` [PATCH 1/5] dccp: Mechanism to resolve CCID dependencies David Miller
2008-11-17  6:50                                                                         ` David Miller
2008-11-18  5:03                                                                         ` Gerrit Renker
2008-11-18  5:03                                                                           ` Gerrit Renker
2008-11-20  9:03                                                                           ` David Miller
2008-11-20  9:03                                                                             ` David Miller
2008-11-22 10:30                                                                     ` net-next-2.6 [PATCH 0/5] dccp: Feature negotiation - continuation of Part II (core) Gerrit Renker
2008-11-22 10:30                                                                       ` Gerrit Renker
2008-11-22 10:30                                                                       ` [PATCH 1/5] dccp: Set per-connection CCIDs via socket options Gerrit Renker
2008-11-22 10:30                                                                         ` Gerrit Renker
2008-11-22 10:30                                                                         ` [PATCH 2/5] dccp: API to query the current TX/RX CCID Gerrit Renker
2008-11-22 10:30                                                                           ` Gerrit Renker
2008-11-22 10:30                                                                           ` [PATCH 3/5] dccp: Increase the scope of variable-length htonl/ntohl functions Gerrit Renker
2008-11-22 10:30                                                                             ` Gerrit Renker
2008-11-22 10:30                                                                             ` [PATCH 4/5] dccp: Support for Mandatory options Gerrit Renker
2008-11-22 10:30                                                                               ` Gerrit Renker
2008-11-22 10:30                                                                               ` [PATCH 5/5] dccp: Header option insertion routine for feature-negotiation Gerrit Renker
2008-11-22 10:30                                                                                 ` Gerrit Renker
2008-11-24  0:09                                                                               ` [PATCH 4/5] dccp: Support for Mandatory options David Miller
2008-11-24  0:09                                                                                 ` David Miller
2008-11-30 13:22                                                                     ` [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II (core) Gerrit Renker
2008-11-30 13:22                                                                       ` Gerrit Renker
2008-11-30 13:22                                                                       ` [PATCH 1/6] dccp: Insert feature-negotiation options into skb Gerrit Renker
2008-11-30 13:22                                                                         ` Gerrit Renker
2008-11-30 13:22                                                                         ` [PATCH 2/6] dccp: Integrate feature-negotiation insertion code Gerrit Renker
2008-11-30 13:22                                                                           ` Gerrit Renker
2008-11-30 13:22                                                                           ` [PATCH 3/6] dccp: Preference list reconciliation Gerrit Renker
2008-11-30 13:22                                                                             ` Gerrit Renker
2008-11-30 13:22                                                                             ` [PATCH 4/6] dccp: Process incoming Change feature-negotiation options Gerrit Renker
2008-11-30 13:22                                                                               ` Gerrit Renker
2008-11-30 13:22                                                                               ` [PATCH 5/6] dccp: Processing Confirm options Gerrit Renker
2008-11-30 13:22                                                                                 ` Gerrit Renker
2008-11-30 13:22                                                                                 ` [PATCH 6/6] dccp: Feature activation handlers Gerrit Renker
2008-11-30 13:22                                                                                   ` Gerrit Renker
2008-12-02  7:34                                                                       ` [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II (core) David Miller
2008-12-02  7:34                                                                         ` [PATCH 0/6] dccp: Feature negotiation - conclusion of Part II David Miller
2008-12-06 16:40                                                                       ` net-next-2.6 [PATCH 0/7] dccp: Feature negotiation - Part III (integration) Gerrit Renker
2008-12-06 16:40                                                                         ` Gerrit Renker
2008-12-06 16:40                                                                         ` [PATCH 1/7] dccp: Integration of dynamic feature activation - part 1 (socket setup) Gerrit Renker
2008-12-06 16:40                                                                           ` Gerrit Renker
2008-12-06 16:40                                                                           ` [PATCH 2/7] dccp: Integration of dynamic feature activation - part 2 (server side) Gerrit Renker
2008-12-06 16:40                                                                             ` Gerrit Renker
2008-12-06 16:40                                                                             ` [PATCH 3/7] dccp: Integration of dynamic feature activation - part 3 (client side) Gerrit Renker
2008-12-06 16:40                                                                               ` Gerrit Renker
2008-12-06 16:40                                                                               ` [PATCH 4/7] dccp: Clean up old feature-negotiation infrastructure Gerrit Renker
2008-12-06 16:40                                                                                 ` Gerrit Renker
2008-12-06 16:40                                                                                 ` [PATCH 5/7] dccp: Remove obsolete parts of the old CCID interface Gerrit Renker
2008-12-06 16:40                                                                                   ` Gerrit Renker
2008-12-06 16:40                                                                                   ` [PATCH 6/7] dccp: Remove manual influence on NDP Count feature Gerrit Renker
2008-12-06 16:40                                                                                     ` Gerrit Renker
2008-12-06 16:40                                                                                     ` [PATCH 7/7] dccp ccid-2: Phase out the use of boolean Ack Vector sysctl Gerrit Renker
2008-12-06 16:40                                                                                       ` Gerrit Renker
2008-12-08  9:19                                                                                       ` David Miller
2008-12-08  9:19                                                                                         ` [PATCH 7/7] dccp ccid-2: Phase out the use of boolean Ack David Miller
2008-12-13 13:41                                                                                         ` net-next-2.6 [PATCH 0/5] dccp: Feature negotiation part III -- complete Gerrit Renker
2008-12-13 13:41                                                                                           ` Gerrit Renker
2008-12-13 13:41                                                                                           ` [PATCH 1/5] dccp: Initialisation framework for feature negotiation Gerrit Renker
2008-12-13 13:41                                                                                             ` Gerrit Renker
2008-12-13 13:41                                                                                             ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-12-13 13:41                                                                                               ` Gerrit Renker
2008-12-13 13:41                                                                                               ` [PATCH 3/5] dccp: Implement both feature-local and feature-remote Sequence Window feature Gerrit Renker
2008-12-13 13:41                                                                                                 ` Gerrit Renker
2008-12-13 13:41                                                                                                 ` [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls Gerrit Renker
2008-12-13 13:41                                                                                                   ` Gerrit Renker
2008-12-13 13:41                                                                                                   ` [PATCH 5/5] dccp: Debugging functions for feature negotiation Gerrit Renker
2008-12-13 13:41                                                                                                     ` Gerrit Renker
2008-12-15 14:15                                                                                                   ` [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls Arnaldo Carvalho de Melo
2008-12-15 14:15                                                                                                     ` [PATCH 4/5] dccp: Initialisation and type-checking of feature Arnaldo Carvalho de Melo
2008-12-15 14:15                                                                                                     ` Arnaldo Carvalho de Melo
2008-12-15 14:23                                                                                                     ` [PATCH 4/5] dccp: Initialisation and type-checking of feature sysctls walter harms
2008-12-15 14:23                                                                                                       ` [PATCH 4/5] dccp: Initialisation and type-checking of feature walter harms
2008-12-15 14:23                                                                                                       ` walter harms
2008-12-13 13:55                                                                                               ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Michał Mirosław
2008-12-13 13:55                                                                                                 ` Michał Mirosław
2008-12-13 14:56                                                                                                 ` Gerrit Renker
2008-12-13 14:56                                                                                                   ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Gerrit Renker
2008-12-14 14:50                                                                                                   ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Michał Mirosław
2008-12-14 14:50                                                                                                     ` Michał Mirosław
2008-12-15 16:25                                                                                                     ` gerrit
2008-12-15 16:25                                                                                                       ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for gerrit
2008-12-16  5:29                                                                                                       ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-12-16  5:29                                                                                                         ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Gerrit Renker
2008-12-16  9:40                                                                                                         ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation David Miller
2008-12-16  9:40                                                                                                           ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for David Miller
2008-12-16 11:19                                                                                                           ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-16 11:19                                                                                                             ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Arnaldo Carvalho de Melo
2008-12-16 21:32                                                                                                             ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation David Miller
2008-12-16 21:32                                                                                                               ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for David Miller
2008-12-16 22:25                                                                                                               ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-16 22:25                                                                                                                 ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Arnaldo Carvalho de Melo
2008-12-16 23:11                                                                                                                 ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation David Miller
2008-12-16 23:11                                                                                                                   ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for David Miller
2008-12-17 13:13                                                                                                                   ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-17 13:13                                                                                                                     ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Arnaldo Carvalho de Melo
     [not found]                                                                                                                     ` <20081217182038.GV14518@ghostprotocols.net>
2008-12-17 18:30                                                                                                                       ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-17 18:30                                                                                                                         ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Arnaldo Carvalho de Melo
2008-12-18  5:41                                                                                                                         ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-12-18  5:41                                                                                                                           ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Gerrit Renker
2008-12-18 10:55                                                                                                                           ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-18 10:55                                                                                                                             ` [RFC][PATCH] static builtin CCIDs was Re: [PATCH 2/5] dccp: Arnaldo Carvalho de Melo
2008-12-18  5:46                                                                                                                     ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-12-18  5:46                                                                                                                       ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Gerrit Renker
2008-12-18 14:01                                                                                                                       ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-18 14:01                                                                                                                         ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Arnaldo Carvalho de Melo
2008-12-16  5:55                                                                                                     ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-12-16  5:55                                                                                                       ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Gerrit Renker
2008-12-16 11:31                                                                                                       ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Michał Mirosław
2008-12-16 11:31                                                                                                         ` Michał Mirosław
2008-12-18  5:56                                                                                                         ` Gerrit Renker
2008-12-18  5:56                                                                                                           ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Gerrit Renker
2008-12-15 13:48                                                                                               ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Arnaldo Carvalho de Melo
2008-12-15 13:48                                                                                                 ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Arnaldo Carvalho de Melo
2008-12-16  5:44                                                                                                 ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for negotiation Gerrit Renker
2008-12-16  5:44                                                                                                   ` [PATCH 2/5] dccp: Auto-load (when supported) CCID plugins for Gerrit Renker
2008-12-08  9:18                                                                                     ` [PATCH 6/7] dccp: Remove manual influence on NDP Count feature David Miller
2008-12-08  9:18                                                                                       ` David Miller
2008-12-08  9:18                                                                                   ` [PATCH 5/7] dccp: Remove obsolete parts of the old CCID interface David Miller
2008-12-08  9:18                                                                                     ` [PATCH 5/7] dccp: Remove obsolete parts of the old CCID David Miller
2008-12-08  9:17                                                                                 ` [PATCH 4/7] dccp: Clean up old feature-negotiation infrastructure David Miller
2008-12-08  9:17                                                                                   ` [PATCH 4/7] dccp: Clean up old feature-negotiation David Miller
2008-12-08  9:16                                                                               ` [PATCH 3/7] dccp: Integration of dynamic feature activation - part 3 (client side) David Miller
2008-12-08  9:16                                                                                 ` [PATCH 3/7] dccp: Integration of dynamic feature activation - David Miller
2008-12-08  9:16                                                                             ` [PATCH 2/7] dccp: Integration of dynamic feature activation - part 2 (server side) David Miller
2008-12-08  9:16                                                                               ` [PATCH 2/7] dccp: Integration of dynamic feature activation - David Miller
2008-12-08  9:15                                                                           ` [PATCH 1/7] dccp: Integration of dynamic feature activation - part 1 (socket setup) David Miller
2008-12-08  9:15                                                                             ` [PATCH 1/7] dccp: Integration of dynamic feature activation - David Miller
     [not found]                                                         ` <1223312049-25967-1-git-send-email-gerrit@erg.abdn.ac.uk>
2008-10-11  7:31                                                           ` [PATCH 1/5] dccp: Basic data structure for feature negotiation Gerrit Renker
2008-10-11  7:31                                                             ` Gerrit Renker
     [not found]                                                             ` <20081105065208.GC3482@gerrit.erg.abdn.ac.uk>
     [not found]                                                               ` <20081105070109.GH3482@gerrit.erg.abdn.ac.uk>
2008-11-05  7:03                                                                 ` Gerrit Renker
2008-11-05  7:03                                                                   ` Gerrit Renker
     [not found]                                                           ` <1223312049-25967-2-git-send-email-gerrit@erg.abdn.ac.uk>
2008-10-11  7:31                                                             ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-10-11  7:31                                                               ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation Gerrit Renker
2008-11-05  6:52                                                               ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Gerrit Renker
2008-11-05  6:52                                                                 ` [PATCH 2/5] dccp: Implement lookup table for feature-negotiation Gerrit Renker
     [not found]                                                             ` <1223312049-25967-3-git-send-email-gerrit@erg.abdn.ac.uk>
2008-10-11  7:31                                                               ` [PATCH 3/5] dccp: List management for new feature negotiation Gerrit Renker
2008-10-11  7:31                                                                 ` Gerrit Renker
2008-11-05  6:53                                                                 ` Gerrit Renker
2008-11-05  6:53                                                                   ` Gerrit Renker
     [not found]                                                               ` <1223312049-25967-4-git-send-email-gerrit@erg.abdn.ac.uk>
2008-10-11  7:31                                                                 ` [PATCH 4/5] dccp: Per-socket initialisation of " Gerrit Renker
2008-10-11  7:31                                                                   ` Gerrit Renker
2008-11-05  6:53                                                                   ` Gerrit Renker
2008-11-05  6:53                                                                     ` Gerrit Renker
     [not found]                                                                 ` <1223312049-25967-5-git-send-email-gerrit@erg.abdn.ac.uk>
2008-10-11  7:32                                                                   ` [PATCH 5/5] dccp: Cleanup routines for " Gerrit Renker
2008-10-11  7:32                                                                     ` Gerrit Renker
2008-11-05  6:54                                                                     ` Gerrit Renker
2008-11-05  6:54                                                                       ` Gerrit Renker
2008-09-24 14:01                                             ` v2 [PATCH 2/5] dccp: Implement lookup table for feature-negotiation information Arnaldo Carvalho de Melo
2008-09-24 14:01                                               ` v2 [PATCH 2/5] dccp: Implement lookup table for Arnaldo Carvalho de Melo
2008-09-22 14:10                                   ` [PATCH 1/5] dccp: Basic data structure for feature negotiation Arnaldo Carvalho de Melo
2008-09-22 14:10                                     ` Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.