[DCCP] CCID: Improve CCID infrastructure

1. No need for ->ccid_init nor ->ccid_exit, this is what module_{init,exit}
   does and anynways neither ccid2 nor ccid3 were using it.

2. Rename struct ccid to struct ccid_operations and introduce struct ccid
   with a pointer to ccid_operations and rigth after it the rx or tx
   private state.

3. Remove the pointer to the state of the half connections from struct
   dccp_sock, now its derived thru ccid_priv() from the ccid pointer.

Now we also can implement the setsockopt for changing the CCID easily as
no ccid init routines can affect struct dccp_sock in any way that prevents
other CCIDs from working if a CCID switch operation is asked by apps.

Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h
index de681c6..3dec50d 100644
--- a/net/dccp/ccid.h
+++ b/net/dccp/ccid.h
@@ -23,14 +23,16 @@
 
 struct tcp_info;
 
-struct ccid {
+struct ccid_operations {
 	unsigned char	ccid_id;
 	const char	*ccid_name;
 	struct module	*ccid_owner;
-	int		(*ccid_init)(struct sock *sk);
-	void		(*ccid_exit)(struct sock *sk);
-	int		(*ccid_hc_rx_init)(struct sock *sk);
-	int		(*ccid_hc_tx_init)(struct sock *sk);
+	kmem_cache_t	*ccid_hc_rx_slab;
+	__u32		ccid_hc_rx_obj_size;
+	kmem_cache_t	*ccid_hc_tx_slab;
+	__u32		ccid_hc_tx_obj_size;
+	int		(*ccid_hc_rx_init)(struct ccid *ccid, struct sock *sk);
+	int		(*ccid_hc_tx_init)(struct ccid *ccid, struct sock *sk);
 	void		(*ccid_hc_rx_exit)(struct sock *sk);
 	void		(*ccid_hc_tx_exit)(struct sock *sk);
 	void		(*ccid_hc_rx_packet_recv)(struct sock *sk,
@@ -67,75 +69,58 @@
 						 int __user *optlen);
 };
 
-extern int	   ccid_register(struct ccid *ccid);
-extern int	   ccid_unregister(struct ccid *ccid);
+extern int ccid_register(struct ccid_operations *ccid_ops);
+extern int ccid_unregister(struct ccid_operations *ccid_ops);
 
-extern struct ccid *ccid_init(unsigned char id, struct sock *sk);
-extern void	   ccid_exit(struct ccid *ccid, struct sock *sk);
+struct ccid {
+	struct ccid_operations *ccid_ops;
+	char		       ccid_priv[0];
+};
 
-static inline void __ccid_get(struct ccid *ccid)
+static inline void *ccid_priv(const struct ccid *ccid)
 {
-	__module_get(ccid->ccid_owner);
+	return (void *)ccid->ccid_priv;
 }
 
+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);
+
+extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk);
+extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk);
+
 static inline int ccid_hc_tx_send_packet(struct ccid *ccid, struct sock *sk,
 					 struct sk_buff *skb, int len)
 {
 	int rc = 0;
-	if (ccid->ccid_hc_tx_send_packet != NULL)
-		rc = ccid->ccid_hc_tx_send_packet(sk, skb, len);
+	if (ccid->ccid_ops->ccid_hc_tx_send_packet != NULL)
+		rc = ccid->ccid_ops->ccid_hc_tx_send_packet(sk, skb, len);
 	return rc;
 }
 
 static inline void ccid_hc_tx_packet_sent(struct ccid *ccid, struct sock *sk,
 					  int more, int len)
 {
-	if (ccid->ccid_hc_tx_packet_sent != NULL)
-		ccid->ccid_hc_tx_packet_sent(sk, more, len);
-}
-
-static inline int ccid_hc_rx_init(struct ccid *ccid, struct sock *sk)
-{
-	int rc = 0;
-	if (ccid->ccid_hc_rx_init != NULL)
-		rc = ccid->ccid_hc_rx_init(sk);
-	return rc;
-}
-
-static inline int ccid_hc_tx_init(struct ccid *ccid, struct sock *sk)
-{
-	int rc = 0;
-	if (ccid->ccid_hc_tx_init != NULL)
-		rc = ccid->ccid_hc_tx_init(sk);
-	return rc;
-}
-
-static inline void ccid_hc_rx_exit(struct ccid *ccid, struct sock *sk)
-{
-	if (ccid != NULL && ccid->ccid_hc_rx_exit != NULL &&
-	    dccp_sk(sk)->dccps_hc_rx_ccid_private != NULL)
-		ccid->ccid_hc_rx_exit(sk);
-}
-
-static inline void ccid_hc_tx_exit(struct ccid *ccid, struct sock *sk)
-{
-	if (ccid != NULL && ccid->ccid_hc_tx_exit != NULL &&
-	    dccp_sk(sk)->dccps_hc_tx_ccid_private != NULL)
-		ccid->ccid_hc_tx_exit(sk);
+	if (ccid->ccid_ops->ccid_hc_tx_packet_sent != NULL)
+		ccid->ccid_ops->ccid_hc_tx_packet_sent(sk, more, len);
 }
 
 static inline void ccid_hc_rx_packet_recv(struct ccid *ccid, struct sock *sk,
 					  struct sk_buff *skb)
 {
-	if (ccid->ccid_hc_rx_packet_recv != NULL)
-		ccid->ccid_hc_rx_packet_recv(sk, skb);
+	if (ccid->ccid_ops->ccid_hc_rx_packet_recv != NULL)
+		ccid->ccid_ops->ccid_hc_rx_packet_recv(sk, skb);
 }
 
 static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
 					  struct sk_buff *skb)
 {
-	if (ccid->ccid_hc_tx_packet_recv != NULL)
-		ccid->ccid_hc_tx_packet_recv(sk, skb);
+	if (ccid->ccid_ops->ccid_hc_tx_packet_recv != NULL)
+		ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb);
 }
 
 static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
