linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / dccp / ccids / ccid3.c
index 090bc39..35d1d34 100644 (file)
@@ -2,7 +2,7 @@
  *  net/dccp/ccids/ccid3.c
  *
  *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
- *  Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz>
+ *  Copyright (c) 2005-6 Ian McDonald <imcdnzl@gmail.com>
  *
  *  An implementation of the DCCP protocol
  *
@@ -34,6 +34,7 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <linux/config.h>
 #include "../ccid.h"
 #include "../dccp.h"
 #include "lib/packet_history.h"
@@ -45,7 +46,7 @@
  * Reason for maths here is to avoid 32 bit overflow when a is big.
  * With this we get close to the limit.
  */
-static u32 usecs_div(const u32 a, const u32 b)
+static inline u32 usecs_div(const u32 a, const u32 b)
 {
        const u32 div = a < (UINT_MAX / (USEC_PER_SEC /    10)) ?    10 :
                        a < (UINT_MAX / (USEC_PER_SEC /    50)) ?    50 :
@@ -75,6 +76,15 @@ static struct dccp_tx_hist *ccid3_tx_hist;
 static struct dccp_rx_hist *ccid3_rx_hist;
 static struct dccp_li_hist *ccid3_li_hist;
 
+static int ccid3_init(struct sock *sk)
+{
+       return 0;
+}
+
+static void ccid3_exit(struct sock *sk)
+{
+}
+
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
                TFRC_SSTATE_NO_SENT = 1,
@@ -97,8 +107,8 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
 }
 #endif
 
-static void ccid3_hc_tx_set_state(struct sock *sk,
-                                 enum ccid3_hc_tx_states state)
+static inline void ccid3_hc_tx_set_state(struct sock *sk,
+                                        enum ccid3_hc_tx_states state)
 {
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
@@ -306,6 +316,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
 
        switch (hctx->ccid3hctx_state) {
        case TFRC_SSTATE_NO_SENT:
+               hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
+               hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
                sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
                               jiffies + usecs_to_jiffies(TFRC_INITIAL_TIMEOUT));
                hctx->ccid3hctx_last_win_count   = 0;
@@ -342,8 +354,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
                new_packet->dccphtx_ccval =
                        DCCP_SKB_CB(skb)->dccpd_ccval =
                                hctx->ccid3hctx_last_win_count;
-               timeval_add_usecs(&hctx->ccid3hctx_t_nom,
-                                 hctx->ccid3hctx_t_ipi);
        }
 out:
        return rc;
@@ -415,8 +425,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
        case TFRC_SSTATE_NO_FBACK:
        case TFRC_SSTATE_FBACK:
                if (len > 0) {
-                       timeval_sub_usecs(&hctx->ccid3hctx_t_nom,
-                                 hctx->ccid3hctx_t_ipi);
+                       hctx->ccid3hctx_t_nom = now;
                        ccid3_calc_new_t_ipi(hctx);
                        ccid3_calc_new_delta(hctx);
                        timeval_add_usecs(&hctx->ccid3hctx_t_nom,
@@ -576,15 +585,16 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
        }
 }
 
-static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
+static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
        const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
        BUG_ON(hctx == NULL);
 
-       if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)
-               DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
-       return 0;
+       if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
+               return;
+
+        DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
 }
 
 static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
@@ -616,7 +626,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                                       __FUNCTION__, dccp_role(sk), sk);
                        rc = -EINVAL;
                } else {
-                       opt_recv->ccid3or_loss_event_rate = ntohl(*(__be32 *)value);
+                       opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value);
                        ccid3_pr_debug("%s, sk=%p, LOSS_EVENT_RATE=%u\n",
                                       dccp_role(sk), sk,
                                       opt_recv->ccid3or_loss_event_rate);
@@ -637,7 +647,7 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                                       __FUNCTION__, dccp_role(sk), sk);
                        rc = -EINVAL;
                } else {
-                       opt_recv->ccid3or_receive_rate = ntohl(*(__be32 *)value);
+                       opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value);
                        ccid3_pr_debug("%s, sk=%p, RECEIVE_RATE=%u\n",
                                       dccp_role(sk), sk,
                                       opt_recv->ccid3or_receive_rate);
