Merge davem@outer-richmond.davemloft.net:src/GIT/net-2.6/
[pandora-kernel.git] / net / dccp / ipv4.c
index 6bccf4d..2afaa46 100644 (file)
 struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
        .lhash_lock     = RW_LOCK_UNLOCKED,
        .lhash_users    = ATOMIC_INIT(0),
-       .lhash_wait     = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
+       .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait),
        .portalloc_lock = SPIN_LOCK_UNLOCKED,
        .port_rover     = 1024 - 1,
 };
 
+EXPORT_SYMBOL_GPL(dccp_hashinfo);
+
 static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
 {
        return inet_csk_get_port(&dccp_hashinfo, sk, snum);
@@ -59,7 +61,8 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
        const int dif = sk->sk_bound_dev_if;
        INET_ADDR_COOKIE(acookie, saddr, daddr)
        const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
-       const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport, dccp_hashinfo.ehash_size);
+       const int hash = inet_ehashfn(daddr, lport, saddr, inet->dport,
+                                     dccp_hashinfo.ehash_size);
        struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash];
        const struct sock *sk2;
        const struct hlist_node *node;
@@ -97,7 +100,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
                NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
        } else if (tw != NULL) {
                /* Silly. Should hash-dance instead... */
-               dccp_tw_deschedule(tw);
+               inet_twsk_deschedule(tw, &dccp_death_row);
                NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
 
                inet_twsk_put(tw);
@@ -131,11 +134,12 @@ static int dccp_v4_hash_connect(struct sock *sk)
                local_bh_disable();
 
                /* TODO. Actually it is not so bad idea to remove
-                * dccp_hashinfo.portalloc_lock before next submission to Linus.
+                * dccp_hashinfo.portalloc_lock before next submission to
+                * Linus.
                 * As soon as we touch this place at all it is time to think.
                 *
-                * Now it protects single _advisory_ variable dccp_hashinfo.port_rover,
-                * hence it is mostly useless.
+                * Now it protects single _advisory_ variable
+                * dccp_hashinfo.port_rover, hence it is mostly useless.
                 * Code will work nicely if we just delete it, but
                 * I am afraid in contented case it will work not better or
                 * even worse: another cpu just will hit the same bucket
@@ -150,7 +154,8 @@ static int dccp_v4_hash_connect(struct sock *sk)
                        rover++;
                        if ((rover < low) || (rover > high))
                                rover = low;
-                       head = &dccp_hashinfo.bhash[inet_bhashfn(rover, dccp_hashinfo.bhash_size)];
+                       head = &dccp_hashinfo.bhash[inet_bhashfn(rover,
+                                                   dccp_hashinfo.bhash_size)];
                        spin_lock(&head->lock);
 
                        /* Does not bother with rcv_saddr checks,
@@ -170,7 +175,8 @@ static int dccp_v4_hash_connect(struct sock *sk)
                                }
                        }
 
-                       tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep, head, rover);
+                       tb = inet_bind_bucket_create(dccp_hashinfo.bind_bucket_cachep,
+                                                    head, rover);
                        if (tb == NULL) {
                                spin_unlock(&head->lock);
                                break;
@@ -201,7 +207,7 @@ ok:
                spin_unlock(&head->lock);
 
                if (tw != NULL) {
-                       dccp_tw_deschedule(tw);
+                       inet_twsk_deschedule(tw, &dccp_death_row);
                        inet_twsk_put(tw);
                }
 
@@ -209,7 +215,8 @@ ok:
                goto out;
        }
 
-       head = &dccp_hashinfo.bhash[inet_bhashfn(snum, dccp_hashinfo.bhash_size)];
+       head = &dccp_hashinfo.bhash[inet_bhashfn(snum,
+                                                dccp_hashinfo.bhash_size)];
        tb   = inet_csk(sk)->icsk_bind_hash;
        spin_lock_bh(&head->lock);
        if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
@@ -302,6 +309,16 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
                                                            usin->sin_port);
        dccp_update_gss(sk, dp->dccps_iss);
 
+       /*
+        * SWL and AWL are initially adjusted so that they are not less than
+        * the initial Sequence Numbers received and sent, respectively:
+        *      SWL := max(GSR + 1 - floor(W/4), ISR),
+        *      AWL := max(GSS - W' + 1, ISS).
+        * These adjustments MUST be applied only at the beginning of the
+        * connection.
+        */
+       dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
+
        inet->id = dp->dccps_iss ^ jiffies;
 
        err = dccp_connect(sk);
@@ -311,7 +328,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
 out:
        return err;
 failure:
-       /* This unhashes the socket and releases the local port, if necessary. */
+       /*
+        * This unhashes the socket and releases the local port, if necessary.
+        */
        dccp_set_state(sk, DCCP_CLOSED);
        ip_rt_put(rt);
        sk->sk_route_caps = 0;
@@ -363,10 +382,11 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
                /*
                 * From: draft-ietf-dccp-spec-11.txt
                 *
-                *      DCCP-Sync packets are the best choice for upward probing,
-                *      since DCCP-Sync probes do not risk application data loss.
+                *      DCCP-Sync packets are the best choice for upward
+                *      probing, since DCCP-Sync probes do not risk application
+                *      data loss.
                 */
-               dccp_send_sync(sk, dp->dccps_gsr);
+               dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC);
        } /* else let the usual retransmit timer handle it */
 }
 