@@ -144,8 +129,8 @@
 					   unsigned char* value)
 {
 	int rc = 0;
-	if (ccid->ccid_hc_tx_parse_options != NULL)
-		rc = ccid->ccid_hc_tx_parse_options(sk, option, len, idx,
+	if (ccid->ccid_ops->ccid_hc_tx_parse_options != NULL)
+		rc = ccid->ccid_ops->ccid_hc_tx_parse_options(sk, option, len, idx,
 						    value);
 	return rc;
 }
@@ -156,37 +141,37 @@
 					   unsigned char* value)
 {
 	int rc = 0;
-	if (ccid->ccid_hc_rx_parse_options != NULL)
-		rc = ccid->ccid_hc_rx_parse_options(sk, option, len, idx, value);
+	if (ccid->ccid_ops->ccid_hc_rx_parse_options != NULL)
+		rc = ccid->ccid_ops->ccid_hc_rx_parse_options(sk, option, len, idx, value);
 	return rc;
 }
 
 static inline void ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
 					     struct sk_buff *skb)
 {
-	if (ccid->ccid_hc_tx_insert_options != NULL)
-		ccid->ccid_hc_tx_insert_options(sk, skb);
+	if (ccid->ccid_ops->ccid_hc_tx_insert_options != NULL)
+		ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb);
 }
 
 static inline void ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
 					     struct sk_buff *skb)
 {
-	if (ccid->ccid_hc_rx_insert_options != NULL)
-		ccid->ccid_hc_rx_insert_options(sk, skb);
+	if (ccid->ccid_ops->ccid_hc_rx_insert_options != NULL)
+		ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb);
 }
 
 static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk,
 				       struct tcp_info *info)
 {
-	if (ccid->ccid_hc_rx_get_info != NULL)
-		ccid->ccid_hc_rx_get_info(sk, info);
+	if (ccid->ccid_ops->ccid_hc_rx_get_info != NULL)
+		ccid->ccid_ops->ccid_hc_rx_get_info(sk, info);
 }
 
 static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk,
 				       struct tcp_info *info)
 {
-	if (ccid->ccid_hc_tx_get_info != NULL)
-		ccid->ccid_hc_tx_get_info(sk, info);
+	if (ccid->ccid_ops->ccid_hc_tx_get_info != NULL)
+		ccid->ccid_ops->ccid_hc_tx_get_info(sk, info);
 }
 
 static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
@@ -194,8 +179,8 @@
 					u32 __user *optval, int __user *optlen)
 {
 	int rc = -ENOPROTOOPT;
-	if (ccid->ccid_hc_rx_getsockopt != NULL)
-		rc = ccid->ccid_hc_rx_getsockopt(sk, optname, len,
+	if (ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
+		rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len,
 						 optval, optlen);
 	return rc;
 }
@@ -205,8 +190,8 @@
 					u32 __user *optval, int __user *optlen)
 {
 	int rc = -ENOPROTOOPT;
-	if (ccid->ccid_hc_tx_getsockopt != NULL)
-		rc = ccid->ccid_hc_tx_getsockopt(sk, optname, len,
+	if (ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
+		rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len,
 						 optval, optlen);
 	return rc;
 }