[DCCP]: Initial feature negotiation implementation

Still needs more work, but boots and doesn't crashes, even
does some negotiation!

18:38:52.174934  127.0.0.1.43458 > 127.0.0.1.5001: request <change_l ack_ratio 2, change_r ccid 2, change_l ccid 2>
18:38:52.218526  127.0.0.1.5001 > 127.0.0.1.43458: response <nop, nop, change_l ack_ratio 2, confirm_r ccid 2 2, confirm_l ccid 2 2, confirm_r ack_ratio 2>
18:38:52.185398  127.0.0.1.43458 > 127.0.0.1.5001: <nop, confirm_r ack_ratio 2, ack_vector0 0x00, elapsed_time 212>

:-)

Signed-off-by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 38321ad..fcfb486 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -28,6 +28,7 @@
 #include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
+#include "feat.h"
 
 struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
 	.lhash_lock	= RW_LOCK_UNLOCKED,
@@ -535,7 +536,8 @@
 	if (req == NULL)
 		goto drop;
 
-	/* FIXME: process options */
+	if (dccp_parse_options(sk, skb))
+		goto drop;
 
 	dccp_openreq_init(req, &dp, skb);
 
@@ -1049,6 +1051,8 @@
 	 * setsockopt(CCIDs-I-want/accept). -acme
 	 */
 	if (likely(!dccp_ctl_socket_init)) {
+		int rc;
+
 		if (dp->dccps_options.dccpo_send_ack_vector) {
 			dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL);
 			if (dp->dccps_hc_rx_ackvec == NULL)
@@ -1069,8 +1073,16 @@
 			dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 			return -ENOMEM;
 		}
-	} else
+
+		rc = dccp_feat_init(sk);
+		if (rc)
+			return rc;
+	} else {
+		/* control socket doesn't need feat nego */
+		INIT_LIST_HEAD(&dp->dccps_options.dccpo_pending);
+		INIT_LIST_HEAD(&dp->dccps_options.dccpo_conf);
 		dccp_ctl_socket_init = 0;
+	}
 
 	dccp_init_xmit_timers(sk);
 	icsk->icsk_rto = DCCP_TIMEOUT_INIT;
@@ -1118,6 +1130,9 @@
 	ccid_exit(dp->dccps_hc_tx_ccid, sk);
 	dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
 
+	/* clean up feature negotiation state */
+	dccp_feat_clean(sk);
+
 	return 0;
 }