]> err.no Git - linux-2.6/blobdiff - net/dccp/proto.c
[PATCH] sunrpc: cache_register can use wrong module reference
[linux-2.6] / net / dccp / proto.c
index 70284e6afe05cda3df8b83cd2dccd502f8b838af..18a0e69c9dc75f709e15be01e7ef6def17de3eb5 100644 (file)
@@ -39,7 +39,7 @@
 #include "ccid.h"
 #include "dccp.h"
 
-DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics);
+DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly;
 
 atomic_t dccp_orphan_count = ATOMIC_INIT(0);
 
@@ -140,6 +140,62 @@ int dccp_disconnect(struct sock *sk, int flags)
        return err;
 }
 
+/*
+ *     Wait for a DCCP event.
+ *
+ *     Note that we don't need to lock the socket, as the upper poll layers
+ *     take care of normal races (between the test and the event) and we don't
+ *     go look at any of the socket buffers directly.
+ */
+static unsigned int dccp_poll(struct file *file, struct socket *sock,
+                             poll_table *wait)
+{
+       unsigned int mask;
+       struct sock *sk = sock->sk;
+
+       poll_wait(file, sk->sk_sleep, wait);
+       if (sk->sk_state == DCCP_LISTEN)
+               return inet_csk_listen_poll(sk);
+
+       /* Socket is not locked. We are protected from async events
+          by poll logic and correct handling of state changes
+          made by another threads is impossible in any case.
+        */
+
+       mask = 0;
+       if (sk->sk_err)
+               mask = POLLERR;
+
+       if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == DCCP_CLOSED)
+               mask |= POLLHUP;
+       if (sk->sk_shutdown & RCV_SHUTDOWN)
+               mask |= POLLIN | POLLRDNORM;
+
+       /* Connected? */
+       if ((1 << sk->sk_state) & ~(DCCPF_REQUESTING | DCCPF_RESPOND)) {
+               if (atomic_read(&sk->sk_rmem_alloc) > 0)
+                       mask |= POLLIN | POLLRDNORM;
+
+               if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
+                       if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk)) {
+                               mask |= POLLOUT | POLLWRNORM;
+                       } else {  /* send SIGIO later */
+                               set_bit(SOCK_ASYNC_NOSPACE,
+                                       &sk->sk_socket->flags);
+                               set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
+
+                               /* Race breaker. If space is freed after
+                                * wspace test but before the flags are set,
+                                * IO signal will be lost.
+                                */
+                               if (sk_stream_wspace(sk) >= sk_stream_min_wspace(sk))
+                                       mask |= POLLOUT | POLLWRNORM;
+                       }
+               }
+       }
+       return mask;
+}
+
 int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
        dccp_pr_debug("entry\n");
@@ -147,25 +203,69 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 }
 
 int dccp_setsockopt(struct sock *sk, int level, int optname,
-                   char *optval, int optlen)
+                   char __user *optval, int optlen)
 {
-       dccp_pr_debug("entry\n");
+       struct dccp_sock *dp;
+       int err;
+       int val;
 
        if (level != SOL_DCCP)
                return ip_setsockopt(sk, level, optname, optval, optlen);
 
-       return -EOPNOTSUPP;
+       if (optlen < sizeof(int))
+               return -EINVAL;
+
+       if (get_user(val, (int __user *)optval))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       dp = dccp_sk(sk);
+       err = 0;
+
+       switch (optname) {
+       case DCCP_SOCKOPT_PACKET_SIZE:
+               dp->dccps_packet_size = val;
+               break;
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+       
+       release_sock(sk);
+       return err;
 }
 
 int dccp_getsockopt(struct sock *sk, int level, int optname,
-                   char *optval, int *optlen)
+                   char __user *optval, int __user *optlen)
 {
-       dccp_pr_debug("entry\n");
+       struct dccp_sock *dp;
+       int val, len;
 
        if (level != SOL_DCCP)
                return ip_getsockopt(sk, level, optname, optval, optlen);
 
-       return -EOPNOTSUPP;
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       len = min_t(unsigned int, len, sizeof(int));
+       if (len < 0)
+               return -EINVAL;
+
+       dp = dccp_sk(sk);
+
+       switch (optname) {
+       case DCCP_SOCKOPT_PACKET_SIZE:
+               val = dp->dccps_packet_size;
+               break;
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, &val, len))
+               return -EFAULT;
+
+       return 0;
 }
 
 int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
