* 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>
*
* An implementation of the DCCP protocol
*
* This code has been developed by the University of Waikato WAND
* research group. For further information please see http://www.wand.net.nz/
- * or e-mail Ian McDonald - iam4@cs.waikato.ac.nz
*
* This code also uses code from Lulea University, rereleased as GPL by its
* authors:
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/config.h>
#include "../ccid.h"
#include "../dccp.h"
+#include "../packet_history.h"
#include "ccid3.h"
#ifdef CCID3_DEBUG
#define TFRC_STD_PACKET_SIZE 256
#define TFRC_MAX_PACKET_SIZE 65535
-#define USEC_IN_SEC 1000000
-
-#define TFRC_INITIAL_TIMEOUT (2 * USEC_IN_SEC)
+#define TFRC_INITIAL_TIMEOUT (2 * USEC_PER_SEC)
/* two seconds as per CCID3 spec 11 */
-#define TFRC_OPSYS_HALF_TIME_GRAN (USEC_IN_SEC / (2 * HZ))
+#define TFRC_OPSYS_HALF_TIME_GRAN (USEC_PER_SEC / (2 * HZ))
/* above is in usecs - half the scheduling granularity as per RFC3448 4.6 */
#define TFRC_WIN_COUNT_PER_RTT 4
static int ccid3_debug;
-static kmem_cache_t *ccid3_tx_hist_slab;
-static kmem_cache_t *ccid3_rx_hist_slab;
-static kmem_cache_t *ccid3_loss_interval_hist_slab;
-
-static inline struct ccid3_tx_hist_entry *ccid3_tx_hist_entry_new(int prio)
-{
- struct ccid3_tx_hist_entry *entry = kmem_cache_alloc(ccid3_tx_hist_slab, prio);
-
- if (entry != NULL)
- entry->ccid3htx_sent = 0;
-
- return entry;
-}
+static struct dccp_tx_hist *ccid3_tx_hist;
+static struct dccp_rx_hist *ccid3_rx_hist;
-static inline void ccid3_tx_hist_entry_delete(struct ccid3_tx_hist_entry *entry)
-{
- if (entry != NULL)
- kmem_cache_free(ccid3_tx_hist_slab, entry);
-}
+static kmem_cache_t *ccid3_loss_interval_hist_slab __read_mostly;
-static inline struct ccid3_rx_hist_entry *ccid3_rx_hist_entry_new(struct sock *sk,
- struct sk_buff *skb,
- int prio)
-{
- struct ccid3_rx_hist_entry *entry = kmem_cache_alloc(ccid3_rx_hist_slab, prio);
-
- if (entry != NULL) {
- const struct dccp_hdr *dh = dccp_hdr(skb);
-
- entry->ccid3hrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
- entry->ccid3hrx_win_count = dh->dccph_ccval;
- entry->ccid3hrx_type = dh->dccph_type;
- entry->ccid3hrx_ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp;
- do_gettimeofday(&(entry->ccid3hrx_tstamp));
- }
-
- return entry;
-}
-
-static inline void ccid3_rx_hist_entry_delete(struct ccid3_rx_hist_entry *entry)
-{
- if (entry != NULL)
- kmem_cache_free(ccid3_rx_hist_slab, entry);
-}
-
-static void ccid3_rx_history_delete(struct list_head *hist)
-{
- struct ccid3_rx_hist_entry *entry, *next;
-
- list_for_each_entry_safe(entry, next, hist, ccid3hrx_node) {
- list_del_init(&entry->ccid3hrx_node);
- kmem_cache_free(ccid3_rx_hist_slab, entry);
- }
-}
-
-static inline struct ccid3_loss_interval_hist_entry *ccid3_loss_interval_hist_entry_new(int prio)
+static inline struct ccid3_loss_interval_hist_entry *
+ ccid3_loss_interval_hist_entry_new(const unsigned int __nocast prio)
{
return kmem_cache_alloc(ccid3_loss_interval_hist_slab, prio);
}
hctx->ccid3hctx_state = state;
}
-static void timeval_sub(struct timeval large, struct timeval small, struct timeval *result) {
-
+static void timeval_sub(struct timeval large, struct timeval small,
+ struct timeval *result)
+{
result->tv_sec = large.tv_sec-small.tv_sec;
if (large.tv_usec < small.tv_usec) {
(result->tv_sec)--;
- result->tv_usec = USEC_IN_SEC+large.tv_usec-small.tv_usec;
+ result->tv_usec = USEC_PER_SEC +
+ large.tv_usec - small.tv_usec;
} else
result->tv_usec = large.tv_usec-small.tv_usec;
}
-static inline void timeval_fix(struct timeval *tv) {
- if (tv->tv_usec >= USEC_IN_SEC) {
+static inline void timeval_fix(struct timeval *tv)
+{
+ if (tv->tv_usec >= USEC_PER_SEC) {
tv->tv_sec++;
- tv->tv_usec -= USEC_IN_SEC;
+ tv->tv_usec -= USEC_PER_SEC;
}
}
-/* returns the difference in usecs between timeval passed in and current time */
-static inline u32 now_delta(struct timeval tv) {
- struct timeval now;
-
- do_gettimeofday(&now);
- return ((now.tv_sec-tv.tv_sec)*1000000+now.tv_usec-tv.tv_usec);
-}
-
#define CALCX_ARRSIZE 500
#define CALCX_SPLIT 50000
hctx->ccid3hctx_x = 10;
}
/* Schedule no feedback timer to expire in max(4 * R, 2 * s / X) */
- next_tmout = max_t(u32, inet_csk(sk)->icsk_rto,
+ next_tmout = max_t(u32, hctx->ccid3hctx_t_rto,
2 * (hctx->ccid3hctx_s * 100000) / (hctx->ccid3hctx_x / 10));
break;
default:
sock_put(sk);
}
-static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb,
- int len, long *delay)
+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_tx_hist_entry *new_packet = NULL;
+ struct dccp_tx_hist_entry *new_packet;
struct timeval now;
+ long delay;
int rc = -ENOTCONN;
// ccid3_pr_debug("%s, sk=%p, skb=%p, len=%d\n", dccp_role(sk), sk, skb, len);
goto out;
/* See if last packet allocated was not sent */
- if (!list_empty(&hctx->ccid3hctx_hist))
- new_packet = list_entry(hctx->ccid3hctx_hist.next,
- struct ccid3_tx_hist_entry, ccid3htx_node);
-
- if (new_packet == NULL || new_packet->ccid3htx_sent) {
- new_packet = ccid3_tx_hist_entry_new(SLAB_ATOMIC);
+ new_packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
+ if (new_packet == NULL || new_packet->dccphtx_sent) {
+ new_packet = dccp_tx_hist_entry_new(ccid3_tx_hist, SLAB_ATOMIC);
rc = -ENOBUFS;
if (new_packet == NULL) {
goto out;
}
- list_add(&new_packet->ccid3htx_node, &hctx->ccid3hctx_hist);
+ dccp_tx_hist_add_entry(&hctx->ccid3hctx_hist, new_packet);
}
do_gettimeofday(&now);
break;
case TFRC_SSTATE_NO_FBACK:
case TFRC_SSTATE_FBACK:
- *delay = (now_delta(hctx->ccid3hctx_t_nom) - hctx->ccid3hctx_delta);
- ccid3_pr_debug("send_packet delay=%ld\n",*delay);
- *delay /= -1000;
+ delay = (now_delta(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 ? -EAGAIN : 0;
+ rc = delay > 0 ? -EAGAIN : 0;
break;
default:
printk(KERN_CRIT "%s: %s, sk=%p, Illegal state (%d)!\n",
/* Can we send? if so add options and add to packet history */
if (rc == 0)
- new_packet->ccid3htx_win_count = DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+ new_packet->dccphtx_ccval =
+ DCCP_SKB_CB(skb)->dccpd_ccval =
+ hctx->ccid3hctx_last_win_count;
out:
return rc;
}
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
- struct ccid3_tx_hist_entry *packet = NULL;
struct timeval now;
-// ccid3_pr_debug("%s, sk=%p, more=%d, len=%d\n", dccp_role(sk), sk, more, len);
BUG_ON(hctx == NULL);
if (hctx->ccid3hctx_state == TFRC_SSTATE_TERM) {
/* check if we have sent a data packet */
if (len > 0) {
unsigned long quarter_rtt;
+ struct dccp_tx_hist_entry *packet;
- if (list_empty(&hctx->ccid3hctx_hist)) {
+ packet = dccp_tx_hist_head(&hctx->ccid3hctx_hist);
+ if (packet == NULL) {
printk(KERN_CRIT "%s: packet doesn't exists in history!\n", __FUNCTION__);
return;
}
- packet = list_entry(hctx->ccid3hctx_hist.next, struct ccid3_tx_hist_entry, ccid3htx_node);
- if (packet->ccid3htx_sent) {
+ if (packet->dccphtx_sent) {
printk(KERN_CRIT "%s: no unsent packet in history!\n", __FUNCTION__);
return;
}
- packet->ccid3htx_tstamp = now;
- packet->ccid3htx_seqno = dp->dccps_gss;
- // ccid3_pr_debug("%s, sk=%p, seqno=%llu inserted!\n", dccp_role(sk), sk, packet->ccid3htx_seqno);
-
+ packet->dccphtx_tstamp = now;
+ packet->dccphtx_seqno = dp->dccps_gss;
+#if 0
+ ccid3_pr_debug("%s, sk=%p, seqno=%llu inserted!\n",
+ dccp_role(sk), sk, packet->dccphtx_seqno);
+#endif
/*
* Check if win_count have changed */
/* COMPLIANCE_BEGIN
min_t(unsigned long, quarter_rtt, 5)) % 16;
ccid3_pr_debug("%s, sk=%p, window changed from %u to %u!\n",
dccp_role(sk), sk,
- packet->ccid3htx_win_count,
+ packet->dccphtx_ccval,
hctx->ccid3hctx_last_win_count);
}
/* COMPLIANCE_END */
#if 0
ccid3_pr_debug("%s, sk=%p, packet sent (%llu,%u)\n",
dccp_role(sk), sk,
- packet->ccid3htx_seqno,
- packet->ccid3htx_win_count);
+ packet->dccphtx_seqno,
+ packet->dccphtx_ccval);
#endif
hctx->ccid3hctx_idle = 0;
- packet->ccid3htx_sent = 1;
+ packet->dccphtx_rtt = hctx->ccid3hctx_rtt;
+ packet->dccphtx_sent = 1;
} else
ccid3_pr_debug("%s, sk=%p, seqno=%llu NOT inserted!\n",
dccp_role(sk), sk, dp->dccps_gss);
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
struct ccid3_options_received *opt_recv;
- struct ccid3_tx_hist_entry *entry, *next, *packet;
+ struct dccp_tx_hist_entry *packet;
unsigned long next_tmout;
- u16 t_elapsed;
+ u32 t_elapsed;
u32 pinv;
u32 x_recv;
u32 r_sample;
/* Calculate new round trip sample by
* R_sample = (now - t_recvdata) - t_delay */
/* get t_recvdata from history */
- packet = NULL;
- list_for_each_entry_safe(entry, next, &hctx->ccid3hctx_hist, ccid3htx_node)
- if (entry->ccid3htx_seqno == DCCP_SKB_CB(skb)->dccpd_ack_seq) {
- packet = entry;
- break;
- }
-
+ 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,
}
/* Update RTT */
- r_sample = now_delta(packet->ccid3htx_tstamp);
+ r_sample = now_delta(packet->dccphtx_tstamp);
/* FIXME: */
// r_sample -= usecs_to_jiffies(t_elapsed * 10);
r_sample);
/* Update timeout interval */
- inet_csk(sk)->icsk_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt, USEC_IN_SEC);
+ hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
+ USEC_PER_SEC);
/* Update receive rate */
hctx->ccid3hctx_x_recv = x_recv; /* x_recv in bytes per second */
/* Update next send time */
if (hctx->ccid3hctx_t_ipi > (hctx->ccid3hctx_t_nom).tv_usec) {
- (hctx->ccid3hctx_t_nom).tv_usec += USEC_IN_SEC;
+ hctx->ccid3hctx_t_nom.tv_usec += USEC_PER_SEC;
(hctx->ccid3hctx_t_nom).tv_sec--;
}
/* FIXME - if no feedback then t_ipi can go > 1 second */
ccid3_calc_new_delta(hctx);
/* remove all packets older than the one acked from history */
-#if 0
- FIXME!
- list_for_each_entry_safe_continue(entry, next, &hctx->ccid3hctx_hist, ccid3htx_node) {
- list_del_init(&entry->ccid3htx_node);
- ccid3_tx_hist_entry_delete(entry);
- }
-#endif
+ dccp_tx_hist_purge_older(ccid3_tx_hist,
+ &hctx->ccid3hctx_hist, packet);
+
if (hctx->ccid3hctx_x < 10) {
ccid3_pr_debug("ccid3_hc_tx_packet_recv hctx->ccid3hctx_x < 10\n");
hctx->ccid3hctx_x = 10;
/* to prevent divide by zero below */
/* Schedule no feedback timer to expire in max(4 * R, 2 * s / X) */
- next_tmout = max(inet_csk(sk)->icsk_rto,
- 2 * (hctx->ccid3hctx_s * 100000) / (hctx->ccid3hctx_x/10));
+ next_tmout = max(hctx->ccid3hctx_t_rto,
+ (2 * (hctx->ccid3hctx_s * 100000) /
+ (hctx->ccid3hctx_x / 10)));
/* maths with 100000 and 10 is to prevent overflow with 32 bit */
ccid3_pr_debug("%s, sk=%p, Scheduled no feedback timer to expire in %lu jiffies (%luus)\n",
hctx->ccid3hctx_x = hctx->ccid3hctx_s; /* set transmission rate to 1 packet per second */
hctx->ccid3hctx_rtt = 4; /* See ccid3_hc_tx_packet_sent win_count calculatation */
- inet_csk(sk)->icsk_rto = USEC_IN_SEC;
+ hctx->ccid3hctx_t_rto = USEC_PER_SEC;
hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
INIT_LIST_HEAD(&hctx->ccid3hctx_hist);
init_timer(&hctx->ccid3hctx_no_feedback_timer);
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = dp->dccps_hc_tx_ccid_private;
- struct ccid3_tx_hist_entry *entry, *next;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
BUG_ON(hctx == NULL);
sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
/* Empty packet history */
- list_for_each_entry_safe(entry, next, &hctx->ccid3hctx_hist, ccid3htx_node) {
- list_del_init(&entry->ccid3htx_node);
- ccid3_tx_hist_entry_delete(entry);
- }
+ dccp_tx_hist_purge(ccid3_tx_hist, &hctx->ccid3hctx_hist);
kfree(dp->dccps_hc_tx_ccid_private);
dp->dccps_hc_tx_ccid_private = NULL;
hcrx->ccid3hcrx_state = state;
}
-static int ccid3_hc_rx_add_hist(struct sock *sk, struct ccid3_rx_hist_entry *packet)
+static int ccid3_hc_rx_add_hist(struct sock *sk,
+ struct dccp_rx_hist_entry *packet)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
- struct ccid3_rx_hist_entry *entry, *next;
+ struct dccp_rx_hist_entry *entry, *next, *iter;
u8 num_later = 0;
- if (list_empty(&hcrx->ccid3hcrx_hist))
- list_add(&packet->ccid3hrx_node, &hcrx->ccid3hcrx_hist);
+ iter = dccp_rx_hist_head(&hcrx->ccid3hcrx_hist);
+ if (iter == NULL)
+ dccp_rx_hist_add_entry(&hcrx->ccid3hcrx_hist, packet);
else {
- u64 seqno = packet->ccid3hrx_seqno;
- struct ccid3_rx_hist_entry *iter = list_entry(hcrx->ccid3hcrx_hist.next,
- struct ccid3_rx_hist_entry,
- ccid3hrx_node);
- if (after48(seqno, iter->ccid3hrx_seqno))
- list_add(&packet->ccid3hrx_node, &hcrx->ccid3hcrx_hist);
+ const u64 seqno = packet->dccphrx_seqno;
+
+ if (after48(seqno, iter->dccphrx_seqno))
+ dccp_rx_hist_add_entry(&hcrx->ccid3hcrx_hist, packet);
else {
- if (iter->ccid3hrx_type == DCCP_PKT_DATA ||
- iter->ccid3hrx_type == DCCP_PKT_DATAACK)
+ if (dccp_rx_hist_entry_data_packet(iter))
num_later = 1;
- list_for_each_entry_continue(iter, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
- if (after48(seqno, iter->ccid3hrx_seqno)) {
- list_add(&packet->ccid3hrx_node, &iter->ccid3hrx_node);
+ list_for_each_entry_continue(iter,
+ &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
+ if (after48(seqno, iter->dccphrx_seqno)) {
+ dccp_rx_hist_add_entry(&iter->dccphrx_node,
+ packet);
goto trim_history;
}
- if (iter->ccid3hrx_type == DCCP_PKT_DATA ||
- iter->ccid3hrx_type == DCCP_PKT_DATAACK)
+ if (dccp_rx_hist_entry_data_packet(iter))
num_later++;
if (num_later == TFRC_RECV_NUM_LATE_LOSS) {
- ccid3_rx_hist_entry_delete(packet);
+ dccp_rx_hist_entry_delete(ccid3_rx_hist, packet);
ccid3_pr_debug("%s, sk=%p, packet(%llu) already lost!\n",
dccp_role(sk), sk, seqno);
return 1;
}
if (num_later < TFRC_RECV_NUM_LATE_LOSS)
- list_add_tail(&packet->ccid3hrx_node, &hcrx->ccid3hcrx_hist);
+ dccp_rx_hist_add_entry(&hcrx->ccid3hcrx_hist,
+ packet);
/* FIXME: else what? should we destroy the packet like above? */
}
}
num_later = TFRC_RECV_NUM_LATE_LOSS + 1;
if (!list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) {
- list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
+ list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
if (num_later == 0) {
- list_del_init(&entry->ccid3hrx_node);
- ccid3_rx_hist_entry_delete(entry);
- } else if (entry->ccid3hrx_type == DCCP_PKT_DATA ||
- entry->ccid3hrx_type == DCCP_PKT_DATAACK)
+ list_del_init(&entry->dccphrx_node);
+ dccp_rx_hist_entry_delete(ccid3_rx_hist, entry);
+ } else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
} else {
* We have no loss interval history so we need at least one
* rtt:s of data packets to approximate rtt.
*/
- list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
+ list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
if (num_later == 0) {
switch (step) {
case 0:
step = 2;
/* OK, find next data packet */
num_later = 1;
- win_count = entry->ccid3hrx_win_count;
+ win_count = entry->dccphrx_ccval;
break;
case 2:
- tmp = win_count - entry->ccid3hrx_win_count;
+ tmp = win_count - entry->dccphrx_ccval;
if (tmp < 0)
tmp += TFRC_WIN_COUNT_LIMIT;
if (tmp > TFRC_WIN_COUNT_PER_RTT + 1) {
num_later = 1;
break;
case 3:
- list_del_init(&entry->ccid3hrx_node);
- ccid3_rx_hist_entry_delete(entry);
+ list_del_init(&entry->dccphrx_node);
+ dccp_rx_hist_entry_delete(ccid3_rx_hist, entry);
break;
}
- } else if (entry->ccid3hrx_type == DCCP_PKT_DATA ||
- entry->ccid3hrx_type == DCCP_PKT_DATAACK)
+ } else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
}
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
- struct ccid3_rx_hist_entry *entry, *packet;
+ struct dccp_rx_hist_entry *packet;
ccid3_pr_debug("%s, sk=%p\n", dccp_role(sk), sk);
if (delta == 0)
delta = 1; /* to prevent divide by zero */
- hcrx->ccid3hcrx_x_recv = (hcrx->ccid3hcrx_bytes_recv * USEC_IN_SEC) / delta;
+ hcrx->ccid3hcrx_x_recv = (hcrx->ccid3hcrx_bytes_recv *
+ USEC_PER_SEC) / delta;
}
break;
default:
return;
}
- packet = NULL;
- list_for_each_entry(entry, &hcrx->ccid3hcrx_hist, ccid3hrx_node)
- if (entry->ccid3hrx_type == DCCP_PKT_DATA ||
- entry->ccid3hrx_type == DCCP_PKT_DATAACK) {
- packet = entry;
- break;
- }
-
+ 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);
}
do_gettimeofday(&(hcrx->ccid3hcrx_tstamp_last_feedback));
- hcrx->ccid3hcrx_last_counter = packet->ccid3hrx_win_count;
- hcrx->ccid3hcrx_seqno_last_counter = packet->ccid3hrx_seqno;
+ 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 */
- hcrx->ccid3hcrx_elapsed_time = now_delta(packet->ccid3hrx_tstamp) / 10;
+ hcrx->ccid3hcrx_elapsed_time = now_delta(packet->dccphrx_tstamp) / 10;
if (hcrx->ccid3hcrx_p == 0)
hcrx->ccid3hcrx_pinv = ~0;
else
static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_sock *dp = dccp_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))
return;
- if (hcrx->ccid3hcrx_elapsed_time != 0 && !dccp_packet_without_ack(skb))
- dccp_insert_option_elapsed_time(sk, skb, hcrx->ccid3hcrx_elapsed_time);
-
- if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) {
- const u32 x_recv = htonl(hcrx->ccid3hcrx_x_recv);
- const u32 pinv = htonl(hcrx->ccid3hcrx_pinv);
-
- 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));
- }
-
DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
+
+ if (dccp_packet_without_ack(skb))
+ 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);
+ 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));
}
/* Weights used to calculate loss event rate */
* These are integers as per section 8 of RFC3448. We can then divide by 4 *
* when we use it.
*/
-const int ccid3_hc_rx_w[TFRC_RECV_IVAL_F_LENGTH] = { 4, 4, 4, 4, 3, 2, 1, 1, };
+static const int ccid3_hc_rx_w[TFRC_RECV_IVAL_F_LENGTH] = {
+ 4, 4, 4, 4, 3, 2, 1, 1,
+};
/*
* args: fvalue - function value to match
*
* both fvalue and p are multiplied by 1,000,000 to use ints
*/
-u32 calcx_reverse_lookup(u32 fvalue) {
+static u32 calcx_reverse_lookup(u32 fvalue) {
int ctr = 0;
int small;
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
- struct ccid3_rx_hist_entry *entry, *next, *tail = NULL;
+ struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
u32 rtt, delta, x_recv, fval, p, tmp2;
- struct timeval tstamp, tmp_tv;
+ struct timeval tstamp = { 0 }, tmp_tv;
int interval = 0;
int win_count = 0;
int step = 0;
u64 tmp1;
- list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
- if (entry->ccid3hrx_type == DCCP_PKT_DATA ||
- entry->ccid3hrx_type == DCCP_PKT_DATAACK) {
+ list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
+ if (dccp_rx_hist_entry_data_packet(entry)) {
tail = entry;
switch (step) {
case 0:
- tstamp = entry->ccid3hrx_tstamp;
- win_count = entry->ccid3hrx_win_count;
+ tstamp = entry->dccphrx_tstamp;
+ win_count = entry->dccphrx_ccval;
step = 1;
break;
case 1:
- interval = win_count - entry->ccid3hrx_win_count;
+ interval = win_count - entry->dccphrx_ccval;
if (interval < 0)
interval += TFRC_WIN_COUNT_LIMIT;
if (interval > 4)
interval = 1;
}
found:
- timeval_sub(tstamp,tail->ccid3hrx_tstamp,&tmp_tv);
- rtt = (tmp_tv.tv_sec * USEC_IN_SEC + tmp_tv.tv_usec) * 4 / interval;
+ timeval_sub(tstamp,tail->dccphrx_tstamp,&tmp_tv);
+ rtt = (tmp_tv.tv_sec * USEC_PER_SEC + tmp_tv.tv_usec) * 4 / interval;
ccid3_pr_debug("%s, sk=%p, approximated RTT to %uus\n",
dccp_role(sk), sk, rtt);
if (rtt == 0)
if (delta == 0)
delta = 1;
- x_recv = (hcrx->ccid3hcrx_bytes_recv * USEC_IN_SEC) / delta;
+ x_recv = (hcrx->ccid3hcrx_bytes_recv * USEC_PER_SEC) / delta;
tmp1 = (u64)x_recv * (u64)rtt;
do_div(tmp1,10000000);
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
- struct ccid3_rx_hist_entry *entry, *a_next, *b_next, *packet;
- struct ccid3_rx_hist_entry *a_loss = NULL;
- struct ccid3_rx_hist_entry *b_loss = NULL;
+ struct dccp_rx_hist_entry *entry, *next, *packet;
+ struct dccp_rx_hist_entry *a_loss = NULL;
+ struct dccp_rx_hist_entry *b_loss = NULL;
u64 seq_loss = DCCP_MAX_SEQNO + 1;
u8 win_loss = 0;
u8 num_later = TFRC_RECV_NUM_LATE_LOSS;
- list_for_each_entry_safe(entry, b_next, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
+ list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
if (num_later == 0) {
b_loss = entry;
break;
- } else if (entry->ccid3hrx_type == DCCP_PKT_DATA ||
- entry->ccid3hrx_type == DCCP_PKT_DATAACK)
+ } else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
if (b_loss == NULL)
goto out_update_li;
- a_next = b_next;
num_later = 1;
-#if 0
- FIXME MERGE GIT!
- list_for_each_entry_safe_continue(entry, a_next, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
+
+ list_for_each_entry_safe_continue(entry, next, &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
if (num_later == 0) {
a_loss = entry;
break;
- } else if (entry->ccid3hrx_type == DCCP_PKT_DATA ||
- entry->ccid3hrx_type == DCCP_PKT_DATAACK)
+ } else if (dccp_rx_hist_entry_data_packet(entry))
--num_later;
}
-#endif
if (a_loss == NULL) {
if (list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) {
/* Locate a lost data packet */
entry = packet = b_loss;
-#if 0
- FIXME MERGE GIT!
- list_for_each_entry_safe_continue(entry, b_next, &hcrx->ccid3hcrx_hist, ccid3hrx_node) {
- u64 delta = dccp_delta_seqno(entry->ccid3hrx_seqno, packet->ccid3hrx_seqno);
+ list_for_each_entry_safe_continue(entry, next, &hcrx->ccid3hcrx_hist,
+ dccphrx_node) {
+ u64 delta = dccp_delta_seqno(entry->dccphrx_seqno,
+ packet->dccphrx_seqno);
if (delta != 0) {
- if (packet->ccid3hrx_type == DCCP_PKT_DATA ||
- packet->ccid3hrx_type == DCCP_PKT_DATAACK)
+ if (dccp_rx_hist_entry_data_packet(packet))
--delta;
/*
* FIXME: check this, probably this % usage is because
*/
#if 0
if (delta % DCCP_NDP_LIMIT !=
- (packet->ccid3hrx_ndp - entry->ccid3hrx_ndp) % DCCP_NDP_LIMIT)
+ (packet->dccphrx_ndp -
+ entry->dccphrx_ndp) % DCCP_NDP_LIMIT)
#endif
- if (delta != packet->ccid3hrx_ndp - entry->ccid3hrx_ndp) {
- seq_loss = entry->ccid3hrx_seqno;
+ if (delta !=
+ packet->dccphrx_ndp - entry->dccphrx_ndp) {
+ seq_loss = entry->dccphrx_seqno;
dccp_inc_seqno(&seq_loss);
}
}
if (packet == a_loss)
break;
}
-#endif
if (seq_loss != DCCP_MAX_SEQNO + 1)
- win_loss = a_loss->ccid3hrx_win_count;
+ win_loss = a_loss->dccphrx_ccval;
out_update_li:
ccid3_hc_rx_update_li(sk, seq_loss, win_loss);
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private;
- struct ccid3_rx_hist_entry *packet;
+ const struct dccp_options_received *opt_recv;
+ struct dccp_rx_hist_entry *packet;
struct timeval now;
+ u32 now_usecs;
u8 win_count;
u32 p_prev;
int ins;
BUG_ON(!(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA ||
hcrx->ccid3hcrx_state == TFRC_RSTATE_DATA));
+ opt_recv = &dp->dccps_options_received;
+
switch (DCCP_SKB_CB(skb)->dccpd_type) {
case DCCP_PKT_ACK:
if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
return;
case DCCP_PKT_DATAACK:
- if (dp->dccps_options_received.dccpor_timestamp_echo == 0)
+ if (opt_recv->dccpor_timestamp_echo == 0)
break;
p_prev = hcrx->ccid3hcrx_rtt;
do_gettimeofday(&now);
- /* hcrx->ccid3hcrx_rtt = now - dp->dccps_options_received.dccpor_timestamp_echo -
- usecs_to_jiffies(dp->dccps_options_received.dccpor_elapsed_time * 10);
- FIXME - I think above code is broken - have to look at options more, will also need
- to fix pr_debug below */
+ now_usecs = now.tv_sec * USEC_PER_SEC + now.tv_usec;
+ hcrx->ccid3hcrx_rtt = now_usecs -
+ (opt_recv->dccpor_timestamp_echo -
+ opt_recv->dccpor_elapsed_time) * 10;
if (p_prev != hcrx->ccid3hcrx_rtt)
- ccid3_pr_debug("%s, sk=%p, New RTT estimate=%lu jiffies, tstamp_echo=%u, elapsed time=%u\n",
- dccp_role(sk), sk, hcrx->ccid3hcrx_rtt,
- dp->dccps_options_received.dccpor_timestamp_echo,
- dp->dccps_options_received.dccpor_elapsed_time);
+ ccid3_pr_debug("%s, New RTT=%luus, elapsed time=%u\n",
+ dccp_role(sk), hcrx->ccid3hcrx_rtt,
+ opt_recv->dccpor_elapsed_time);
break;
case DCCP_PKT_DATA:
break;
return;
}
- packet = ccid3_rx_hist_entry_new(sk, skb, SLAB_ATOMIC);
+ packet = dccp_rx_hist_entry_new(ccid3_rx_hist, 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);
return;
}
- win_count = packet->ccid3hrx_win_count;
+ win_count = packet->dccphrx_ccval;
ins = ccid3_hc_rx_add_hist(sk, packet);
case TFRC_RSTATE_DATA:
hcrx->ccid3hcrx_bytes_recv += skb->len - dccp_hdr(skb)->dccph_doff * 4;
if (ins == 0) {
- do_gettimeofday(&now);
- if ((now_delta(hcrx->ccid3hcrx_tstamp_last_ack)) >= hcrx->ccid3hcrx_rtt) {
- hcrx->ccid3hcrx_tstamp_last_ack = now;
+ if (now_delta(hcrx->ccid3hcrx_tstamp_last_ack) >=
+ hcrx->ccid3hcrx_rtt) {
+ do_gettimeofday(&hcrx->ccid3hcrx_tstamp_last_ack);
ccid3_hc_rx_send_feedback(sk);
}
return;
}
/* Dealing with packet loss */
- ccid3_pr_debug("%s, sk=%p(%s), skb=%p, data loss! Reacting...\n",
- dccp_role(sk), sk, dccp_state_name(sk->sk_state), 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;
hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
INIT_LIST_HEAD(&hcrx->ccid3hcrx_loss_interval_hist);
-
+ /*
+ * XXX this seems to be paranoid, need to think more about this, for
+ * now start with something different than zero. -acme
+ */
+ hcrx->ccid3hcrx_rtt = USEC_PER_SEC / 5;
return 0;
}
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
/* Empty packet history */
- ccid3_rx_history_delete(&hcrx->ccid3hcrx_hist);
+ dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist);
/* Empty loss interval history */
ccid3_loss_interval_history_delete(&hcrx->ccid3hcrx_loss_interval_hist);
dp->dccps_hc_rx_ccid_private = NULL;
}
+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;
+
+ if (hcrx == NULL)
+ return;
+
+ info->tcpi_ca_state = hcrx->ccid3hcrx_state;
+ info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
+ info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
+}
+
+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;
+
+ if (hctx == NULL)
+ return;
+
+ info->tcpi_rto = hctx->ccid3hctx_t_rto;
+ info->tcpi_rtt = hctx->ccid3hctx_rtt;
+}
+
static struct ccid ccid3 = {
.ccid_id = 3,
.ccid_name = "ccid3",
.ccid_hc_rx_exit = ccid3_hc_rx_exit,
.ccid_hc_rx_insert_options = ccid3_hc_rx_insert_options,
.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,
};
module_param(ccid3_debug, int, 0444);
static __init int ccid3_module_init(void)
{
- int rc = -ENOMEM;
+ int rc = -ENOBUFS;
- ccid3_tx_hist_slab = kmem_cache_create("dccp_ccid3_tx_history",
- sizeof(struct ccid3_tx_hist_entry), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (ccid3_tx_hist_slab == NULL)
+ ccid3_rx_hist = dccp_rx_hist_new("ccid3");
+ if (ccid3_rx_hist == NULL)
goto out;
- ccid3_rx_hist_slab = kmem_cache_create("dccp_ccid3_rx_history",
- sizeof(struct ccid3_rx_hist_entry), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (ccid3_rx_hist_slab == NULL)
- goto out_free_tx_history;
+ ccid3_tx_hist = dccp_tx_hist_new("ccid3");
+ if (ccid3_tx_hist == NULL)
+ goto out_free_rx;
- ccid3_loss_interval_hist_slab = kmem_cache_create("dccp_ccid3_loss_interval_history",
- sizeof(struct ccid3_loss_interval_hist_entry), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ ccid3_loss_interval_hist_slab = kmem_cache_create("li_hist_ccid3",
+ sizeof(struct ccid3_loss_interval_hist_entry),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
if (ccid3_loss_interval_hist_slab == NULL)
- goto out_free_rx_history;
+ goto out_free_tx;
rc = ccid_register(&ccid3);
if (rc != 0)
goto out_free_loss_interval_history;
-
out:
return rc;
+
out_free_loss_interval_history:
kmem_cache_destroy(ccid3_loss_interval_hist_slab);
ccid3_loss_interval_hist_slab = NULL;
-out_free_rx_history:
- kmem_cache_destroy(ccid3_rx_hist_slab);
- ccid3_rx_hist_slab = NULL;
-out_free_tx_history:
- kmem_cache_destroy(ccid3_tx_hist_slab);
- ccid3_tx_hist_slab = NULL;
+out_free_tx:
+ dccp_tx_hist_delete(ccid3_tx_hist);
+ ccid3_tx_hist = NULL;
+out_free_rx:
+ dccp_rx_hist_delete(ccid3_rx_hist);
+ ccid3_rx_hist = NULL;
goto out;
}
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_slab != NULL) {
- kmem_cache_destroy(ccid3_tx_hist_slab);
- ccid3_tx_hist_slab = NULL;
+ if (ccid3_tx_hist != NULL) {
+ dccp_tx_hist_delete(ccid3_tx_hist);
+ ccid3_tx_hist = NULL;
}
- if (ccid3_rx_hist_slab != NULL) {
- kmem_cache_destroy(ccid3_rx_hist_slab);
- ccid3_rx_hist_slab = NULL;
+ if (ccid3_rx_hist != NULL) {
+ dccp_rx_hist_delete(ccid3_rx_hist);
+ ccid3_rx_hist = NULL;
}
if (ccid3_loss_interval_hist_slab != NULL) {
kmem_cache_destroy(ccid3_loss_interval_hist_slab);