@@ -403,11 +423,13 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
        dh->dccph_x        = 1;
 
        dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
-       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
+       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
+                        DCCP_SKB_CB(rxskb)->dccpd_seq);
 
        bh_lock_sock(dccp_ctl_socket->sk);
        err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
-                                   rxskb->nh.iph->daddr, rxskb->nh.iph->saddr, NULL);
+                                   rxskb->nh.iph->daddr,
+                                   rxskb->nh.iph->saddr, NULL);
        bh_unlock_sock(dccp_ctl_socket->sk);
 
        if (err == NET_XMIT_CN || err == 0) {
@@ -416,7 +438,8 @@ static void dccp_v4_ctl_send_ack(struct sk_buff *rxskb)
        }
 }
 
-static void dccp_v4_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
+static void dccp_v4_reqsk_send_ack(struct sk_buff *skb,
+                                  struct request_sock *req)
 {
        dccp_v4_ctl_send_ack(skb);
 }
@@ -463,7 +486,8 @@ out:
 void dccp_v4_err(struct sk_buff *skb, u32 info)
 {
        const struct iphdr *iph = (struct iphdr *)skb->data;
-       const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data + (iph->ihl << 2));
+       const struct dccp_hdr *dh = (struct dccp_hdr *)(skb->data +
+                                                       (iph->ihl << 2));
        struct dccp_sock *dp;
        struct inet_sock *inet;
        const int type = skb->h.icmph->type;
@@ -603,8 +627,6 @@ out:
        sock_put(sk);
 }
 