@@ -182,8 +282,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                return -EMSGSIZE;
 
        lock_sock(sk);
-
-       timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
+       timeo = sock_sndtimeo(sk, noblock);
 
        /*
         * We have to use sk_stream_wait_connect here to set sk_write_pending,
@@ -192,265 +291,136 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        /* Wait for a connection to finish. */
        if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN | DCCPF_CLOSING))
                if ((rc = sk_stream_wait_connect(sk, &timeo)) != 0)
-                       goto out_err;
+                       goto out_release;
 
        size = sk->sk_prot->max_header + len;
        release_sock(sk);
        skb = sock_alloc_send_skb(sk, size, noblock, &rc);
        lock_sock(sk);
-
        if (skb == NULL)
                goto out_release;
 
        skb_reserve(skb, sk->sk_prot->max_header);
        rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
-       if (rc == 0) {
-               struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
-               const struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts;
-               long delay; 
-
-               /*
-                * XXX: This is just to match the Waikato tree CA interaction
-                * points, after the CCID3 code is stable and I have a better
-                * understanding of behaviour I'll change this to look more like
-                * TCP.
-                */
-               while (1) {
-                       rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk,
-                                                   skb, len, &delay);
-                       if (rc == 0)
-                               break;
-                       if (rc != -EAGAIN)
-                               goto out_discard;
-                       if (delay > timeo)
-                               goto out_discard;
-                       release_sock(sk);
-                       delay = schedule_timeout(delay);
-                       lock_sock(sk);
-                       timeo -= delay;
-                       if (signal_pending(current))
-                               goto out_interrupted;
-                       rc = -EPIPE;
-                       if (!(sk->sk_state == DCCP_PARTOPEN || sk->sk_state == DCCP_OPEN))
-                               goto out_discard;
-               }
+       if (rc != 0)
+               goto out_discard;
 
-               if (sk->sk_state == DCCP_PARTOPEN) {
-                       /* See 8.1.5.  Handshake Completion */
-                       inet_csk_schedule_ack(sk);
-                       inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
-                       dcb->dccpd_type = DCCP_PKT_DATAACK;
-                       /* FIXME: we really should have a dccps_ack_pending or use icsk */
-               } else if (inet_csk_ack_scheduled(sk) ||
-                          (dp->dccps_options.dccpo_send_ack_vector &&
-                           ap->dccpap_buf_ackno != DCCP_MAX_SEQNO + 1 &&
-                           ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1))
-                       dcb->dccpd_type = DCCP_PKT_DATAACK;
-               else
-                       dcb->dccpd_type = DCCP_PKT_DATA;
-               dccp_transmit_skb(sk, skb);
-               ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
-       } else {
-out_discard:
-               kfree_skb(skb);
-       }
+       rc = dccp_write_xmit(sk, skb, &timeo);
+       /*
+        * XXX we don't use sk_write_queue, so just discard the packet.
+        *     Current plan however is to _use_ sk_write_queue with
+        *     an algorith similar to tcp_sendmsg, where the main difference
+        *     is that in DCCP we have to respect packet boundaries, so
+        *     no coalescing of skbs.
+        *
+        *     This bug was _quickly_ found & fixed by just looking at an OSTRA
+        *     generated callgraph 8) -acme
+        */
+       if (rc != 0)
+               goto out_discard;
 out_release:
        release_sock(sk);
        return rc ? : len;
-out_err:
-       rc = sk_stream_error(sk, flags, rc);
+out_discard:
+       kfree_skb(skb);
        goto out_release;
-out_interrupted:
-       rc = sock_intr_errno(timeo);
-       goto out_discard;
 }
 