@@ -648,10 +658,17 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
        return rc;
 }
 
-static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
+static int ccid3_hc_tx_init(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
+       struct ccid3_hc_tx_sock *hctx;
+
+       dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx), gfp_any());
+       if (dp->dccps_hc_tx_ccid_private == NULL)
+               return -ENOMEM;
+
+       hctx = ccid3_hc_tx_sk(sk);
+       memset(hctx, 0, sizeof(*hctx));
 
        if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
            dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
@@ -664,9 +681,6 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
        hctx->ccid3hctx_t_rto = USEC_PER_SEC;
        hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
        INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
-
-       hctx->ccid3hctx_no_feedback_timer.function = ccid3_hc_tx_no_feedback_timer;
-       hctx->ccid3hctx_no_feedback_timer.data     = (unsigned long)sk;
        init_timer(&hctx->ccid3hctx_no_feedback_timer);
 
        return 0;
@@ -674,6 +688,7 @@ static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
 
 static void ccid3_hc_tx_exit(struct sock *sk)
 {
+       struct dccp_sock *dp = dccp_sk(sk);
        struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
        BUG_ON(hctx == NULL);
@@ -683,6 +698,9 @@ static void ccid3_hc_tx_exit(struct sock *sk)
 
        /* Empty packet history */
        dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
+
+       kfree(dp->dccps_hc_tx_ccid_private);
+       dp->dccps_hc_tx_ccid_private = NULL;
 }
 
 /*
@@ -709,8 +727,8 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
 }
 #endif
 
-static void ccid3_hc_rx_set_state(struct sock *sk,
-                                 enum ccid3_hc_rx_states state)
+static inline void ccid3_hc_rx_set_state(struct sock *sk,
+                                        enum ccid3_hc_rx_states state)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
@@ -760,7 +778,8 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        }
 
        hcrx->ccid3hcrx_tstamp_last_feedback = now;
-       hcrx->ccid3hcrx_ccval_last_counter   = packet->dccphrx_ccval;
+       hcrx->ccid3hcrx_last_counter         = packet->dccphrx_ccval;
+       hcrx->ccid3hcrx_seqno_last_counter   = packet->dccphrx_seqno;
        hcrx->ccid3hcrx_bytes_recv           = 0;
 
        /* Convert to multiples of 10us */
@@ -774,35 +793,31 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        dccp_send_ack(sk);
 }
 
-static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
+static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
        const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
-       __be32 x_recv, pinv;
+       u32 x_recv, pinv;
 
        BUG_ON(hcrx == NULL);
 
        if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
-               return 0;
+               return;
 
-       DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_ccval_last_counter;
+       DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
 
        if (dccp_packet_without_ack(skb))
-               return 0;
-
+               return;
+               
+       if (hcrx->ccid3hcrx_elapsed_time != 0)
+               dccp_insert_option_elapsed_time(sk, skb,
+                                               hcrx->ccid3hcrx_elapsed_time);
+       dccp_insert_option_timestamp(sk, skb);
        x_recv = htonl(hcrx->ccid3hcrx_x_recv);
        pinv   = htonl(hcrx->ccid3hcrx_pinv);