-extern struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst, enum dccp_reset_codes code);
-
 int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code)
 {
        struct sk_buff *skb;
@@ -619,16 +641,12 @@ int dccp_v4_send_reset(struct sock *sk, enum dccp_reset_codes code)
 
        skb = dccp_make_reset(sk, sk->sk_dst_cache, code);
        if (skb != NULL) {
-               const struct dccp_sock *dp = dccp_sk(sk);
                const struct inet_sock *inet = inet_sk(sk);
 
                err = ip_build_and_send_pkt(skb, sk,
                                            inet->saddr, inet->daddr, NULL);
                if (err == NET_XMIT_CN)
                        err = 0;
-
-               ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
-               ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
        }
 
        return err;
@@ -687,7 +705,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        ireq->loc_addr = daddr;
        ireq->rmt_addr = saddr;
        /* FIXME: Merge Aristeu's option parsing code when ready */
-       req->rcv_wnd    = 100; /* Fake, option parsing will get the right value */
+       req->rcv_wnd    = 100; /* Fake, option parsing will get the
+                                 right value */
        ireq->opt       = NULL;
 
        /* 
@@ -802,7 +821,8 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
        return sk;
 }
 
-int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, const u32 daddr)
+int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr,
+                    const u32 daddr)
 {
        const struct dccp_hdr* dh = dccp_hdr(skb);
        int checksum_len;
@@ -812,11 +832,13 @@ int dccp_v4_checksum(const struct sk_buff *skb, const u32 saddr, const u32 daddr
                checksum_len = skb->len;
        else {
                checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
-               checksum_len = checksum_len < skb->len ? checksum_len : skb->len;
+               checksum_len = checksum_len < skb->len ? checksum_len :
+                                                        skb->len;
        }
 
        tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
-       return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp);
+       return csum_tcpudp_magic(saddr, daddr, checksum_len,
+                                IPPROTO_DCCP, tmp);
 }
 
 static int dccp_v4_verify_checksum(struct sk_buff *skb,
@@ -830,10 +852,12 @@ static int dccp_v4_verify_checksum(struct sk_buff *skb,
                checksum_len = skb->len;
        else {
                checksum_len = (dh->dccph_cscov + dh->dccph_x) * sizeof(u32);
-               checksum_len = checksum_len < skb->len ? checksum_len : skb->len;
+               checksum_len = checksum_len < skb->len ? checksum_len :
+                                                        skb->len;
        }
        tmp = csum_partial((unsigned char *)dh, checksum_len, 0);
-       return csum_tcpudp_magic(saddr, daddr, checksum_len, IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
+       return csum_tcpudp_magic(saddr, daddr, checksum_len,
+                                IPPROTO_DCCP, tmp) == 0 ? 0 : -1;
 }
 
 static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
@@ -848,7 +872,9 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
                            .proto = sk->sk_protocol,
                            .uli_u = { .ports =
                                       { .sport = dccp_hdr(skb)->dccph_dport,
-                                        .dport = dccp_hdr(skb)->dccph_sport } } };
+                                        .dport = dccp_hdr(skb)->dccph_sport }
+                                    }
+                         };
 
        if (ip_route_output_flow(&rt, &fl, sk, 0)) {
                IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
@@ -858,7 +884,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
        return &rt->u.dst;
 }
 
-void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
+static void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
 {
        int err;
        struct dccp_hdr *rxdh = dccp_hdr(rxskb), *dh;
@@ -867,6 +893,7 @@ void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
                                       sizeof(struct dccp_hdr_reset);
        struct sk_buff *skb;
        struct dst_entry *dst;
+       u64 seqno;
 
        /* Never send a reset in response to a reset. */
        if (rxdh->dccph_type == DCCP_PKT_RESET)
@@ -897,17 +924,25 @@ void dccp_v4_ctl_send_reset(struct sk_buff *rxskb)
        dh->dccph_dport    = rxdh->dccph_sport;
        dh->dccph_doff     = dccp_hdr_reset_len / 4;
        dh->dccph_x        = 1;
-       dccp_hdr_reset(skb)->dccph_reset_code = DCCP_SKB_CB(rxskb)->dccpd_reset_code;
+       dccp_hdr_reset(skb)->dccph_reset_code =
+                               DCCP_SKB_CB(rxskb)->dccpd_reset_code;
 
-       dccp_hdr_set_seq(dh, DCCP_SKB_CB(rxskb)->dccpd_ack_seq);
-       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), DCCP_SKB_CB(rxskb)->dccpd_seq);
+       /* See "8.3.1. Abnormal Termination" in draft-ietf-dccp-spec-11 */
+       seqno = 0;
+       if (DCCP_SKB_CB(rxskb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+               dccp_set_seqno(&seqno, DCCP_SKB_CB(rxskb)->dccpd_ack_seq + 1);
+
+       dccp_hdr_set_seq(dh, seqno);
+       dccp_hdr_set_ack(dccp_hdr_ack_bits(skb),
+                        DCCP_SKB_CB(rxskb)->dccpd_seq);
 
        dh->dccph_checksum = dccp_v4_checksum(skb, rxskb->nh.iph->saddr,
                                              rxskb->nh.iph->daddr);
 
        bh_lock_sock(dccp_ctl_socket->sk);
        err = ip_build_and_send_pkt(skb, dccp_ctl_socket->sk,
-                                   rxskb->nh.iph->daddr, rxskb->nh.iph->saddr, NULL);
+                                   rxskb->nh.iph->daddr,
+                                   rxskb->nh.iph->saddr, NULL);
        bh_unlock_sock(dccp_ctl_socket->sk);
 
        if (err == NET_XMIT_CN || err == 0) {
@@ -931,7 +966,8 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
        /*
         *  Step 3: Process LISTEN state
         *     If S.state == LISTEN,
-        *        If P.type == Request or P contains a valid Init Cookie option,
+        *        If P.type == Request or P contains a valid Init Cookie
+        *              option,
         *           * Must scan the packet's options to check for an Init
         *              Cookie.  Only the Init Cookie is processed here,
         *              however; other options are processed in Step 8.  This
@@ -948,7 +984,8 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
         *           Generate Reset(No Connection) unless P.type == Reset
         *           Drop packet and return
         *
-        * NOTE: the check for the packet types is done in dccp_rcv_state_process
+        * NOTE: the check for the packet types is done in
+        *       dccp_rcv_state_process
         */
        if (sk->sk_state == DCCP_LISTEN) {
                struct sock *nsk = dccp_v4_hnd_req(sk, skb);
@@ -983,7 +1020,7 @@ static inline int dccp_invalid_packet(struct sk_buff *skb)
                return 1;
 
        if (!pskb_may_pull(skb, sizeof(struct dccp_hdr))) {
-               dccp_pr_debug("pskb_may_pull failed\n");
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: pskb_may_pull failed\n");
                return 1;
        }
 
@@ -991,7 +1028,7 @@ static inline int dccp_invalid_packet(struct sk_buff *skb)
 
        /* If the packet type is not understood, drop packet and return */
        if (dh->dccph_type >= DCCP_PKT_INVALID) {
-               dccp_pr_debug("invalid packet type\n");
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: invalid packet type\n");
                return 1;
        }
 
@@ -1000,12 +1037,16 @@ static inline int dccp_invalid_packet(struct sk_buff *skb)
         * packet, drop packet and return
         */
        if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) {
-               dccp_pr_debug("Offset(%u) too small 1\n", dh->dccph_doff);
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
+                                           "too small 1\n",
+                              dh->dccph_doff);
                return 1;
        }
 
        if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) {
-               dccp_pr_debug("P.Data Offset(%u) too small 2\n", dh->dccph_doff);
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.Data Offset(%u) "
+                                           "too small 2\n",
+                              dh->dccph_doff);
                return 1;
        }
 