-EXPORT_SYMBOL(dccp_sendmsg);
-
 int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len, int nonblock, int flags, int *addr_len)
 {
        const struct dccp_hdr *dh;
-       int copied = 0;
-       unsigned long used;
-       int err;
-       int target;             /* Read at least this many bytes */
        long timeo;
 
        lock_sock(sk);
 
-       err = -ENOTCONN;
-       if (sk->sk_state == DCCP_LISTEN)
+       if (sk->sk_state == DCCP_LISTEN) {
+               len = -ENOTCONN;
                goto out;
-
-       timeo = sock_rcvtimeo(sk, nonblock);
-
-       /* Urgent data needs to be handled specially. */
-       if (flags & MSG_OOB)
-               goto recv_urg;
-
-       /* FIXME */
-#if 0
-       seq = &tp->copied_seq;
-       if (flags & MSG_PEEK) {
-               peek_seq = tp->copied_seq;
-               seq = &peek_seq;
        }
-#endif
 
-       target = sock_rcvlowat(sk, flags & MSG_WAITALL, len);
+       timeo = sock_rcvtimeo(sk, nonblock);
 
        do {
-               struct sk_buff *skb;
-               u32 offset;
-
-       /* FIXME */
-#if 0
-               /* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */
-               if (tp->urg_data && tp->urg_seq == *seq) {
-                       if (copied)
-                               break;
-                       if (signal_pending(current)) {
-                               copied = timeo ? sock_intr_errno(timeo) : -EAGAIN;
-                               break;
-                       }
-               }
-#endif
-
-               /* Next get a buffer. */
+               struct sk_buff *skb = skb_peek(&sk->sk_receive_queue);
 
-               skb = skb_peek(&sk->sk_receive_queue);
-               do {
-                       if (!skb)
-                               break;
-
-                       offset = 0;
-                       dh = dccp_hdr(skb);
+               if (skb == NULL)
+                       goto verify_sock_status;
 
-                       if (dh->dccph_type == DCCP_PKT_DATA ||
-                           dh->dccph_type == DCCP_PKT_DATAACK)
-                               goto found_ok_skb;
+               dh = dccp_hdr(skb);
 
-                       if (dh->dccph_type == DCCP_PKT_RESET ||
-                           dh->dccph_type == DCCP_PKT_CLOSE) {
-                               dccp_pr_debug("found fin ok!\n");
-                               goto found_fin_ok;
-                       }
-                       dccp_pr_debug("packet_type=%s\n", dccp_packet_name(dh->dccph_type));
-                       BUG_TRAP(flags & MSG_PEEK);
-                       skb = skb->next;
-               } while (skb != (struct sk_buff *)&sk->sk_receive_queue);
+               if (dh->dccph_type == DCCP_PKT_DATA ||
+                   dh->dccph_type == DCCP_PKT_DATAACK)
+                       goto found_ok_skb;
 
-               /* Well, if we have backlog, try to process it now yet. */
-               if (copied >= target && !sk->sk_backlog.tail)
+               if (dh->dccph_type == DCCP_PKT_RESET ||
+                   dh->dccph_type == DCCP_PKT_CLOSE) {
+                       dccp_pr_debug("found fin ok!\n");
+                       len = 0;
+                       goto found_fin_ok;
+               }
+               dccp_pr_debug("packet_type=%s\n",
+                             dccp_packet_name(dh->dccph_type));
+               sk_eat_skb(sk, skb);
+verify_sock_status:
+               if (sock_flag(sk, SOCK_DONE)) {
+                       len = 0;
                        break;
+               }
 
-               if (copied) {
-                       if (sk->sk_err ||
-                           sk->sk_state == DCCP_CLOSED ||
-                           (sk->sk_shutdown & RCV_SHUTDOWN) ||
-                           !timeo ||
-                           signal_pending(current) ||
-                           (flags & MSG_PEEK))
-                               break;
-               } else {
-                       if (sock_flag(sk, SOCK_DONE))
-                               break;
-
-                       if (sk->sk_err) {
-                               copied = sock_error(sk);
-                               break;
-                       }
-
-                       if (sk->sk_shutdown & RCV_SHUTDOWN)
-                               break;
-
-                       if (sk->sk_state == DCCP_CLOSED) {
-                               if (!sock_flag(sk, SOCK_DONE)) {
-                                       /* This occurs when user tries to read
-                                        * from never connected socket.
-                                        */
-                                       copied = -ENOTCONN;
-                                       break;
-                               }
-                               break;
-                       }
+               if (sk->sk_err) {
+                       len = sock_error(sk);
+                       break;
+               }
 
-                       if (!timeo) {
-                               copied = -EAGAIN;
-                               break;
-                       }
+               if (sk->sk_shutdown & RCV_SHUTDOWN) {
+                       len = 0;
+                       break;
+               }
 
-                       if (signal_pending(current)) {
-                               copied = sock_intr_errno(timeo);
+               if (sk->sk_state == DCCP_CLOSED) {
+                       if (!sock_flag(sk, SOCK_DONE)) {
+                               /* This occurs when user tries to read
+                                * from never connected socket.
+                                */
+                               len = -ENOTCONN;
                                break;
                        }
+                       len = 0;
+                       break;
                }
 
-               /* FIXME: cleanup_rbuf(sk, copied); */
+               if (!timeo) {
+                       len = -EAGAIN;
+                       break;
+               }
 
-               if (copied >= target) {
-                       /* Do not sleep, just process backlog. */
-                       release_sock(sk);
-                       lock_sock(sk);
-               } else
-                       sk_wait_data(sk, &timeo);
+               if (signal_pending(current)) {
+                       len = sock_intr_errno(timeo);
+                       break;
+               }
 
+               sk_wait_data(sk, &timeo);
                continue;
-
        found_ok_skb:
-               /* Ok so how much can we use? */
-               used = skb->len - offset;
-               if (len < used)
-                       used = len;
-
-               if (!(flags & MSG_TRUNC)) {
-                       err = skb_copy_datagram_iovec(skb, offset,
-                                                     msg->msg_iov, used);
-                       if (err) {
-                               /* Exception. Bailout! */
-                               if (!copied)
-                                       copied = -EFAULT;
-                               break;
-                       }
+               if (len > skb->len)
+                       len = skb->len;
+               else if (len < skb->len)
+                       msg->msg_flags |= MSG_TRUNC;
+
+               if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len)) {
+                       /* Exception. Bailout! */
+                       len = -EFAULT;
+                       break;
                }
-
-               copied += used;
-               len -= used;
-
-               /* FIXME: tcp_rcv_space_adjust(sk); */
-
-//skip_copy:
-               if (used + offset < skb->len)
-                       continue;
-
-               if (!(flags & MSG_PEEK))
-                       sk_eat_skb(sk, skb);
-               continue;
        found_fin_ok:
                if (!(flags & MSG_PEEK))
                        sk_eat_skb(sk, skb);
                break;
-               
-       } while (len > 0);
-
-       /* According to UNIX98, msg_name/msg_namelen are ignored
-        * on connected socket. I was just happy when found this 8) --ANK
-        */
-
-       /* Clean up data we have read: This will do ACK frames. */
-       /* FIXME: cleanup_rbuf(sk, copied); */
-
-       release_sock(sk);
-       return copied;
-
+       } while (1);
 out:
        release_sock(sk);
-       return err;
-
-recv_urg:
-       /* FIXME: err = tcp_recv_urg(sk, timeo, msg, len, flags, addr_len); */
-       goto out;
+       return len;
 }
 
 static int inet_dccp_listen(struct socket *sock, int backlog)
@@ -490,16 +460,16 @@ out:
 }
 
 static const unsigned char dccp_new_state[] = {
-       /* current state:        new state:      action:        */
-       [0]                     = DCCP_CLOSED,
-       [DCCP_OPEN]             = DCCP_CLOSING | DCCP_ACTION_FIN,
-       [DCCP_REQUESTING]       = DCCP_CLOSED,
-       [DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
-       [DCCP_LISTEN]           = DCCP_CLOSED,
-       [DCCP_RESPOND]  = DCCP_CLOSED,
-       [DCCP_CLOSING]  = DCCP_CLOSED,
-       [DCCP_TIME_WAIT]        = DCCP_CLOSED,
-       [DCCP_CLOSED]   = DCCP_CLOSED,
+       /* current state:   new state:      action:     */
+       [0]               = DCCP_CLOSED,
+       [DCCP_OPEN]       = DCCP_CLOSING | DCCP_ACTION_FIN,
+       [DCCP_REQUESTING] = DCCP_CLOSED,
+       [DCCP_PARTOPEN]   = DCCP_CLOSING | DCCP_ACTION_FIN,
+       [DCCP_LISTEN]     = DCCP_CLOSED,
+       [DCCP_RESPOND]    = DCCP_CLOSED,
+       [DCCP_CLOSING]    = DCCP_CLOSED,
+       [DCCP_TIME_WAIT]  = DCCP_CLOSED,
+       [DCCP_CLOSED]     = DCCP_CLOSED,
 };
 
 static int dccp_close_state(struct sock *sk)
@@ -544,12 +514,15 @@ void dccp_close(struct sock *sk, long timeout)
                /* Check zero linger _after_ checking for unread data. */
                sk->sk_prot->disconnect(sk, 0);
        } else if (dccp_close_state(sk)) {
-               dccp_send_close(sk);
+               dccp_send_close(sk, 1);
        }
 
        sk_stream_wait_close(sk, timeout);
 
 adjudge_to_death:
