summaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/ackvec.c20
-rw-r--r--net/dccp/ackvec.h4
-rw-r--r--net/dccp/ccids/Kconfig8
-rw-r--r--net/dccp/ccids/ccid2.c204
-rw-r--r--net/dccp/ccids/ccid2.h9
-rw-r--r--net/dccp/ccids/ccid3.c12
-rw-r--r--net/dccp/dccp.h2
-rw-r--r--net/dccp/feat.h5
-rw-r--r--net/dccp/ipv4.c14
-rw-r--r--net/dccp/ipv6.c15
-rw-r--r--net/dccp/output.c90
-rw-r--r--net/dccp/proto.c16
-rw-r--r--net/dccp/sysctl.c8
13 files changed, 264 insertions, 143 deletions
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 8c211c58893b..4d176d33983f 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -142,14 +142,13 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
if (av != NULL) {
- av->dccpav_buf_head =
- av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
+ av->dccpav_buf_head = DCCP_MAX_ACKVEC_LEN - 1;
av->dccpav_buf_ackno = DCCP_MAX_SEQNO + 1;
av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0;
av->dccpav_ack_ptr = 0;
av->dccpav_time.tv_sec = 0;
av->dccpav_time.tv_usec = 0;
- av->dccpav_sent_len = av->dccpav_vec_len = 0;
+ av->dccpav_vec_len = 0;
INIT_LIST_HEAD(&av->dccpav_records);
}
@@ -353,11 +352,13 @@ static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
{
struct dccp_ackvec_record *next;
- av->dccpav_buf_tail = avr->dccpavr_ack_ptr - 1;
- if (av->dccpav_buf_tail == 0)
- av->dccpav_buf_tail = DCCP_MAX_ACKVEC_LEN - 1;
-
- av->dccpav_vec_len -= avr->dccpavr_sent_len;
+ /* sort out vector length */
+ if (av->dccpav_buf_head <= avr->dccpavr_ack_ptr)
+ av->dccpav_vec_len = avr->dccpavr_ack_ptr - av->dccpav_buf_head;
+ else
+ av->dccpav_vec_len = DCCP_MAX_ACKVEC_LEN - 1
+ - av->dccpav_buf_head
+ + avr->dccpavr_ack_ptr;
/* free records */
list_for_each_entry_safe_from(avr, next, &av->dccpav_records,
@@ -434,8 +435,7 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
break;
found:
if (between48(avr->dccpavr_ack_seqno, ackno_end_rl, ackno)) {
- const u8 state = (*vector &
- DCCP_ACKVEC_STATE_MASK) >> 6;
+ const u8 state = *vector & DCCP_ACKVEC_STATE_MASK;
if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) {
#ifdef CONFIG_IP_DCCP_DEBUG
struct dccp_sock *dp = dccp_sk(sk);
diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h
index 0adf4b56c34c..2424effac7f6 100644
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -54,9 +54,7 @@ struct dccp_ackvec {
struct list_head dccpav_records;
struct timeval dccpav_time;
u8 dccpav_buf_head;
- u8 dccpav_buf_tail;
u8 dccpav_ack_ptr;
- u8 dccpav_sent_len;
u8 dccpav_vec_len;
u8 dccpav_buf_nonce;
u8 dccpav_ack_nonce;
@@ -107,7 +105,7 @@ extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb);
static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
{
- return av->dccpav_sent_len != av->dccpav_vec_len;
+ return av->dccpav_vec_len;
}
#else /* CONFIG_IP_DCCP_ACKVEC */
static inline int dccp_ackvec_init(void)
diff --git a/net/dccp/ccids/Kconfig b/net/dccp/ccids/Kconfig
index ca00191628f7..32752f750447 100644
--- a/net/dccp/ccids/Kconfig
+++ b/net/dccp/ccids/Kconfig
@@ -30,6 +30,14 @@ config IP_DCCP_CCID2
If in doubt, say M.
+config IP_DCCP_CCID2_DEBUG
+ bool "CCID2 debug"
+ depends on IP_DCCP_CCID2
+ ---help---
+ Enable CCID2 debug messages.
+
+ If in doubt, say N.
+
config IP_DCCP_CCID3
tristate "CCID3 (TCP-Friendly) (EXPERIMENTAL)"
depends on IP_DCCP
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index e9615627dcd6..457dd3db7f41 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -27,7 +27,6 @@
*
* BUGS:
* - sequence number wrapping
- * - jiffies wrapping
*/
#include "../ccid.h"
@@ -36,8 +35,7 @@
static int ccid2_debug;
-#undef CCID2_DEBUG
-#ifdef CCID2_DEBUG
+#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
#define ccid2_pr_debug(format, a...) \
do { if (ccid2_debug) \
printk(KERN_DEBUG "%s: " format, __FUNCTION__, ##a); \
@@ -46,9 +44,7 @@ static int ccid2_debug;
#define ccid2_pr_debug(format, a...)
#endif
-static const int ccid2_seq_len = 128;
-
-#ifdef CCID2_DEBUG
+#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
{
int len = 0;
@@ -71,8 +67,8 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
/* packets are sent sequentially */
BUG_ON(seqp->ccid2s_seq <= prev->ccid2s_seq);
- BUG_ON(seqp->ccid2s_sent < prev->ccid2s_sent);
- BUG_ON(len > ccid2_seq_len);
+ BUG_ON(time_before(seqp->ccid2s_sent,
+ prev->ccid2s_sent));
seqp = prev;
}
@@ -84,16 +80,57 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
do {
seqp = seqp->ccid2s_prev;
len++;
- BUG_ON(len > ccid2_seq_len);
} while (seqp != hctx->ccid2hctx_seqh);
- BUG_ON(len != ccid2_seq_len);
ccid2_pr_debug("total len=%d\n", len);
+ BUG_ON(len != hctx->ccid2hctx_seqbufc * CCID2_SEQBUF_LEN);
}
#else
#define ccid2_hc_tx_check_sanity(hctx) do {} while (0)
#endif
+static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx, int num,
+ gfp_t gfp)
+{
+ struct ccid2_seq *seqp;
+ int i;
+
+ /* check if we have space to preserve the pointer to the buffer */
+ if (hctx->ccid2hctx_seqbufc >= (sizeof(hctx->ccid2hctx_seqbuf) /
+ sizeof(struct ccid2_seq*)))
+ return -ENOMEM;
+
+ /* allocate buffer and initialize linked list */
+ seqp = kmalloc(sizeof(*seqp) * num, gfp);
+ if (seqp == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < (num - 1); i++) {
+ seqp[i].ccid2s_next = &seqp[i + 1];
+ seqp[i + 1].ccid2s_prev = &seqp[i];
+ }
+ seqp[num - 1].ccid2s_next = seqp;
+ seqp->ccid2s_prev = &seqp[num - 1];
+
+ /* This is the first allocation. Initiate the head and tail. */
+ if (hctx->ccid2hctx_seqbufc == 0)
+ hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqt = seqp;
+ else {
+ /* link the existing list with the one we just created */
+ hctx->ccid2hctx_seqh->ccid2s_next = seqp;
+ seqp->ccid2s_prev = hctx->ccid2hctx_seqh;
+
+ hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[num - 1];
+ seqp[num - 1].ccid2s_next = hctx->ccid2hctx_seqt;
+ }
+
+ /* store the original pointer to the buffer so we can free it */
+ hctx->ccid2hctx_seqbuf[hctx->ccid2hctx_seqbufc] = seqp;
+ hctx->ccid2hctx_seqbufc++;
+
+ return 0;
+}
+
static int ccid2_hc_tx_send_packet(struct sock *sk,
struct sk_buff *skb, int len)
{
@@ -122,7 +159,7 @@ static int ccid2_hc_tx_send_packet(struct sock *sk,
}
}
- return 100; /* XXX */
+ return 1; /* XXX CCID should dequeue when ready instead of polling */
}
static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
@@ -150,10 +187,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, int val)
dp->dccps_l_ack_ratio = val;
}
-static void ccid2_change_cwnd(struct sock *sk, int val)
+static void ccid2_change_cwnd(struct ccid2_hc_tx_sock *hctx, int val)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
-
if (val == 0)
val = 1;
@@ -164,6 +199,17 @@ static void ccid2_change_cwnd(struct sock *sk, int val)
hctx->ccid2hctx_cwnd = val;
}
+static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hctx, long val)
+{
+ ccid2_pr_debug("change SRTT to %ld\n", val);
+ hctx->ccid2hctx_srtt = val;
+}
+
+static void ccid2_change_pipe(struct ccid2_hc_tx_sock *hctx, long val)
+{
+ hctx->ccid2hctx_pipe = val;
+}
+
static void ccid2_start_rto_timer(struct sock *sk);
static void ccid2_hc_tx_rto_expire(unsigned long data)
@@ -193,11 +239,11 @@ static void ccid2_hc_tx_rto_expire(unsigned long data)
ccid2_start_rto_timer(sk);
/* adjust pipe, cwnd etc */
- hctx->ccid2hctx_pipe = 0;
+ ccid2_change_pipe(hctx, 0);
hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd >> 1;
if (hctx->ccid2hctx_ssthresh < 2)
hctx->ccid2hctx_ssthresh = 2;
- ccid2_change_cwnd(sk, 1);
+ ccid2_change_cwnd(hctx, 1);
/* clear state about stuff we sent */
hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh;
@@ -232,13 +278,14 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_seq *next;
u64 seq;
ccid2_hc_tx_check_sanity(hctx);
BUG_ON(!hctx->ccid2hctx_sendwait);
hctx->ccid2hctx_sendwait = 0;
- hctx->ccid2hctx_pipe++;
+ ccid2_change_pipe(hctx, hctx->ccid2hctx_pipe + 1);
BUG_ON(hctx->ccid2hctx_pipe < 0);
/* There is an issue. What if another packet is sent between
@@ -251,15 +298,23 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
hctx->ccid2hctx_seqh->ccid2s_seq = seq;
hctx->ccid2hctx_seqh->ccid2s_acked = 0;
hctx->ccid2hctx_seqh->ccid2s_sent = jiffies;
- hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqh->ccid2s_next;
- ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
- hctx->ccid2hctx_pipe);
+ next = hctx->ccid2hctx_seqh->ccid2s_next;
+ /* check if we need to alloc more space */
+ if (next == hctx->ccid2hctx_seqt) {
+ int rc;
+
+ ccid2_pr_debug("allocating more space in history\n");
+ rc = ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_KERNEL);
+ BUG_ON(rc); /* XXX what do we do? */
- if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt) {
- /* XXX allocate more space */
- WARN_ON(1);
+ next = hctx->ccid2hctx_seqh->ccid2s_next;
+ BUG_ON(next == hctx->ccid2hctx_seqt);
}
+ hctx->ccid2hctx_seqh = next;
+
+ ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
+ hctx->ccid2hctx_pipe);
hctx->ccid2hctx_sent++;
@@ -295,7 +350,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, int len)
if (!timer_pending(&hctx->ccid2hctx_rtotimer))
ccid2_start_rto_timer(sk);
-#ifdef CCID2_DEBUG
+#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
ccid2_pr_debug("pipe=%d\n", hctx->ccid2hctx_pipe);
ccid2_pr_debug("Sent: seq=%llu\n", seq);
do {
@@ -398,7 +453,7 @@ static inline void ccid2_new_ack(struct sock *sk,
/* increase every 2 acks */
hctx->ccid2hctx_ssacks++;
if (hctx->ccid2hctx_ssacks == 2) {
- ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+ ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd+1);
hctx->ccid2hctx_ssacks = 0;
*maxincr = *maxincr - 1;
}
@@ -411,26 +466,28 @@ static inline void ccid2_new_ack(struct sock *sk,
hctx->ccid2hctx_acks++;
if (hctx->ccid2hctx_acks >= hctx->ccid2hctx_cwnd) {
- ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd + 1);
+ ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd + 1);
hctx->ccid2hctx_acks = 0;
}
}
/* update RTO */
if (hctx->ccid2hctx_srtt == -1 ||
- (jiffies - hctx->ccid2hctx_lastrtt) >= hctx->ccid2hctx_srtt) {
- unsigned long r = jiffies - seqp->ccid2s_sent;
+ time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) {
+ unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent;
int s;
/* first measurement */
if (hctx->ccid2hctx_srtt == -1) {
ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
r, jiffies, seqp->ccid2s_seq);
- hctx->ccid2hctx_srtt = r;
+ ccid2_change_srtt(hctx, r);
hctx->ccid2hctx_rttvar = r >> 1;
} else {
/* RTTVAR */
long tmp = hctx->ccid2hctx_srtt - r;
+ long srtt;
+
if (tmp < 0)
tmp *= -1;
@@ -440,10 +497,12 @@ static inline void ccid2_new_ack(struct sock *sk,
hctx->ccid2hctx_rttvar += tmp;
/* SRTT */
- hctx->ccid2hctx_srtt *= 7;
- hctx->ccid2hctx_srtt >>= 3;
+ srtt = hctx->ccid2hctx_srtt;
+ srtt *= 7;
+ srtt >>= 3;
tmp = r >> 3;
- hctx->ccid2hctx_srtt += tmp;
+ srtt += tmp;
+ ccid2_change_srtt(hctx, srtt);
}
s = hctx->ccid2hctx_rttvar << 2;
/* clock granularity is 1 when based on jiffies */
@@ -479,13 +538,29 @@ static void ccid2_hc_tx_dec_pipe(struct sock *sk)
{
struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
- hctx->ccid2hctx_pipe--;
+ ccid2_change_pipe(hctx, hctx->ccid2hctx_pipe-1);
BUG_ON(hctx->ccid2hctx_pipe < 0);
if (hctx->ccid2hctx_pipe == 0)
ccid2_hc_tx_kill_rto_timer(sk);
}
+static void ccid2_congestion_event(struct ccid2_hc_tx_sock *hctx,
+ struct ccid2_seq *seqp)
+{
+ if (time_before(seqp->ccid2s_sent, hctx->ccid2hctx_last_cong)) {
+ ccid2_pr_debug("Multiple losses in an RTT---treating as one\n");
+ return;
+ }
+
+ hctx->ccid2hctx_last_cong = jiffies;
+
+ ccid2_change_cwnd(hctx, hctx->ccid2hctx_cwnd >> 1);
+ hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
+ if (hctx->ccid2hctx_ssthresh < 2)
+ hctx->ccid2hctx_ssthresh = 2;
+}
+
static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -496,7 +571,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
unsigned char veclen;
int offset = 0;
int done = 0;
- int loss = 0;
unsigned int maxincr = 0;
ccid2_hc_tx_check_sanity(hctx);
@@ -582,15 +656,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* run length
*/
while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
- const u8 state = (*vector &
- DCCP_ACKVEC_STATE_MASK) >> 6;
+ const u8 state = *vector &
+ DCCP_ACKVEC_STATE_MASK;
/* new packet received or marked */
if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
!seqp->ccid2s_acked) {
if (state ==
DCCP_ACKVEC_STATE_ECN_MARKED) {
- loss = 1;
+ ccid2_congestion_event(hctx,
+ seqp);
} else
ccid2_new_ack(sk, seqp,
&maxincr);
@@ -642,7 +717,13 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
/* check for lost packets */
while (1) {
if (!seqp->ccid2s_acked) {
- loss = 1;
+ ccid2_pr_debug("Packet lost: %llu\n",
+ seqp->ccid2s_seq);
+ /* XXX need to traverse from tail -> head in
+ * order to detect multiple congestion events in
+ * one ack vector.
+ */
+ ccid2_congestion_event(hctx, seqp);
ccid2_hc_tx_dec_pipe(sk);
}
if (seqp == hctx->ccid2hctx_seqt)
@@ -661,53 +742,33 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
}
- if (loss) {
- /* XXX do bit shifts guarantee a 0 as the new bit? */
- ccid2_change_cwnd(sk, hctx->ccid2hctx_cwnd >> 1);
- hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd;
- if (hctx->ccid2hctx_ssthresh < 2)
- hctx->ccid2hctx_ssthresh = 2;
- }
-
ccid2_hc_tx_check_sanity(hctx);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
{
struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid);
- int seqcount = ccid2_seq_len;
- int i;
- /* XXX init variables with proper values */
- hctx->ccid2hctx_cwnd = 1;
- hctx->ccid2hctx_ssthresh = 10;
+ ccid2_change_cwnd(hctx, 1);
+ /* Initialize ssthresh to infinity. This means that we will exit the
+ * initial slow-start after the first packet loss. This is what we
+ * want.
+ */
+ hctx->ccid2hctx_ssthresh = ~0;
hctx->ccid2hctx_numdupack = 3;
+ hctx->ccid2hctx_seqbufc = 0;
/* XXX init ~ to window size... */
- hctx->ccid2hctx_seqbuf = kmalloc(sizeof(*hctx->ccid2hctx_seqbuf) *
- seqcount, gfp_any());
- if (hctx->ccid2hctx_seqbuf == NULL)
+ if (ccid2_hc_tx_alloc_seq(hctx, CCID2_SEQBUF_LEN, GFP_ATOMIC) != 0)
return -ENOMEM;
- for (i = 0; i < (seqcount - 1); i++) {
- hctx->ccid2hctx_seqbuf[i].ccid2s_next =
- &hctx->ccid2hctx_seqbuf[i + 1];
- hctx->ccid2hctx_seqbuf[i + 1].ccid2s_prev =
- &hctx->ccid2hctx_seqbuf[i];
- }
- hctx->ccid2hctx_seqbuf[seqcount - 1].ccid2s_next =
- hctx->ccid2hctx_seqbuf;
- hctx->ccid2hctx_seqbuf->ccid2s_prev =
- &hctx->ccid2hctx_seqbuf[seqcount - 1];
-
- hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqbuf;
- hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh;
hctx->ccid2hctx_sent = 0;
hctx->ccid2hctx_rto = 3 * HZ;
- hctx->ccid2hctx_srtt = -1;
+ ccid2_change_srtt(hctx, -1);
hctx->ccid2hctx_rttvar = -1;
hctx->ccid2hctx_lastrtt = 0;
hctx->ccid2hctx_rpdupack = -1;
+ hctx->ccid2hctx_last_cong = jiffies;
hctx->ccid2hctx_rtotimer.function = &ccid2_hc_tx_rto_expire;
hctx->ccid2hctx_rtotimer.data = (unsigned long)sk;
@@ -720,10 +781,13 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
static void ccid2_hc_tx_exit(struct sock *sk)
{
struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ int i;
ccid2_hc_tx_kill_rto_timer(sk);
- kfree(hctx->ccid2hctx_seqbuf);
- hctx->ccid2hctx_seqbuf = NULL;
+
+ for (i = 0; i < hctx->ccid2hctx_seqbufc; i++)
+ kfree(hctx->ccid2hctx_seqbuf[i]);
+ hctx->ccid2hctx_seqbufc = 0;
}
static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index 451a87464fa5..5b2ef4acb300 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -35,6 +35,9 @@ struct ccid2_seq {
struct ccid2_seq *ccid2s_next;
};
+#define CCID2_SEQBUF_LEN 256
+#define CCID2_SEQBUF_MAX 128
+
/** struct ccid2_hc_tx_sock - CCID2 TX half connection
*
* @ccid2hctx_ssacks - ACKs recv in slow start
@@ -50,10 +53,11 @@ struct ccid2_hc_tx_sock {
int ccid2hctx_cwnd;
int ccid2hctx_ssacks;
int ccid2hctx_acks;
- int ccid2hctx_ssthresh;
+ unsigned int ccid2hctx_ssthresh;
int ccid2hctx_pipe;
int ccid2hctx_numdupack;
- struct ccid2_seq *ccid2hctx_seqbuf;
+ struct ccid2_seq *ccid2hctx_seqbuf[CCID2_SEQBUF_MAX];
+ int ccid2hctx_seqbufc;
struct ccid2_seq *ccid2hctx_seqh;
struct ccid2_seq *ccid2hctx_seqt;
long ccid2hctx_rto;
@@ -67,6 +71,7 @@ struct ccid2_hc_tx_sock {
u64 ccid2hctx_rpseq;
int ccid2hctx_rpdupack;
int ccid2hctx_sendwait;
+ unsigned long ccid2hctx_last_cong;
};
struct ccid2_hc_rx_sock {
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 090bc39e8199..195aa9566228 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -900,7 +900,7 @@ 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;
+ struct dccp_li_hist_entry *head;
u64 seq_temp;
if (list_empty(&hcrx->ccid3hcrx_li_hist)) {
@@ -908,15 +908,15 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
&hcrx->ccid3hcrx_li_hist, seq_loss, win_loss))
return;
- next = (struct dccp_li_hist_entry *)
- hcrx->ccid3hcrx_li_hist.next;
- next->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
+ head = list_entry(hcrx->ccid3hcrx_li_hist.next,
+ struct dccp_li_hist_entry, dccplih_node);
+ head->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;
+ head = list_entry(hcrx->ccid3hcrx_li_hist.next,
+ struct dccp_li_hist_entry, dccplih_node);
/* 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 */
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index a5c5475724c0..0a21be437ed3 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -130,7 +130,7 @@ extern void dccp_send_delayed_ack(struct sock *sk);
extern void dccp_send_sync(struct sock *sk, const u64 seq,
const enum dccp_pkt_type pkt_type);
-extern int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo);
+extern void dccp_write_xmit(struct sock *sk, int block);
extern void dccp_write_space(struct sock *sk);
extern void dccp_init_xmit_timers(struct sock *sk);
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index b44c45504fb6..cee553d416ca 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -27,5 +27,10 @@ extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
extern int dccp_feat_init(struct dccp_minisock *dmsk);
extern int dccp_feat_default_sequence_window;
+extern int dccp_feat_default_rx_ccid;
+extern int dccp_feat_default_tx_ccid;
+extern int dccp_feat_default_ack_ratio;
+extern int dccp_feat_default_send_ack_vector;
+extern int dccp_feat_default_send_ndp_count;
#endif /* _DCCP_FEAT_H */
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 7f56f7e8f571..9a1a76a7dc41 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -501,6 +501,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
dccp_openreq_init(req, &dp, skb);
+ if (security_inet_conn_request(sk, skb, req))
+ goto drop_and_free;
+
ireq = inet_rsk(req);
ireq->loc_addr = daddr;
ireq->rmt_addr = saddr;
@@ -605,10 +608,10 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
if (req != NULL)
return dccp_check_req(sk, skb, req, prev);
- nsk = __inet_lookup_established(&dccp_hashinfo,
- iph->saddr, dh->dccph_sport,
- iph->daddr, ntohs(dh->dccph_dport),
- inet_iif(skb));
+ nsk = inet_lookup_established(&dccp_hashinfo,
+ iph->saddr, dh->dccph_sport,
+ iph->daddr, dh->dccph_dport,
+ inet_iif(skb));
if (nsk != NULL) {
if (nsk->sk_state != DCCP_TIME_WAIT) {
bh_lock_sock(nsk);
@@ -678,6 +681,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
}
};
+ security_skb_classify_flow(skb, &fl);
if (ip_route_output_flow(&rt, &fl, sk, 0)) {
IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
return NULL;
@@ -921,7 +925,7 @@ static int dccp_v4_rcv(struct sk_buff *skb)
* Look up flow ID in table and get corresponding socket */
sk = __inet_lookup(&dccp_hashinfo,
skb->nh.iph->saddr, dh->dccph_sport,
- skb->nh.iph->daddr, ntohs(dh->dccph_dport),
+ skb->nh.iph->daddr, dh->dccph_dport,
inet_iif(skb));
/*
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 610c722ac27f..7a47399cf31f 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -201,6 +201,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = usin->sin6_port;
fl.fl_ip_sport = inet->sport;
+ security_sk_classify_flow(sk, &fl);
if (np->opt != NULL && np->opt->srcrt != NULL) {
const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
@@ -230,7 +231,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&np->saddr, saddr);
inet->rcv_saddr = LOOPBACK4_IPV6;
- __ip6_dst_store(sk, dst, NULL);
+ __ip6_dst_store(sk, dst, NULL, NULL);
icsk->icsk_ext_hdr_len = 0;
if (np->opt != NULL)
@@ -322,6 +323,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
+ security_sk_classify_flow(sk, &fl);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err) {
@@ -422,6 +424,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
fl.oif = ireq6->iif;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
+ security_req_classify_flow(req, &fl);
if (dst == NULL) {
opt = np->opt;
@@ -566,6 +569,7 @@ static void dccp_v6_ctl_send_reset(struct sk_buff *rxskb)
fl.oif = inet6_iif(rxskb);
fl.fl_ip_dport = dh->dccph_dport;
fl.fl_ip_sport = dh->dccph_sport;
+ security_skb_classify_flow(rxskb, &fl);
/* sk = NULL, but it is safe for now. RST socket required. */
if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
@@ -622,6 +626,7 @@ static void dccp_v6_reqsk_send_ack(struct sk_buff *rxskb,
fl.oif = inet6_iif(rxskb);
fl.fl_ip_dport = dh->dccph_dport;
fl.fl_ip_sport = dh->dccph_sport;
+ security_req_classify_flow(req, &fl);
if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) {
if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) {
@@ -704,6 +709,9 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
dccp_openreq_init(req, &dp, skb);
+ if (security_inet_conn_request(sk, skb, req))
+ goto drop_and_free;
+
ireq6 = inet6_rsk(req);
ireq = inet_rsk(req);
ipv6_addr_copy(&ireq6->rmt_addr, &skb->nh.ipv6h->saddr);
@@ -842,6 +850,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
+ security_sk_classify_flow(sk, &fl);
if (ip6_dst_lookup(sk, &dst, &fl))
goto out;
@@ -863,7 +872,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
* comment in that function for the gory details. -acme
*/
- __ip6_dst_store(newsk, dst, NULL);
+ __ip6_dst_store(newsk, dst, NULL, NULL);
newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
NETIF_F_TSO);
newdp6 = (struct dccp6_sock *)newsk;
@@ -961,7 +970,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
if (skb->protocol == htons(ETH_P_IP))
return dccp_v4_do_rcv(sk, skb);
- if (sk_filter(sk, skb, 0))
+ if (sk_filter(sk, skb))
goto discard;
/*
diff --git a/net/dccp/output.c b/net/dccp/output.c
index 58669beee132..7102e3aed4ca 100644
--- a/net/dccp/output.c
+++ b/net/dccp/output.c
@@ -198,7 +198,7 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
while (1) {
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
- if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
+ if (sk->sk_err)
goto do_error;
if (!*timeo)
goto do_nonblock;
@@ -234,37 +234,72 @@ do_interrupted:
goto out;
}
-int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo)
+static void dccp_write_xmit_timer(unsigned long data) {
+ struct sock *sk = (struct sock *)data;
+ struct dccp_sock *dp = dccp_sk(sk);
+
+ bh_lock_sock(sk);
+ if (sock_owned_by_user(sk))
+ sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1);
+ else
+ dccp_write_xmit(sk, 0);
+ bh_unlock_sock(sk);
+ sock_put(sk);
+}
+
+void dccp_write_xmit(struct sock *sk, int block)
{
- const struct dccp_sock *dp = dccp_sk(sk);
- int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
+ struct dccp_sock *dp = dccp_sk(sk);
+ struct sk_buff *skb;
+ long timeo = 30000; /* If a packet is taking longer than 2 secs
+ we have other issues */
+
+ while ((skb = skb_peek(&sk->sk_write_queue))) {
+ int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
skb->len);
- if (err > 0)
- err = dccp_wait_for_ccid(sk, skb, timeo);
+ if (err > 0) {
+ if (!block) {
+ sk_reset_timer(sk, &dp->dccps_xmit_timer,
+ msecs_to_jiffies(err)+jiffies);
+ break;
+ } else
+ err = dccp_wait_for_ccid(sk, skb, &timeo);
+ if (err) {
+ printk(KERN_CRIT "%s:err at dccp_wait_for_ccid"
+ " %d\n", __FUNCTION__, err);
+ dump_stack();
+ }
+ }
- if (err == 0) {
- struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
- const int len = skb->len;
+ skb_dequeue(&sk->sk_write_queue);
+ if (err == 0) {
+ struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
+ const int len = skb->len;
- if (sk->sk_state == DCCP_PARTOPEN) {
- /* See 8.1.5. Handshake Completion */
- inet_csk_schedule_ack(sk);
- inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
+ if (sk->sk_state == DCCP_PARTOPEN) {
+ /* See 8.1.5. Handshake Completion */
+ inet_csk_schedule_ack(sk);
+ inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
inet_csk(sk)->icsk_rto,
DCCP_RTO_MAX);
- dcb->dccpd_type = DCCP_PKT_DATAACK;
- } else if (dccp_ack_pending(sk))
- dcb->dccpd_type = DCCP_PKT_DATAACK;
- else
- dcb->dccpd_type = DCCP_PKT_DATA;
-
- err = dccp_transmit_skb(sk, skb);
- ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
- } else
- kfree_skb(skb);
-
- return err;
+ dcb->dccpd_type = DCCP_PKT_DATAACK;
+ } else if (dccp_ack_pending(sk))
+ dcb->dccpd_type = DCCP_PKT_DATAACK;
+ else
+ dcb->dccpd_type = DCCP_PKT_DATA;
+
+ err = dccp_transmit_skb(sk, skb);
+ ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
+ if (err) {
+ printk(KERN_CRIT "%s:err from "
+ "ccid_hc_tx_packet_sent %d\n",
+ __FUNCTION__, err);
+ dump_stack();
+ }
+ } else
+ kfree(skb);
+ }
}
int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
@@ -426,6 +461,9 @@ static inline void dccp_connect_init(struct sock *sk)
dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
icsk->icsk_retransmits = 0;
+ init_timer(&dp->dccps_xmit_timer);
+ dp->dccps_xmit_timer.data = (unsigned long)sk;
+ dp->dccps_xmit_timer.function = dccp_write_xmit_timer;
}
int dccp_connect(struct sock *sk)
@@ -560,8 +598,10 @@ void dccp_send_close(struct sock *sk, const int active)
DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
if (active) {
+ dccp_write_xmit(sk, 1);
dccp_skb_entail(sk, skb);
dccp_transmit_skb(sk, skb_clone(skb, prio));
+ /* FIXME do we need a retransmit timer here? */
} else
dccp_transmit_skb(sk, skb);
}
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 6f14bb5a28d4..962df0ea31aa 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -662,17 +662,8 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (rc != 0)
goto out_discard;
- rc = dccp_write_xmit(sk, skb, &timeo);
- /*
- * XXX we don't use sk_write_queue, so just discard the packet.
- * Current plan however is to _use_ sk_write_queue with
- * an algorith similar to tcp_sendmsg, where the main difference
- * is that in DCCP we have to respect packet boundaries, so
- * no coalescing of skbs.
- *
- * This bug was _quickly_ found & fixed by just looking at an OSTRA
- * generated callgraph 8) -acme
- */
+ skb_queue_tail(&sk->sk_write_queue, skb);
+ dccp_write_xmit(sk,0);
out_release:
release_sock(sk);
return rc ? : len;
@@ -846,6 +837,7 @@ static int dccp_close_state(struct sock *sk)
void dccp_close(struct sock *sk, long timeout)
{
+ struct dccp_sock *dp = dccp_sk(sk);
struct sk_buff *skb;
int state;
@@ -862,6 +854,8 @@ void dccp_close(struct sock *sk, long timeout)
goto adjudge_to_death;
}
+ sk_stop_timer(sk, &dp->dccps_xmit_timer);
+
/*
* We need to flush the recv. buffs. We do this only on the
* descriptor close, not protocol-sourced closes, because the
diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c
index c1ba9451bc3d..38bc157876f3 100644
--- a/net/dccp/sysctl.c
+++ b/net/dccp/sysctl.c
@@ -11,18 +11,12 @@
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include "feat.h"
#ifndef CONFIG_SYSCTL
#error This file should not be compiled without CONFIG_SYSCTL defined
#endif
-extern int dccp_feat_default_sequence_window;
-extern int dccp_feat_default_rx_ccid;
-extern int dccp_feat_default_tx_ccid;
-extern int dccp_feat_default_ack_ratio;
-extern int dccp_feat_default_send_ack_vector;
-extern int dccp_feat_default_send_ndp_count;
-
static struct ctl_table dccp_default_table[] = {
{
.ctl_name = NET_DCCP_DEFAULT_SEQ_WINDOW,