@@ -1019,15 +1060,17 @@ static inline int dccp_invalid_packet(struct sk_buff *skb)
            dh->dccph_type != DCCP_PKT_DATA &&
            dh->dccph_type != DCCP_PKT_ACK &&
            dh->dccph_type != DCCP_PKT_DATAACK) {
-               dccp_pr_debug("P.type (%s) not Data, Ack nor DataAck and P.X == 0\n",
-                             dccp_packet_name(dh->dccph_type));
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: P.type (%s) not Data, Ack "
+                                           "nor DataAck and P.X == 0\n",
+                              dccp_packet_name(dh->dccph_type));
                return 1;
        }
 
        /* If the header checksum is incorrect, drop packet and return */
        if (dccp_v4_verify_checksum(skb, skb->nh.iph->saddr,
                                    skb->nh.iph->daddr) < 0) {
-               dccp_pr_debug("header checksum is incorrect\n");
+               LIMIT_NETDEBUG(KERN_WARNING "DCCP: header checksum is "
+                                           "incorrect\n");
                return 1;
        }
 
@@ -1053,10 +1096,11 @@ int dccp_v4_rcv(struct sk_buff *skb)
         * dccp_ackpkts_add, you'll get something like this on a session that
         * sends 10 DATA/DATAACK packets:
         *
-        * dccp_ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1|
+        * ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1|
         *
         * 0, 0 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == just this packet
-        * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets with the same state
+        * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets
+        *                                                 with the same state
         * 3, 0 means: DCCP_ACKPKTS_STATE_NOT_RECEIVED, RLE == just this packet
         *
         * So...
@@ -1070,10 +1114,12 @@ int dccp_v4_rcv(struct sk_buff *skb)
         * 281473596467416 was received
         * 281473596467415 was not received
         * 281473596467414 was received
-        * 281473596467413 was received (this one was the 3way handshake RESPONSE)
+        * 281473596467413 was received (this one was the 3way handshake
+        *                               RESPONSE)
         *
         */