+       /*
+        * It is the last release_sock in its life. It will remove backlog.
+        */
        release_sock(sk);
        /*
         * Now socket is owned by kernel and we acquire BH lock
@@ -561,11 +534,26 @@ adjudge_to_death:
 
        sock_hold(sk);
        sock_orphan(sk);
-                                               
-       if (sk->sk_state != DCCP_CLOSED)
+
+       /*
+        * The last release_sock may have processed the CLOSE or RESET
+        * packet moving sock to CLOSED state, if not we have to fire
+        * the CLOSE/CLOSEREQ retransmission timer, see "8.3. Termination"
+        * in draft-ietf-dccp-spec-11. -acme
+        */
+       if (sk->sk_state == DCCP_CLOSING) {
+               /* FIXME: should start at 2 * RTT */
+               /* Timer for repeating the CLOSE/CLOSEREQ until an answer. */
+               inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
+                                         inet_csk(sk)->icsk_rto,
+                                         DCCP_RTO_MAX);
+#if 0
+               /* Yeah, we should use sk->sk_prot->orphan_count, etc */
                dccp_set_state(sk, DCCP_CLOSED);
+#endif
+       }
 
-       atomic_inc(&dccp_orphan_count);
+       atomic_inc(sk->sk_prot->orphan_count);
        if (sk->sk_state == DCCP_CLOSED)
                inet_csk_destroy_sock(sk);
 
