source "net/dccp/ccids/Kconfig"
 
+menu "DCCP Kernel Hacking"
+       depends on IP_DCCP=m && DEBUG_KERNEL=y
+
+config IP_DCCP_DEBUG
+       bool "DCCP debug messages"
+       ---help---
+         Only use this if you're hacking DCCP.
+
+         Just say N.
+
+config IP_DCCP_UNLOAD_HACK
+       depends on IP_DCCP_CCID3=m
+       bool "DCCP control sock unload hack"
+       ---help---
+         Enable this to be able to unload the dccp module when the it
+         has only one refcount held, the control sock one. Just execute
+         "rmmod dccp_ccid3 dccp"
+
+         Just say N.
+endmenu
+
 endmenu
 
 
 static __exit void ccid3_module_exit(void)
 {
+#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
+       /*
+        * Hack to use while developing, so that we get rid of the control
+        * sock, that is what keeps a refcount on dccp.ko -acme
+        */
+       extern void dccp_ctl_sock_exit(void);
+
+       dccp_ctl_sock_exit();
+#endif
        ccid_unregister(&ccid3);
 
        if (ccid3_tx_hist != NULL) {
 
  *     published by the Free Software Foundation.
  */
 
+#include <linux/config.h>
 #include <linux/dccp.h>
 #include <net/snmp.h>
 #include <net/sock.h>
 #include <net/tcp.h>
 
-#define DCCP_DEBUG
-
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
 extern int dccp_debug;
 
 #define dccp_pr_debug(format, a...) \
 extern void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap,
                                         struct sock *sk, u64 ackno);
 
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
 extern void dccp_ackvector_print(const u64 ackno,
                                 const unsigned char *vector, int len);
 extern void dccp_ackpkts_print(const struct dccp_ackpkts *ap);
 
 int dccp_parse_options(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
        const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
                                        "CLIENT rx opt: " : "server rx opt: ";
 #endif
                                     struct sk_buff *skb,
                                     u32 elapsed_time)
 {
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
        struct dccp_sock *dp = dccp_sk(sk);
        const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
                                        "CLIENT TX opt: " : "server TX opt: ";
 static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
        const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
                                        "CLIENT TX opt: " : "server TX opt: ";
 #endif
                                              struct sk_buff *skb)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
        const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
                                        "CLIENT TX opt: " : "server TX opt: ";
 #endif
        struct dccp_ackpkts *ap = kmalloc(sizeof(*ap) + len, priority);
 
        if (ap != NULL) {
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
                memset(ap->dccpap_buf, 0xFF, len);
 #endif
                ap->dccpap_buf_len   = len;
 void dccp_ackpkts_free(struct dccp_ackpkts *ap)
 {
        if (ap != NULL) {
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
                memset(ap, 0xFF, sizeof(*ap) + ap->dccpap_buf_len);
 #endif
                kfree(ap);
        return -EILSEQ;
 }
 
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
 void dccp_ackvector_print(const u64 ackno, const unsigned char *vector,
                          int len)
 {
                return;
 
        if (ackno == ap->dccpap_ack_seqno) {
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
                struct dccp_sock *dp = dccp_sk(sk);
                const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
                                        "CLIENT rx ack: " : "server rx ack: ";
                        /* dccp_pr_debug_cat("yes\n"); */
 
                        if (state != DCCP_ACKPKTS_STATE_NOT_RECEIVED) {
-#ifdef DCCP_DEBUG
+#ifdef CONFIG_IP_DCCP_DEBUG
                                struct dccp_sock *dp = dccp_sk(sk);
                                const char *debug_prefix =
                                        dp->dccps_role == DCCP_ROLE_CLIENT ?
 
        return rc;
 }
 
-static void __exit dccp_ctl_sock_exit(void)
+#ifdef CONFIG_IP_DCCP_UNLOAD_HACK
+void dccp_ctl_sock_exit(void)
 {
        if (dccp_ctl_socket != NULL)
                sock_release(dccp_ctl_socket);
 }
 
+EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
+#endif
+
 static int __init init_dccp_v4_mibs(void)
 {
        int rc = -ENOMEM;
 
 static void __exit dccp_fini(void)
 {
-       dccp_ctl_sock_exit();
-
        inet_unregister_protosw(&dccp_v4_protosw);
 
        if (inet_del_protocol(&dccp_protocol, IPPROTO_DCCP) < 0)
                printk(dccp_del_proto_err_msg);
 
-       /* Free the control endpoint.  */
-       sock_release(dccp_ctl_socket);
-
-       proto_unregister(&dccp_v4_prot);
-
+       free_percpu(dccp_statistics[0]);
+       free_percpu(dccp_statistics[1]);
+       free_pages((unsigned long)dccp_hashinfo.bhash,
+                  get_order(dccp_hashinfo.bhash_size *
+                            sizeof(struct inet_bind_hashbucket)));
+       free_pages((unsigned long)dccp_hashinfo.ehash,
+                  get_order(dccp_hashinfo.ehash_size *
+                            sizeof(struct inet_ehash_bucket)));
        kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
+       proto_unregister(&dccp_v4_prot);
 }
 
 module_init(dccp_init);