-
-       if ((hcrx->ccid3hcrx_elapsed_time != 0 &&
-            dccp_insert_option_elapsed_time(sk, skb,
-                                            hcrx->ccid3hcrx_elapsed_time)) ||
-           dccp_insert_option_timestamp(sk, skb) ||
-           dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
-                              &pinv, sizeof(pinv)) ||
-           dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
-                              &x_recv, sizeof(x_recv)))
-               return -1;
-
-       return 0;
+       dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
+                          &pinv, sizeof(pinv));
+       dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
+                          &x_recv, sizeof(x_recv));
 }
 
 /* calculate first loss interval
@@ -856,11 +871,6 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
                interval = 1;
        }
 found:
-       if (!tail) {
-               LIMIT_NETDEBUG(KERN_WARNING "%s: tail is null\n",
-                  __FUNCTION__);
-               return ~0;
-       }
        rtt = timeval_delta(&tstamp, &tail->dccphrx_tstamp) * 4 / interval;
        ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
                       dccp_role(sk), sk, rtt);
@@ -871,20 +881,9 @@ found:
        delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback);
        x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta);
 
-       if (x_recv == 0)
-               x_recv = hcrx->ccid3hcrx_x_recv;
-
        tmp1 = (u64)x_recv * (u64)rtt;
        do_div(tmp1,10000000);
        tmp2 = (u32)tmp1;
-
-       if (!tmp2) {
-               LIMIT_NETDEBUG(KERN_WARNING "tmp2 = 0 "
-                  "%s: x_recv = %u, rtt =%u\n",
-                  __FUNCTION__, x_recv, rtt);
-               return ~0;
-       }
-
        fval = (hcrx->ccid3hcrx_s * 100000) / tmp2;
        /* do not alter order above or you will get overflow on 32 bit */
        p = tfrc_calc_x_reverse_lookup(fval);
@@ -900,101 +899,31 @@ found:
 static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
-       struct dccp_li_hist_entry *next, *head;
-       u64 seq_temp;
 
-       if (list_empty(&hcrx->ccid3hcrx_li_hist)) {
-               if (!dccp_li_hist_interval_new(ccid3_li_hist,
-                  &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss))
-                       return;
+       if (seq_loss != DCCP_MAX_SEQNO + 1 &&
+           list_empty(&hcrx->ccid3hcrx_li_hist)) {
+               struct dccp_li_hist_entry *li_tail;
 
-               next = (struct dccp_li_hist_entry *)
-                  hcrx->ccid3hcrx_li_hist.next;
-               next->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
-       } else {
-               struct dccp_li_hist_entry *entry;
-               struct list_head *tail;
-
-               head = (struct dccp_li_hist_entry *)
-                  hcrx->ccid3hcrx_li_hist.next;
-               /* FIXME win count check removed as was wrong */
-               /* should make this check with receive history */
-               /* and compare there as per section 10.2 of RFC4342 */
-
-               /* new loss event detected */
-               /* calculate last interval length */
-               seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss);
-               entry = dccp_li_hist_entry_new(ccid3_li_hist, SLAB_ATOMIC);
-
-               if (entry == NULL) {
-                       printk(KERN_CRIT "%s: out of memory\n",__FUNCTION__);
-                       dump_stack();
+               li_tail = dccp_li_hist_interval_new(ccid3_li_hist,
+                                                   &hcrx->ccid3hcrx_li_hist,
+                                                   seq_loss, win_loss);
+               if (li_tail == NULL)
                        return;
-               }
-
-               list_add(&entry->dccplih_node, &hcrx->ccid3hcrx_li_hist);
-
-               tail = hcrx->ccid3hcrx_li_hist.prev;
-               list_del(tail);
-               kmem_cache_free(ccid3_li_hist->dccplih_slab, tail);
-
-               /* Create the newest interval */
-               entry->dccplih_seqno = seq_loss;
-               entry->dccplih_interval = seq_temp;
-               entry->dccplih_win_count = win_loss;
-       }
+               li_tail->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
+       } else
+                   LIMIT_NETDEBUG(KERN_WARNING "%s: FIXME: find end of "
+                                  "interval\n", __FUNCTION__);
 }
 
