]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/dccp/ccids/ccid3.c
[DCCP] CCID2: Drop sock reference count on timer expiration and reset.
[linux-2.6-omap-h63xx.git] / net / dccp / ccids / ccid3.c
index 145aafafe4e271a29ece1ace85d71451c82be056..f9e16db09bef353435d700824539a829781ee777 100644 (file)
@@ -2,7 +2,7 @@
  *  net/dccp/ccids/ccid3.c
  *
  *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
- *  Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz>
+ *  Copyright (c) 2005-6 Ian McDonald <imcdnzl@gmail.com>
  *
  *  An implementation of the DCCP protocol
  *
@@ -76,17 +76,6 @@ 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)
-{
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
-       return 0;
-}
-
-static void ccid3_exit(struct sock *sk)
-{
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
-}
-
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
                TFRC_SSTATE_NO_SENT = 1,
@@ -112,8 +101,7 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
 static inline void ccid3_hc_tx_set_state(struct sock *sk,
                                         enum ccid3_hc_tx_states state)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
 
        ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
@@ -154,8 +142,7 @@ static inline void ccid3_calc_new_delta(struct ccid3_hc_tx_sock *hctx)
  */ 
 static void ccid3_hc_tx_update_x(struct sock *sk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
        /* To avoid large error in calcX */
        if (hctx->ccid3hctx_p >= TFRC_SMALLEST_P) {
@@ -169,7 +156,7 @@ static void ccid3_hc_tx_update_x(struct sock *sk)
        } else {
                struct timeval now;
 
-               do_gettimeofday(&now);
+               dccp_timestamp(sk, &now);
                if (timeval_delta(&now, &hctx->ccid3hctx_t_ld) >=
                    hctx->ccid3hctx_rtt) {
                        hctx->ccid3hctx_x = max_t(u32, min_t(u32, hctx->ccid3hctx_x_recv,
@@ -184,9 +171,8 @@ static void ccid3_hc_tx_update_x(struct sock *sk)
 static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
 {
        struct sock *sk = (struct sock *)data;
-       struct dccp_sock *dp = dccp_sk(sk);
        unsigned long next_tmout = 0;
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
        bh_lock_sock(sk);
        if (sock_owned_by_user(sk)) {
@@ -284,20 +270,20 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
                                   struct sk_buff *skb, int len)
 {
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        struct dccp_tx_hist_entry *new_packet;
        struct timeval now;
        long delay;
        int rc = -ENOTCONN;
 
-       /* Check if pure ACK or Terminating*/
+       BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);
 
+       /* Check if pure ACK or Terminating*/
        /*
         * XXX: We only call this function for DATA and DATAACK, on, these
         * packets can have zero length, but why the comment about "pure ACK"?
         */
-       if (hctx == NULL || len == 0 ||
-           hctx->ccid3hctx_state == TFRC_SSTATE_TERM)
+       if (unlikely(len == 0))
                goto out;
 
        /* See if last packet allocated was not sent */
@@ -307,31 +293,26 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
                                                    SLAB_ATOMIC);
 
                rc = -ENOBUFS;
-               if (new_packet == NULL) {
-                       ccid3_pr_debug("%s, sk=%p, not enough mem to add "
-                                      "to history, send refused\n",
-                                      dccp_role(sk), sk);
+               if (unlikely(new_packet == NULL)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, not enough "
+                                      "mem to add to history, send refused\n",
+                                      __FUNCTION__, dccp_role(sk), sk);
                        goto out;
                }
 
                dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
        }
 
-       do_gettimeofday(&now);
+       dccp_timestamp(sk, &now);
 
        switch (hctx->ccid3hctx_state) {
        case TFRC_SSTATE_NO_SENT:
-               ccid3_pr_debug("%s, sk=%p, first packet(%llu)\n",
-                              dccp_role(sk), sk, dp->dccps_gss);
-
-               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;
                hctx->ccid3hctx_t_last_win_count = now;
                ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
-               hctx->ccid3hctx_t_ipi = TFRC_INITIAL_TIMEOUT;
+               hctx->ccid3hctx_t_ipi = TFRC_INITIAL_IPI;
 
                /* Set nominal send time for initial packet */
                hctx->ccid3hctx_t_nom = now;
@@ -344,7 +325,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk,
        case TFRC_SSTATE_FBACK:
                delay = (timeval_delta(&now, &hctx->ccid3hctx_t_nom) -
                         hctx->ccid3hctx_delta);
-               ccid3_pr_debug("send_packet delay=%ld\n", delay);
                delay /= -1000;
                /* divide by -1000 is to convert to ms and get sign right */
                rc = delay > 0 ? delay : 0;
@@ -370,19 +350,13 @@ out:
 
 static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       const struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        struct timeval now;
 
-       BUG_ON(hctx == NULL);
-
-       if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
-               ccid3_pr_debug("%s, sk=%p, while state is TFRC_SSTATE_TERM!\n",
-                              dccp_role(sk), sk);
-               return;
-       }
+       BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);
 
-       do_gettimeofday(&now);
+       dccp_timestamp(sk, &now);
 
        /* check if we have sent a data packet */
        if (len > 0) {
@@ -390,14 +364,14 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
                struct dccp_tx_hist_entry *packet;
 
                packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
-               if (packet == NULL) {
-                       printk(KERN_CRIT "%s: packet doesn't exists in "
-                                        "history!\n", __FUNCTION__);
+               if (unlikely(packet == NULL)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: packet doesn't "
+                                      "exists in history!\n", __FUNCTION__);
                        return;
                }
-               if (packet->dccphtx_sent) {
-                       printk(KERN_CRIT "%s: no unsent packet in history!\n",
-                              __FUNCTION__);
+               if (unlikely(packet->dccphtx_sent)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: no unsent packet in "
+                                      "history!\n", __FUNCTION__);
                        return;
                }
                packet->dccphtx_tstamp = now;
@@ -457,24 +431,18 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more, int len)
 
 static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       const struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        struct ccid3_options_received *opt_recv;
        struct dccp_tx_hist_entry *packet;
+       struct timeval now;
        unsigned long next_tmout; 
        u32 t_elapsed;
        u32 pinv;
        u32 x_recv;
        u32 r_sample;
 
-       if (hctx == NULL)
-               return;
-
-       if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
-               ccid3_pr_debug("%s, sk=%p, received a packet when "
-                              "terminating!\n", dccp_role(sk), sk);
-               return;
-       }
+       BUG_ON(hctx == NULL || hctx->ccid3hctx_state == TFRC_SSTATE_TERM);
 
        /* we are only interested in ACKs */
        if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK ||
@@ -498,20 +466,21 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
                /* get t_recvdata from history */
                packet = dccp_tx_hist_find_entry(&hctx->ccid3hctx_hist,
                                                 DCCP_SKB_CB(skb)->dccpd_ack_seq);
-               if (packet == NULL) {
-                       ccid3_pr_debug("%s, sk=%p, seqno %llu(%s) does't "
-                                      "exist in history!\n",
-                                      dccp_role(sk), sk,
-                                      DCCP_SKB_CB(skb)->dccpd_ack_seq,
-                                      dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+               if (unlikely(packet == NULL)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, seqno "
+                                      "%llu(%s) does't exist in history!\n",
+                                      __FUNCTION__, dccp_role(sk), sk,
+                           (unsigned long long)DCCP_SKB_CB(skb)->dccpd_ack_seq,
+                               dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
                        return;
                }
 
                /* Update RTT */
-               r_sample = timeval_now_delta(&packet->dccphtx_tstamp);
+               dccp_timestamp(sk, &now);
+               r_sample = timeval_delta(&now, &packet->dccphtx_tstamp);
                if (unlikely(r_sample <= t_elapsed))
-                       LIMIT_NETDEBUG(KERN_WARNING
-                                      "%s: r_sample=%uus, t_elapsed=%uus\n",
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, "
+                                      "t_elapsed=%uus\n",
                                       __FUNCTION__, r_sample, t_elapsed);
                else
                        r_sample -= t_elapsed;
@@ -607,11 +576,11 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
 
 static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
-       if (hctx == NULL || !(sk->sk_state == DCCP_OPEN ||
-                             sk->sk_state == DCCP_PARTOPEN))
+       BUG_ON(hctx == NULL);
+
+       if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
                return;
 
         DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
@@ -622,12 +591,11 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                                     unsigned char *value)
 {
        int rc = 0;
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       const struct dccp_sock *dp = dccp_sk(sk);
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
        struct ccid3_options_received *opt_recv;
 
-       if (hctx == NULL)
-               return 0;
+       BUG_ON(hctx == NULL);
 
        opt_recv = &hctx->ccid3hctx_options_received;
 
@@ -641,10 +609,10 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
 
        switch (option) {
        case TFRC_OPT_LOSS_EVENT_RATE:
-               if (len != 4) {
-                       ccid3_pr_debug("%s, sk=%p, invalid len for "
-                                      "TFRC_OPT_LOSS_EVENT_RATE\n",
-                                      dccp_role(sk), sk);
+               if (unlikely(len != 4)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, invalid "
+                                      "len for TFRC_OPT_LOSS_EVENT_RATE\n",
+                                      __FUNCTION__, dccp_role(sk), sk);
                        rc = -EINVAL;
                } else {
                        opt_recv->ccid3or_loss_event_rate = ntohl(*(u32 *)value);
@@ -662,10 +630,10 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
                               opt_recv->ccid3or_loss_intervals_len);
                break;
        case TFRC_OPT_RECEIVE_RATE:
-               if (len != 4) {
-                       ccid3_pr_debug("%s, sk=%p, invalid len for "
-                                      "TFRC_OPT_RECEIVE_RATE\n",
-                                      dccp_role(sk), sk);
+               if (unlikely(len != 4)) {
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, invalid "
+                                      "len for TFRC_OPT_RECEIVE_RATE\n",
+                                      __FUNCTION__, dccp_role(sk), sk);
                        rc = -EINVAL;
                } else {
                        opt_recv->ccid3or_receive_rate = ntohl(*(u32 *)value);
@@ -684,13 +652,11 @@ static int ccid3_hc_tx_init(struct sock *sk)
        struct dccp_sock *dp = dccp_sk(sk);
        struct ccid3_hc_tx_sock *hctx;
 
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
-
-       hctx = dp->dccps_hc_tx_ccid_private = kmalloc(sizeof(*hctx),
-                                                     gfp_any());
-       if (hctx == NULL)
+       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 &&
@@ -704,6 +670,9 @@ static int ccid3_hc_tx_init(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;
@@ -712,9 +681,8 @@ static int ccid3_hc_tx_init(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 = dp->dccps_hc_tx_ccid_private;
+       struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
        BUG_ON(hctx == NULL);
 
        ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
@@ -754,8 +722,7 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
 static inline void ccid3_hc_rx_set_state(struct sock *sk,
                                         enum ccid3_hc_rx_states state)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
 
        ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
@@ -767,14 +734,14 @@ static inline void ccid3_hc_rx_set_state(struct sock *sk,
 
 static void ccid3_hc_rx_send_feedback(struct sock *sk)
 {
+       struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
        struct dccp_rx_hist_entry *packet;
        struct timeval now;
 
        ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
 
-       do_gettimeofday(&now);
+       dccp_timestamp(sk, &now);
 
        switch (hcrx->ccid3hcrx_state) {
        case TFRC_RSTATE_NO_DATA:
@@ -795,10 +762,10 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
        }
 
        packet = dccp_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
-       if (packet == NULL) {
-               printk(KERN_CRIT "%s: %s, sk=%p, no data packet in history!\n",
-                      __FUNCTION__, dccp_role(sk), sk);
-               dump_stack();
+       if (unlikely(packet == NULL)) {
+               LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, no data packet "
+                              "in history!\n",
+                              __FUNCTION__, dccp_role(sk), sk);
                return;
        }
 
@@ -820,12 +787,12 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
 
 static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
+       const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        u32 x_recv, pinv;
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
 
-       if (hcrx == NULL || !(sk->sk_state == DCCP_OPEN ||
-                             sk->sk_state == DCCP_PARTOPEN))
+       BUG_ON(hcrx == NULL);
+
+       if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
                return;
 
        DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
@@ -851,8 +818,7 @@ static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
 
 static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
        u32 rtt, delta, x_recv, fval, p, tmp2;
        struct timeval tstamp = { 0, };
@@ -883,17 +849,17 @@ static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
                }
        }
 
-       if (step == 0) {
-               printk(KERN_CRIT "%s: %s, sk=%p, packet history contains no "
-                                "data packets!\n",
-                      __FUNCTION__, dccp_role(sk), sk);
+       if (unlikely(step == 0)) {
+               LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, packet history "
+                              "contains no data packets!\n",
+                              __FUNCTION__, dccp_role(sk), sk);
                return ~0;
        }
 
-       if (interval == 0) {
-               ccid3_pr_debug("%s, sk=%p, Could not find a win_count "
-                              "interval > 0. Defaulting to 1\n",
-                              dccp_role(sk), sk);
+       if (unlikely(interval == 0)) {
+               LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Could not find a "
+                              "win_count interval > 0. Defaulting to 1\n",
+                              __FUNCTION__, dccp_role(sk), sk);
                interval = 1;
        }
 found:
@@ -903,10 +869,9 @@ found:
        if (rtt == 0)
                rtt = 1;
 
-       delta = timeval_now_delta(&hcrx->ccid3hcrx_tstamp_last_feedback);
-       x_recv = hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC;
-       if (likely(delta > 1))
-               x_recv /= delta;
+       dccp_timestamp(sk, &tstamp);
+       delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback);
+       x_recv = usecs_div(hcrx->ccid3hcrx_bytes_recv, delta);
 
        tmp1 = (u64)x_recv * (u64)rtt;
        do_div(tmp1,10000000);
@@ -925,8 +890,7 @@ found:
 
 static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
 
        if (seq_loss != DCCP_MAX_SEQNO + 1 &&
            list_empty(&hcrx->ccid3hcrx_li_hist)) {
@@ -938,14 +902,14 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
                if (li_tail == NULL)
                        return;
                li_tail->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
-       }
-       /* FIXME: find end of interval */
+       } else
+                   LIMIT_NETDEBUG(KERN_WARNING "%s: FIXME: find end of "
+                                  "interval\n", __FUNCTION__);
 }
 
 static void ccid3_hc_rx_detect_loss(struct sock *sk)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        u8 win_loss;
        const u64 seq_loss = dccp_rx_hist_detect_loss(&hcrx->ccid3hcrx_hist,
                                                      &hcrx->ccid3hcrx_li_hist,
@@ -956,8 +920,7 @@ static void ccid3_hc_rx_detect_loss(struct sock *sk)
 
 static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
 {
-       struct dccp_sock *dp = dccp_sk(sk);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
        const struct dccp_options_received *opt_recv;
        struct dccp_rx_hist_entry *packet;
        struct timeval now;
@@ -965,13 +928,11 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        u32 p_prev, r_sample, t_elapsed;
        int ins;
 
-       if (hcrx == NULL)
-               return;
-
-       BUG_ON(!(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
+       BUG_ON(hcrx == NULL ||
+              !(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
                 hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA));
 
-       opt_recv = &dp->dccps_options_received;
+       opt_recv = &dccp_sk(sk)->dccps_options_received;
 
        switch (DCCP_SKB_CB(skb)->dccpd_type) {
        case DCCP_PKT_ACK:
@@ -981,14 +942,14 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                if (opt_recv->dccpor_timestamp_echo == 0)
                        break;
                p_prev = hcrx->ccid3hcrx_rtt;
-               do_gettimeofday(&now);
+               dccp_timestamp(sk, &now);
                timeval_sub_usecs(&now, opt_recv->dccpor_timestamp_echo * 10);
                r_sample = timeval_usecs(&now);
                t_elapsed = opt_recv->dccpor_elapsed_time * 10;
 
                if (unlikely(r_sample <= t_elapsed))
-                       LIMIT_NETDEBUG(KERN_WARNING
-                                      "%s: r_sample=%uus, t_elapsed=%uus\n",
+                       LIMIT_NETDEBUG(KERN_WARNING "%s: r_sample=%uus, "
+                                      "t_elapsed=%uus\n",
                                       __FUNCTION__, r_sample, t_elapsed);
                else
                        r_sample -= t_elapsed;
@@ -1006,19 +967,16 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                break;
        case DCCP_PKT_DATA:
                break;
-       default:
-               ccid3_pr_debug("%s, sk=%p, not DATA/DATAACK/ACK packet(%s)\n",
-                              dccp_role(sk), sk,
-                              dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+       default: /* We're not interested in other packet types, move along */
                return;
        }
 
-       packet = dccp_rx_hist_entry_new(ccid3_rx_hist, opt_recv->dccpor_ndp,
+       packet = dccp_rx_hist_entry_new(ccid3_rx_hist, sk, opt_recv->dccpor_ndp,
                                        skb, SLAB_ATOMIC);
-       if (packet == NULL) {
-               ccid3_pr_debug("%s, sk=%p, Not enough mem to add rx packet "
-                              "to history (consider it lost)!",
-                              dccp_role(sk), sk);
+       if (unlikely(packet == NULL)) {
+               LIMIT_NETDEBUG(KERN_WARNING "%s: %s, sk=%p, Not enough mem to "
+                               "add rx packet to history, consider it lost!\n",
+                              __FUNCTION__, dccp_role(sk), sk);
                return;
        }
 
@@ -1045,7 +1003,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
                if (ins != 0)
                        break;
 
-               do_gettimeofday(&now);
+               dccp_timestamp(sk, &now);
                if (timeval_delta(&now, &hcrx->ccid3hcrx_tstamp_last_ack) >=
                    hcrx->ccid3hcrx_rtt) {
                        hcrx->ccid3hcrx_tstamp_last_ack = now;
@@ -1067,9 +1025,13 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
        p_prev = hcrx->ccid3hcrx_p;
        
        /* Calculate loss event rate */
-       if (!list_empty(&hcrx->ccid3hcrx_li_hist))
+       if (!list_empty(&hcrx->ccid3hcrx_li_hist)) {
+               u32 i_mean = dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist);
+
                /* Scaling up by 1000000 as fixed decimal */
-               hcrx->ccid3hcrx_p = 1000000 / dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist);
+               if (i_mean != 0)
+                       hcrx->ccid3hcrx_p = 1000000 / i_mean;
+       }
 
        if (hcrx->ccid3hcrx_p > p_prev) {
                ccid3_hc_rx_send_feedback(sk);
@@ -1084,11 +1046,11 @@ static int ccid3_hc_rx_init(struct sock *sk)
 
        ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
 
-       hcrx = dp->dccps_hc_rx_ccid_private = kmalloc(sizeof(*hcrx),
-                                                     gfp_any());
-       if (hcrx == NULL)
+       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 &&
@@ -1100,7 +1062,7 @@ static int ccid3_hc_rx_init(struct sock *sk)
        hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
        INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
        INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist);
-       do_gettimeofday(&hcrx->ccid3hcrx_tstamp_last_ack);
+       dccp_timestamp(sk, &hcrx->ccid3hcrx_tstamp_last_ack);
        hcrx->ccid3hcrx_tstamp_last_feedback = hcrx->ccid3hcrx_tstamp_last_ack;
        hcrx->ccid3hcrx_rtt = 5000; /* XXX 5ms for now... */
        return 0;
@@ -1108,13 +1070,10 @@ static int ccid3_hc_rx_init(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);
-       struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
-
-       ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
 
-       if (hcrx == NULL)
-               return;
+       BUG_ON(hcrx == NULL);
 
        ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
 
@@ -1130,12 +1089,14 @@ static void ccid3_hc_rx_exit(struct sock *sk)
 
 static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
-       const struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
+       const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
 
-       if (hcrx == NULL)
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
                return;
 
+       BUG_ON(hcrx == NULL);
+
        info->tcpi_ca_state     = hcrx->ccid3hcrx_state;
        info->tcpi_options      |= TCPI_OPT_TIMESTAMPS;
        info->tcpi_rcv_rtt      = hcrx->ccid3hcrx_rtt;
@@ -1143,22 +1104,76 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
 
 static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
 {
-       const struct dccp_sock *dp = dccp_sk(sk);
-       const struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
+       const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
-       if (hctx == NULL)
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
                return;
 
+       BUG_ON(hctx == NULL);
+
        info->tcpi_rto = hctx->ccid3hctx_t_rto;
        info->tcpi_rtt = hctx->ccid3hctx_rtt;
 }
 
+static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
+                                 u32 __user *optval, int __user *optlen)
+{
+       const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+       const void *val;
+       
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
+               return -EINVAL;
+
+       switch (optname) {
+       case DCCP_SOCKOPT_CCID_RX_INFO:
+               if (len < sizeof(hcrx->ccid3hcrx_tfrc))
+                       return -EINVAL;
+               len = sizeof(hcrx->ccid3hcrx_tfrc);
+               val = &hcrx->ccid3hcrx_tfrc;
+               break;
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, val, len))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
+                                 u32 __user *optval, int __user *optlen)
+{
+       const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+       const void *val;
+       
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
+               return -EINVAL;
+
+       switch (optname) {
+       case DCCP_SOCKOPT_CCID_TX_INFO:
+               if (len < sizeof(hctx->ccid3hctx_tfrc))
+                       return -EINVAL;
+               len = sizeof(hctx->ccid3hctx_tfrc);
+               val = &hctx->ccid3hctx_tfrc;
+               break;
+       default:
+               return -ENOPROTOOPT;
+       }
+
+       if (put_user(len, optlen) || copy_to_user(optval, val, len))
+               return -EFAULT;
+
+       return 0;
+}
+
 static struct ccid ccid3 = {
        .ccid_id                   = 3,
        .ccid_name                 = "ccid3",
        .ccid_owner                = THIS_MODULE,
-       .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,
@@ -1172,6 +1187,8 @@ static struct ccid ccid3 = {
        .ccid_hc_rx_packet_recv    = ccid3_hc_rx_packet_recv,
        .ccid_hc_rx_get_info       = ccid3_hc_rx_get_info,
        .ccid_hc_tx_get_info       = ccid3_hc_tx_get_info,
+       .ccid_hc_rx_getsockopt     = ccid3_hc_rx_getsockopt,
+       .ccid_hc_tx_getsockopt     = ccid3_hc_tx_getsockopt,
 };
  
 module_param(ccid3_debug, int, 0444);