Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6
[powerpc.git] / net / dccp / ipv4.c
index 4fa56db..6298cf5 100644 (file)
 #include <net/tcp_states.h>
 #include <net/xfrm.h>
 
+#include "ackvec.h"
 #include "ccid.h"
 #include "dccp.h"
 
 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,26 +62,27 @@ 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);
-       struct inet_ehash_bucket *head = &dccp_hashinfo.ehash[hash];
+       unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
+       struct inet_ehash_bucket *head = inet_ehash_bucket(&dccp_hashinfo, hash);
        const struct sock *sk2;
        const struct hlist_node *node;
        struct inet_timewait_sock *tw;
 
+       prefetch(head->chain.first);
        write_lock(&head->lock);
 
        /* Check TIME-WAIT sockets first. */
        sk_for_each(sk2, node, &(head + dccp_hashinfo.ehash_size)->chain) {
                tw = inet_twsk(sk2);
 
-               if (INET_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif))
+               if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
                        goto not_unique;
        }
        tw = NULL;
 
        /* And established part... */
        sk_for_each(sk2, node, &head->chain) {
-               if (INET_MATCH(sk2, acookie, saddr, daddr, ports, dif))
+               if (INET_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif))
                        goto not_unique;
        }
 
@@ -86,7 +90,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
         * in hash table socket with a funny identity. */
        inet->num = lport;
        inet->sport = htons(lport);
-       sk->sk_hashent = hash;
+       sk->sk_hash = hash;
        BUG_TRAP(sk_unhashed(sk));
        __sk_add_node(sk, &head->chain);
        sock_prot_inc_use(sk->sk_prot);
@@ -97,7 +101,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 +135,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 +155,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 +176,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 +208,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 +216,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) {
@@ -239,6 +247,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
 
        dp->dccps_role = DCCP_ROLE_CLIENT;
 
+       if (dccp_service_not_initialized(sk))
+               return -EPROTO;
+
        if (addr_len < sizeof(struct sockaddr_in))
                return -EINVAL;
 
@@ -302,6 +313,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 +332,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 +386,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 +427,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 +442,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);
 }
@@ -436,6 +463,7 @@ static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
        if (skb != NULL) {
                const struct inet_request_sock *ireq = inet_rsk(req);
 
+               memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
                err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
                                            ireq->rmt_addr,
                                            ireq->opt);
@@ -463,7 +491,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 +632,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 +646,13 @@ 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);
 
+               memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
                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;
@@ -643,6 +667,16 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk,
                                           dccp_hdr(skb)->dccph_sport);
 }
 
+static inline int dccp_bad_service_code(const struct sock *sk,
+                                       const __u32 service)
+{
+       const struct dccp_sock *dp = dccp_sk(sk);
+
+       if (dp->dccps_service == service)
+               return 0;
+       return !dccp_list_has_service(dp->dccps_service_list, service);
+}
+
 int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 {
        struct inet_request_sock *ireq;
@@ -651,13 +685,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        struct dccp_request_sock *dreq;
        const __u32 saddr = skb->nh.iph->saddr;
        const __u32 daddr = skb->nh.iph->daddr;
+       const __u32 service = dccp_hdr_request(skb)->dccph_req_service;
+       struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+       __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY;
        struct dst_entry *dst = NULL;
 
        /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
        if (((struct rtable *)skb->dst)->rt_flags &
-           (RTCF_BROADCAST | RTCF_MULTICAST))
+           (RTCF_BROADCAST | RTCF_MULTICAST)) {
+               reset_code = DCCP_RESET_CODE_NO_CONNECTION;
                goto drop;
+       }
 
+       if (dccp_bad_service_code(sk, service)) {
+               reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE;
+               goto drop;
+       }
        /*
         * TW buckets are converted to open requests without
         * limitations, they conserve resources and peer is
@@ -687,7 +730,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;
 
        /* 
@@ -699,9 +743,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
         * dccp_create_openreq_child.
         */
        dreq = dccp_rsk(req);
-       dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq;
-       dreq->dreq_iss = dccp_v4_init_sequence(sk, skb);
-       dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service;
+       dreq->dreq_isr     = dcb->dccpd_seq;
+       dreq->dreq_iss     = dccp_v4_init_sequence(sk, skb);
+       dreq->dreq_service = service;
 
        if (dccp_v4_send_response(sk, req, dst))
                goto drop_and_free;