-static int ccid3_hc_rx_detect_loss(struct sock *sk,
-                                    struct dccp_rx_hist_entry *packet)
+static void ccid3_hc_rx_detect_loss(struct sock *sk)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
-       struct dccp_rx_hist_entry *rx_hist = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
-       u64 seqno = packet->dccphrx_seqno;
-       u64 tmp_seqno;
-       int loss = 0;
-       u8 ccval;
-
-
-       tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
-
-       if (!rx_hist ||
-          follows48(packet->dccphrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) {
-               hcrx->ccid3hcrx_seqno_nonloss = seqno;
-               hcrx->ccid3hcrx_ccval_nonloss = packet->dccphrx_ccval;
-               goto detect_out;
-       }
-
+       u8 win_loss;
+       const u64 seq_loss = dccp_rx_hist_detect_loss(&hcrx->ccid3hcrx_hist,
+                                                     &hcrx->ccid3hcrx_li_hist,
+                                                     &win_loss);
 
-       while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno)
-          > TFRC_RECV_NUM_LATE_LOSS) {
-               loss = 1;
-               ccid3_hc_rx_update_li(sk, hcrx->ccid3hcrx_seqno_nonloss,
-                  hcrx->ccid3hcrx_ccval_nonloss);
-               tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
-               dccp_inc_seqno(&tmp_seqno);
-               hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
-               dccp_inc_seqno(&tmp_seqno);
-               while (dccp_rx_hist_find_entry(&hcrx->ccid3hcrx_hist,
-                  tmp_seqno, &ccval)) {
-                       hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
-                       hcrx->ccid3hcrx_ccval_nonloss = ccval;
-                       dccp_inc_seqno(&tmp_seqno);
-               }
-       }
-
-       /* FIXME - this code could be simplified with above while */
-       /* but works at moment */
-       if (follows48(packet->dccphrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) {
-               hcrx->ccid3hcrx_seqno_nonloss = seqno;
-               hcrx->ccid3hcrx_ccval_nonloss = packet->dccphrx_ccval;
-       }
-
-detect_out:
-       dccp_rx_hist_add_packet(ccid3_rx_hist, &hcrx->ccid3hcrx_hist,
-                  &hcrx->ccid3hcrx_li_hist, packet,
-                  hcrx->ccid3hcrx_seqno_nonloss);
-       return loss;
+       ccid3_hc_rx_update_li(sk, seq_loss, win_loss);
 }
 
 static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
@@ -1004,8 +933,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        struct dccp_rx_hist_entry *packet;
        struct timeval now;
        u8 win_count;
-       u32 p_prev, rtt_prev, r_sample, t_elapsed;
-       int loss;
+       u32 p_prev, r_sample, t_elapsed;
+       int ins;
 
        BUG_ON(hcrx == NULL ||
               !(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
@@ -1020,7 +949,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        case DCCP_PKT_DATAACK:
                if (opt_recv->dccpor_timestamp_echo == 0)
                        break;
-               rtt_prev = hcrx->ccid3hcrx_rtt;
+               p_prev = hcrx->ccid3hcrx_rtt;
                dccp_timestamp(sk, &now);
                timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10);
                r_sample = timeval_usecs(&now);
@@ -1039,8 +968,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                        hcrx->ccid3hcrx_rtt = (hcrx->ccid3hcrx_rtt * 9) / 10 +
                                              r_sample / 10;
 
-               if (rtt_prev != hcrx->ccid3hcrx_rtt)
-                       ccid3_pr_debug("%s, New RTT=%uus, elapsed time=%u\n",
+               if (p_prev != hcrx->ccid3hcrx_rtt)
+                       ccid3_pr_debug("%s, New RTT=%luus, elapsed time=%u\n",
                                       dccp_role(sk), hcrx->ccid3hcrx_rtt,
                                       opt_recv->dccpor_elapsed_time);
                break;
@@ -1061,7 +990,8 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
 
        win_count = packet->dccphrx_ccval;
 
-       loss = ccid3_hc_rx_detect_loss(sk, packet);
+       ins = dccp_rx_hist_add_packet(ccid3_rx_hist, &hcrx->ccid3hcrx_hist,
+                                     &hcrx->ccid3hcrx_li_hist, packet);
 
        if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK)
                return;
@@ -1078,7 +1008,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        case TFRC_RSTATE_DATA:
                hcrx->ccid3hcrx_bytes_recv += skb->len -
                                              dccp_hdr(skb)->dccph_doff * 4;
-               if (loss)
+               if (ins != 0)
                        break;
 
                dccp_timestamp(sk, &now);
@@ -1099,6 +1029,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        ccid3_pr_debug("%s, sk=%p(%s), data loss! Reacting...\n",
                       dccp_role(sk), sk, dccp_state_name(sk->sk_state));
 
+       ccid3_hc_rx_detect_loss(sk);
        p_prev = hcrx->ccid3hcrx_p;
        
        /* Calculate loss event rate */
@@ -1108,9 +1039,6 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                /* Scaling up by 1000000 as fixed decimal */
                if (i_mean != 0)
                        hcrx->ccid3hcrx_p = 1000000 / i_mean;
-       } else {
-               printk(KERN_CRIT "%s: empty loss hist\n",__FUNCTION__);
-               dump_stack();
        }
 
        if (hcrx->ccid3hcrx_p > p_prev) {
@@ -1119,13 +1047,20 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        }
 }
 