-       if (dh->dccph_type == DCCP_PKT_DATA || dh->dccph_type == DCCP_PKT_DATAACK) {
+       if (dh->dccph_type == DCCP_PKT_DATA ||
+           dh->dccph_type == DCCP_PKT_DATAACK) {
                static int discard = 0;
 
                if (discard) {
@@ -1131,8 +1177,9 @@ int dccp_v4_rcv(struct sk_buff *skb)
         */
               
        if (sk->sk_state == DCCP_TIME_WAIT) {
-               dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: discard_and_relse\n");
-                goto discard_and_relse;
+               dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: "
+                             "do_time_wait\n");
+                goto do_time_wait;
        }
 
        if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
@@ -1167,7 +1214,8 @@ no_dccp_socket:
         *              Drop packet and return
         */
        if (dh->dccph_type != DCCP_PKT_RESET) {
-               DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
+               DCCP_SKB_CB(skb)->dccpd_reset_code =
+                                       DCCP_RESET_CODE_NO_CONNECTION;
                dccp_v4_ctl_send_reset(skb);
        }
 
@@ -1179,6 +1227,10 @@ discard_it:
 discard_and_relse:
        sock_put(sk);
        goto discard_it;
+
+do_time_wait:
+       inet_twsk_put((struct inet_timewait_sock *)sk);
+       goto no_dccp_socket;
 }
 
 static int dccp_v4_init_sock(struct sock *sk)
@@ -1187,10 +1239,12 @@ static int dccp_v4_init_sock(struct sock *sk)
        static int dccp_ctl_socket_init = 1;
 
        dccp_options_init(&dp->dccps_options);
+       do_gettimeofday(&dp->dccps_epoch);
 
        if (dp->dccps_options.dccpo_send_ack_vector) {
-               dp->dccps_hc_rx_ackpkts = dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN,
-                                                            GFP_KERNEL);
+               dp->dccps_hc_rx_ackpkts =
+                       dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN,
+                                          GFP_KERNEL);
 
                if (dp->dccps_hc_rx_ackpkts == NULL)
                        return -ENOMEM;
@@ -1204,8 +1258,10 @@ static int dccp_v4_init_sock(struct sock *sk)
         * setsockopt(CCIDs-I-want/accept). -acme
         */
        if (likely(!dccp_ctl_socket_init)) {
-               dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, sk);
-               dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, sk);
+               dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid,
+                                                sk);
+               dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid,
+                                                sk);
                if (dp->dccps_hc_rx_ccid == NULL ||
                    dp->dccps_hc_tx_ccid == NULL) {
                        ccid_exit(dp->dccps_hc_rx_ccid, sk);
@@ -1221,13 +1277,14 @@ static int dccp_v4_init_sock(struct sock *sk)
        dccp_init_xmit_timers(sk);
        inet_csk(sk)->icsk_rto = DCCP_TIMEOUT_INIT;
        sk->sk_state = DCCP_CLOSED;
+       sk->sk_write_space = dccp_write_space;
        dp->dccps_mss_cache = 536;
        dp->dccps_role = DCCP_ROLE_UNDEFINED;
 
        return 0;
 }
 
-int dccp_v4_destroy_sock(struct sock *sk)
+static int dccp_v4_destroy_sock(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
 
@@ -1244,6 +1301,8 @@ int dccp_v4_destroy_sock(struct sock *sk)
        if (inet_csk(sk)->icsk_bind_hash != NULL)
                inet_put_port(&dccp_hashinfo, sk);
 
+       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
        dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts);
        dp->dccps_hc_rx_ackpkts = NULL;
        ccid_exit(dp->dccps_hc_rx_ccid, sk);
@@ -1290,5 +1349,5 @@ struct proto dccp_v4_prot = {
        .max_header             = MAX_DCCP_HEADER,
        .obj_size               = sizeof(struct dccp_sock),
        .rsk_prot               = &dccp_request_sock_ops,
-       .twsk_obj_size          = sizeof(struct inet_timewait_sock), /* FIXME! create dccp_timewait_sock */
+       .twsk_obj_size          = sizeof(struct inet_timewait_sock),
 };