@@ -716,6 +760,7 @@ drop_and_free:
        __reqsk_free(req);
 drop:
        DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS);
+       dcb->dccpd_reset_code = reset_code;
        return -1;
 }
 
@@ -802,7 +847,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 +858,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 +878,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 +898,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 +910,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 +919,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 +950,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 +992,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 +1010,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);
@@ -968,7 +1031,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
        return 0;
 
 reset:
-       DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION;
        dccp_v4_ctl_send_reset(skb);
 discard:
        kfree_skb(skb);
@@ -983,7 +1045,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 +1053,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 +1062,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 +1085,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;
        }
 
@@ -1047,42 +1115,7 @@ int dccp_v4_rcv(struct sk_buff *skb)
                goto discard_it;
 
        dh = dccp_hdr(skb);
-#if 0
-       /*
-        * Use something like this to simulate some DATA/DATAACK loss to test
-        * 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|
-        *
-        * 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
-        * 3, 0 means: DCCP_ACKPKTS_STATE_NOT_RECEIVED, RLE == just this packet
-        *
-        * So...
-        *
-        * 281473596467422 was received
-        * 281473596467421 was not received
-        * 281473596467420 was received
-        * 281473596467419 was not received
-        * 281473596467418 was received
-        * 281473596467417 was not received
-        * 281473596467416 was received
-        * 281473596467415 was not received
-        * 281473596467414 was received
-        * 281473596467413 was received (this one was the 3way handshake RESPONSE)
-        *
-        */
-       if (dh->dccph_type == DCCP_PKT_DATA || dh->dccph_type == DCCP_PKT_DATAACK) {
-               static int discard = 0;
 
-               if (discard) {
-                       discard = 0;
-                       goto discard_it;
-               }
-               discard = 1;
-       }
-#endif
        DCCP_SKB_CB(skb)->dccpd_seq  = dccp_hdr_seq(skb);
        DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type;
 
@@ -1131,8 +1164,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 +1201,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 +1214,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,12 +1226,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);
-
-               if (dp->dccps_hc_rx_ackpkts == NULL)
+               dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN,
+                                                          GFP_KERNEL);
+               if (dp->dccps_hc_rx_ackvec == NULL)
                        return -ENOMEM;
        }
 
@@ -1204,14 +1243,18 @@ 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_rx_ccid,
+                                                sk);
+               dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid,
+                                                sk);
                if (dp->dccps_hc_rx_ccid == NULL ||
                    dp->dccps_hc_tx_ccid == NULL) {
                        ccid_exit(dp->dccps_hc_rx_ccid, sk);
                        ccid_exit(dp->dccps_hc_tx_ccid, sk);
-                       dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts);
-                       dp->dccps_hc_rx_ackpkts = NULL;
+                       if (dp->dccps_options.dccpo_send_ack_vector) {
+                               dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+                               dp->dccps_hc_rx_ackvec = NULL;
+                       }
                        dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
                        return -ENOMEM;
                }
@@ -1219,14 +1262,17 @@ static int dccp_v4_init_sock(struct sock *sk)
                dccp_ctl_socket_init = 0;
 
        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;
+       dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
 
        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);
 
@@ -1243,8 +1289,17 @@ int dccp_v4_destroy_sock(struct sock *sk)
        if (inet_csk(sk)->icsk_bind_hash != NULL)
                inet_put_port(&dccp_hashinfo, sk);
 
-       dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts);
-       dp->dccps_hc_rx_ackpkts = NULL;
+       if (dp->dccps_service_list != NULL) {
+               kfree(dp->dccps_service_list);
+               dp->dccps_service_list = NULL;
+       }
+
+       ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk);
+       ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk);
+       if (dp->dccps_options.dccpo_send_ack_vector) {
+               dccp_ackvec_free(dp->dccps_hc_rx_ackvec);
+               dp->dccps_hc_rx_ackvec = NULL;
+       }
        ccid_exit(dp->dccps_hc_rx_ccid, sk);
        ccid_exit(dp->dccps_hc_tx_ccid, sk);
        dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL;
@@ -1289,5 +1344,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),
 };