-static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
+static int ccid3_hc_rx_init(struct sock *sk)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
+       struct ccid3_hc_rx_sock *hcrx;
 
        ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
 
+       dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx), gfp_any());
+       if (dp->dccps_hc_rx_ccid_private == NULL)
+               return -ENOMEM;
+
+       hcrx = ccid3_hc_rx_sk(sk);
+       memset(hcrx, 0, sizeof(*hcrx));
+
        if (dp->dccps_packet_size >= TFRC_MIN_PACKET_SIZE &&
            dp->dccps_packet_size <= TFRC_MAX_PACKET_SIZE)
                hcrx->ccid3hcrx_s = dp->dccps_packet_size;
@@ -1144,6 +1079,7 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
 static void ccid3_hc_rx_exit(struct sock *sk)
 {
        struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+       struct dccp_sock *dp = dccp_sk(sk);
 
        BUG_ON(hcrx == NULL);
 
@@ -1154,6 +1090,9 @@ static void ccid3_hc_rx_exit(struct sock *sk)
 
        /* Empty loss interval history */
        dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist);
+
+       kfree(dp->dccps_hc_rx_ccid_private);
+       dp->dccps_hc_rx_ccid_private = NULL;
 }
 
 static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
@@ -1239,11 +1178,12 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
        return 0;
 }
 
-static struct ccid_operations ccid3 = {
+static struct ccid ccid3 = {
        .ccid_id                   = 3,
        .ccid_name                 = "ccid3",
        .ccid_owner                = THIS_MODULE,
-       .ccid_hc_tx_obj_size       = sizeof(struct ccid3_hc_tx_sock),
+       .ccid_init                 = ccid3_init,
+       .ccid_exit                 = ccid3_exit,
        .ccid_hc_tx_init           = ccid3_hc_tx_init,
        .ccid_hc_tx_exit           = ccid3_hc_tx_exit,
        .ccid_hc_tx_send_packet    = ccid3_hc_tx_send_packet,
@@ -1251,7 +1191,6 @@ static struct ccid_operations ccid3 = {
        .ccid_hc_tx_packet_recv    = ccid3_hc_tx_packet_recv,
        .ccid_hc_tx_insert_options = ccid3_hc_tx_insert_options,
        .ccid_hc_tx_parse_options  = ccid3_hc_tx_parse_options,
-       .ccid_hc_rx_obj_size       = sizeof(struct ccid3_hc_rx_sock),
        .ccid_hc_rx_init           = ccid3_hc_rx_init,
        .ccid_hc_rx_exit           = ccid3_hc_rx_exit,
        .ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options,
@@ -1302,6 +1241,15 @@ module_init(ccid3_module_init);
 
 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) {
@@ -1319,7 +1267,7 @@ static __exit void ccid3_module_exit(void)
 }
 module_exit(ccid3_module_exit);
 
-MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>, "
+MODULE_AUTHOR("Ian McDonald <iam4@cs.waikato.ac.nz>, "
              "Arnaldo Carvalho de Melo <acme@ghostprotocols.net>");
 MODULE_DESCRIPTION("DCCP TFRC CCID3 CCID");
 MODULE_LICENSE("GPL");