Index: include/linux/dccp.h
===================================================================
--- include/linux/dccp.h.orig	2005-05-06 10:43:42.000000000 -0300
+++ include/linux/dccp.h	2005-05-06 11:15:26.000000000 -0300
@@ -348,9 +348,9 @@
 };
 
 /* initial values for each feature */
+#define DCCPF_INITIAL_CCID			2
 #define DCCPF_INITIAL_SEQUENCE_WINDOW		100
 #define DCCPF_INITIAL_ACK_RATIO			2
-#define DCCPF_INITIAL_CCID			2
 #define DCCPF_INITIAL_ALLOW_SHORT_SEQNOS	1
 #define DCCPF_INITIAL_ECN_INCAPABLE		0
 #define DCCPF_INITIAL_SEND_ACK_VECTOR		0
@@ -376,7 +376,7 @@
 struct dccp_features {
 	__u64			dccpf_old_sequence_window;
 	__u16			dccpf_old_ack_ratio;
-	char			*dccpf_old_ccid;
+	__u8			dccpf_old_ccid;
 	__u8			dccpf_old_allow_short_seqnos;
 	__u8			dccpf_old_ecn_incapable;
 	__u8			dccpf_old_send_ack_vector;
@@ -390,8 +390,9 @@
   * struct dccp_options - option values for a DCCP connection
   *	@dccpo_features - old features' values and their current state
   *	@dccpo_sequence_window - Sequence Window Feature (section 7.5.2)
+  *	@dccpo_ccid_list - CCID preference list
   *	@dccpo_ack_ratio - Ack Ratio Feature (section 11.3)
-  *	@dccpo_ccid - Congestion Control Id (CCID) (section 10)
+  *	@dccpo_ccid - current Congestion Control Id (CCID) (section 10)
   *	@dccpo_allow_short_seqnos - Allow Short Sequence Numbers (section 7.6.1)
   *	@dccpo_ecn_incapable - ECN Incapable Host (section 12.1)
   *	@dccpo_send_ack_vector - Send Ack Vector Feature (section 11.5)
@@ -403,6 +404,7 @@
 struct dccp_options {
 	struct dccp_features	dccpo_features;
 	__u64			dccpo_sequence_window;
+	__u8			*dccpo_ccid_list;
 	__u16			dccpo_ack_ratio;
 	__u8			dccpo_ccid;
 	__u8			dccpo_allow_short_seqnos;
@@ -443,6 +445,7 @@
  * @dccps_gsr - greatest valid sequence number received
  * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss
  * @dccps_client - is this sock a client?
+ * @dccps_options - current stable options
  * @dccps_ndp_count - number of Non Data Packets since last data packet
  * @dccps_hc_rx_ackedpkts - receiver half connection acked packets
  */
Index: net/dccp/dccp_options.c
===================================================================
--- net/dccp/dccp_options.c.orig	2005-05-06 10:44:27.000000000 -0300
+++ net/dccp/dccp_options.c	2005-05-06 12:10:10.000000000 -0300
@@ -19,10 +19,12 @@
 #include <net/dccp.h>
 
 /* stores the default values for new connection. may be changed with sysctl */
+static __u8 dccp_default_ccid_list[] = { 2, 3, 0 };	/* 0 terminated */
 static struct dccp_options dccpo_default_values = {
 	.dccpo_sequence_window	  = DCCPF_INITIAL_SEQUENCE_WINDOW,
 	.dccpo_ack_ratio	  = DCCPF_INITIAL_ACK_RATIO,
 	.dccpo_ccid		  = DCCPF_INITIAL_CCID,
+	.dccpo_ccid_list	  = dccp_default_ccid_list,
 	.dccpo_allow_short_seqnos = DCCPF_INITIAL_ALLOW_SHORT_SEQNOS,
 	.dccpo_ecn_incapable	  = DCCPF_INITIAL_ECN_INCAPABLE,
 	.dccpo_send_ack_vector	  = DCCPF_INITIAL_SEND_ACK_VECTOR,
@@ -127,6 +129,8 @@
 	case DCCPO_CONFIRM_L:
 	case DCCPO_CHANGE_R:
 	case DCCPO_CONFIRM_R:
+		/* FIXME - check if the this option is valid for a server or
+		 * client */
 		if (dh->dccph_type == DCCP_PKT_DATA)
 			rc = -1;
 		break;
@@ -144,12 +148,59 @@
 	return rc;
 }
 
-static int dccp_negotiate_feature(struct sk_buff *skb, char *opt)
+/**
+ * dccp_negotiate_feature - DCCP feature negotiation
+ * 
+ * @sk - sock that owns this packet
+ * @opt - begin of the option
+ */
+static int dccp_negotiate_feature(struct sock *sk, char *opt)
 {
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_options *dccpo = &dp->dccps_options;
+	struct dccp_features *dccpf = &dccpo->dccpo_features;
 	int rc = 0;
+  
+	switch (opt[2]) {
+ 	case DCCPF_CCID:
+	{
+		int f_size = 0, s_size = 0;
+		char *first, *second, *f, *s;
+
+		/* checking if our preference list has priority or the
+		 * other side's */
+		if (opt[0] == DCCPO_CHANGE_R) {
+			/* we're the server */
+			first = dccpo->dccpo_ccid;
+			while (*first++)
+				f_size++;
+			first = dccpo->dccpo_ccid;
+			second = opt + 3;
+			s_size = opt[1];
+		} else {
+			/* we're the client */
+			first = opt + 3;
+			f_size = opt[1];
+			second = dccpo->dccpo_ccid;
+			while (*second++)
+				s_size++;
+			second = dccpo->dccpo_ccid;
+		}
 
-	switch (opt[1]) {
-	case DCCPF_CCID:
+		/* choosing CCID */
+		for (f = first; f - first < f_size; f++) {
+			for (s = second; s - second < s_size; s++) {
+				if (*f == *s) {
+					/* found. updating our current CCID
+					 * and keeping the old CCID */
+					dccpf->dccpf_old_ccid =
+							dccpo->dccpo_ccid; 
+					dccpo->dccpo_ccid = *f;
+				}
+			}
+		}
+		break;
+	}
 	case DCCPF_ALLOW_SHORT_SEQNOS:
 	case DCCPF_SEQUENCE_WINDOW:
 	case DCCPF_ECN_INCAPABLE:
@@ -159,20 +210,17 @@
 	case DCCPF_MIN_CRC_COVERAGE:
 	case DCCPF_CHECK_DATA:
 		break;
-	/* we should silently ignore these features as we
-	 * don't understand it unless marked as mandatory */
+	/* we should send an empty confirm option for these */
 	case DCCPF_RESERVED:
 	case DCCPF_MIN_CCID_SPECIFIC:
 	case DCCPF_MAX_CCID_SPECIFIC:
-		if (mandatory)
-			rc = 1;
+		break;
 	}
 
 	return rc;
 }
 
 /* TODO
- * - we must check if the packet type may carry options
  * - we must check for repeated options
  */
 int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
@@ -412,6 +460,37 @@
 	memcpy(ptr, ap->dccpap_packets + ap->dccpap_head, ap->dccpap_vector_len);
 }
 
+static void dccp_insert_option_ccid(struct sock *sk, struct sk_buff *skb)
+{
+	struct dccp_sock *dp = dccp_sk(sk);
+	struct dccp_options *dccpo = &dp->dccps_options;
+	struct dccp_features *dccpf = &dccpo->dccpo_features;
+
+	/* FIXME - use other thing to indicate we changed CCID by a CHANGE L/R
+	 * option */
+	if (dccpf->dccpf_old_ccid != 0) {
+		/* changed CCID, send confirm */
+		unsigned char *ptr;
+		int llen = 0, len = 4; /* CONFIRM L/R + size + feature # +
+					* selected CCID */
+
+		/* adding CCID preference list size in total length */
+		for (ptr = dccpo->dccpo_ccid_list; *ptr != 0; ptr++, llen++);
+		len += llen;
+
+		if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
+			return;
+
+		DCCP_SKB_CB(skb)->dccpd_opt_len += len;
+
+		ptr = skb_push(skb, len);
+		*ptr++ = /* FIXME */1? CONFIRM_L:CONFIRM_R;
+		*ptr++ = len;
+		*ptr++ = dccpo->dccpo_ccid;
+		memcpy(ptr, dccpo->dccpo_ccid_list, llen);
+	}
+}
+
 void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
 {
 	struct dccp_sock *dp = dccp_sk(sk);
@@ -425,6 +504,10 @@
 	    dp->dccps_hc_rx_ackedpkts->dccpap_nr_packets != 0)
 		dccp_insert_option_ack_vector(sk, skb);
 
+	if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
+		dccp_insert_option_ccid(sk, skb);
+	}
+
 	/* FIXME: insert other options when appropriate */
 
 	if (DCCP_SKB_CB(skb)->dccpd_opt_len != 0) {