@@ -581,7 +569,7 @@ void dccp_shutdown(struct sock *sk, int how)
        dccp_pr_debug("entry\n");
 }
 
-struct proto_ops inet_dccp_ops = {
+static struct proto_ops inet_dccp_ops = {
        .family         = PF_INET,
        .owner          = THIS_MODULE,
        .release        = inet_release,
@@ -590,9 +578,11 @@ struct proto_ops inet_dccp_ops = {
        .socketpair     = sock_no_socketpair,
        .accept         = inet_accept,
        .getname        = inet_getname,
-       .poll           = sock_no_poll,
+       /* FIXME: work on tcp_poll to rename it to inet_csk_poll */
+       .poll           = dccp_poll,
        .ioctl          = inet_ioctl,
-       .listen         = inet_dccp_listen, /* FIXME: work on inet_listen to rename it to sock_common_listen */
+       /* FIXME: work on inet_listen to rename it to sock_common_listen */
+       .listen         = inet_dccp_listen,
        .shutdown       = inet_shutdown,
        .setsockopt     = sock_common_setsockopt,
        .getsockopt     = sock_common_getsockopt,
@@ -644,12 +634,18 @@ static int __init dccp_ctl_sock_init(void)
        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)
+       if (dccp_ctl_socket != NULL) {
                sock_release(dccp_ctl_socket);
+               dccp_ctl_socket = NULL;
+       }
 }
 
+EXPORT_SYMBOL_GPL(dccp_ctl_sock_exit);
+#endif
+
 static int __init init_dccp_v4_mibs(void)
 {
        int rc = -ENOMEM;
@@ -676,9 +672,11 @@ static int thash_entries;
 module_param(thash_entries, int, 0444);
 MODULE_PARM_DESC(thash_entries, "Number of ehash buckets");
 
+#ifdef CONFIG_IP_DCCP_DEBUG
 int dccp_debug;
 module_param(dccp_debug, int, 0444);
 MODULE_PARM_DESC(dccp_debug, "Enable debug messages");
+#endif
 
 static int __init dccp_init(void)
 {
@@ -689,10 +687,10 @@ static int __init dccp_init(void)
        if (rc)
                goto out;
 
-       dccp_hashinfo.bind_bucket_cachep = kmem_cache_create("dccp_bind_bucket",
-                                              sizeof(struct inet_bind_bucket),
-                                              0, SLAB_HWCACHE_ALIGN,
-                                              NULL, NULL);
+       dccp_hashinfo.bind_bucket_cachep =
+               kmem_cache_create("dccp_bind_bucket",
+                                 sizeof(struct inet_bind_bucket), 0,
+                                 SLAB_HWCACHE_ALIGN, NULL, NULL);
        if (!dccp_hashinfo.bind_bucket_cachep)
                goto out_proto_unregister;
 
@@ -708,14 +706,16 @@ static int __init dccp_init(void)
                goal = num_physpages >> (23 - PAGE_SHIFT);
 
        if (thash_entries)
-               goal = (thash_entries * sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
+               goal = (thash_entries *
+                       sizeof(struct inet_ehash_bucket)) >> PAGE_SHIFT;
        for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
                ;
        do {
                dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
                                        sizeof(struct inet_ehash_bucket);
                dccp_hashinfo.ehash_size >>= 1;
-               while (dccp_hashinfo.ehash_size & (dccp_hashinfo.ehash_size - 1))
+               while (dccp_hashinfo.ehash_size &
+                      (dccp_hashinfo.ehash_size - 1))
                        dccp_hashinfo.ehash_size--;
                dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
                        __get_free_pages(GFP_ATOMIC, ehash_order);
@@ -737,7 +737,8 @@ static int __init dccp_init(void)
        do {
                dccp_hashinfo.bhash_size = (1UL << bhash_order) * PAGE_SIZE /
                                        sizeof(struct inet_bind_hashbucket);
-               if ((dccp_hashinfo.bhash_size > (64 * 1024)) && bhash_order > 0)
+               if ((dccp_hashinfo.bhash_size > (64 * 1024)) &&
+                   bhash_order > 0)
                        continue;
                dccp_hashinfo.bhash = (struct inet_bind_hashbucket *)
                        __get_free_pages(GFP_ATOMIC, bhash_order);
@@ -793,26 +794,33 @@ static const char dccp_del_proto_err_msg[] __exitdata =
 
 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);
 module_exit(dccp_fini);
 
-/* __stringify doesn't likes enums, so use SOCK_DCCP (6) value directly  */
-MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-6");
+/*
+ * __stringify doesn't likes enums, so use SOCK_DCCP (6) and IPPROTO_DCCP (33)
+ * values directly, Also cover the case where the protocol is not specified,
+ * i.e. net-pf-PF_INET-proto-0-type-SOCK_DCCP
+ */
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-33-type-6");
+MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-0-type-6");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@conectiva.com.br>");
 MODULE_DESCRIPTION("DCCP - Datagram Congestion Controlled Protocol");