[DCCP]: Use a NULL CCID for benchmarking and debugging

This provides a NULL CCID module for testing and possibly as
basis for developing other (more sophisticated) CCID modules.

Signed-off-by: Gerrit Renker
---
 include/linux/dccp.h    |    1 +
 net/dccp/ccid.c         |    3 +++
 net/dccp/ccids/Kconfig  |    9 +++++++++
 net/dccp/ccids/Makefile |    4 ++++
 net/dccp/ccids/ccid0.c  |   28 ++++++++++++++++++++++++++++
 net/dccp/feat.c         |   12 +++++++++++-
 6 files changed, 56 insertions(+), 1 deletion(-)

--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -173,6 +173,7 @@ enum {
 enum {
 	DCCPC_CCID2 = 2,
 	DCCPC_CCID3 = 3,
+	DCCPC_CCID_NULL = 248,	/* RFC 4340, 19.5: 248..255 are for testing */
 };
 
 /* DCCP features (RFC 4340 section 6.4) */
--- /dev/null
+++ b/net/dccp/ccids/ccid0.c
@@ -0,0 +1,28 @@
+/*
+ *  CCID 248 ("UDP-like"): A non-congestion-control CCID
+ */
+#include "../ccid.h"
+#include "../dccp.h"
+
+static struct ccid_operations ccid0 = {
+	.ccid_id	= DCCPC_CCID_NULL,
+	.ccid_name	= "UDP-like",
+	.ccid_owner	= THIS_MODULE,
+};
+
+static __init int ccid0_module_init(void)
+{
+	return ccid_register(&ccid0);
+}
+module_init(ccid0_module_init);
+
+static __exit void ccid0_module_exit(void)
+{
+	ccid_unregister(&ccid0);
+}
+module_exit(ccid0_module_exit);
+
+MODULE_AUTHOR("Gerrit Renker");
+MODULE_DESCRIPTION("A NULL CCID (no congestion control at all)");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("net-dccp-ccid-248");
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -18,6 +18,9 @@ static u8 builtin_ccids[] = {
 #if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE)
 	DCCPC_CCID3,
 #endif
+#if defined(CONFIG_IP_DCCP_CCID0) || defined(CONFIG_IP_DCCP_CCID0_MODULE)
+	DCCPC_CCID_NULL,
+#endif
 };
 
 static struct ccid_operations *ccids[CCID_MAX];
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -476,7 +476,8 @@ static u8 dccp_feat_is_valid_sp_val(u8 f
 {
 	switch (feat_num) {
 	case DCCPF_CCID:
-		return (val == DCCPC_CCID2 || val == DCCPC_CCID3);
+		return (val == DCCPC_CCID2 || val == DCCPC_CCID3 ||
+			val == DCCPC_CCID_NULL);
 	/* Type-check Boolean feature values: */
 	case DCCPF_SHORT_SEQNOS:
 	case DCCPF_ECN_INCAPABLE:
@@ -780,9 +781,18 @@ static const struct ccid_dependency *dcc
 			{ 0, 0, 0, 0 }
 		}
 	};
+	static const struct ccid_dependency ccid0_dependencies[2][1] = {
+		{	/* Receiver-side dependencies: none */
+			{ 0, 0, 0, 0 },
+		},
+		{	/* Sender-side dependencies: none */
+			{ 0, 0, 0, 0 }
+		}
+	};
 	switch (ccid) {
 	case DCCPC_CCID2: return ccid2_dependencies[is_local];
 	case DCCPC_CCID3: return ccid3_dependencies[is_local];
+	case DCCPC_CCID_NULL: return ccid0_dependencies[is_local];
 	default:	  return NULL;	/* other CCIDs: no specifics yet */
 	}
 }
--- a/net/dccp/ccids/Kconfig
+++ b/net/dccp/ccids/Kconfig
@@ -115,4 +115,13 @@ config IP_DCCP_TFRC_DEBUG
 	bool
 	default y if IP_DCCP_CCID3_DEBUG
 
+config IP_DCCP_CCID0
+	tristate "CCID NULL (UDP-Like) (EXPERIMENTAL)"
+	depends on IP_DCCP_DEBUG
+	def_tristate IP_DCCP
+	---help---
+	  CCID NULL (with experimental ID 248) performs no congestion control
+	  at all. It is not meant for deployment on an Internet, but for
+	  benchmarking and debugging purposes only.
+
 endmenu
--- a/net/dccp/ccids/Makefile
+++ b/net/dccp/ccids/Makefile
@@ -6,4 +6,8 @@ obj-$(CONFIG_IP_DCCP_CCID2) += dccp_ccid
 
 dccp_ccid2-y := ccid2.o
 
+obj-$(CONFIG_IP_DCCP_CCID0) += dccp_ccid0.o
+
+dccp_ccid0-y := ccid0.o
+
 obj-y += lib/
