Commit 6c1b6c6b authored by David S. Miller's avatar David S. Miller
parents fe822240 7e87fe84
...@@ -462,6 +462,7 @@ struct dccp_ackvec; ...@@ -462,6 +462,7 @@ struct dccp_ackvec;
* @dccps_hc_rx_insert_options - receiver wants to add options when acking * @dccps_hc_rx_insert_options - receiver wants to add options when acking
* @dccps_hc_tx_insert_options - sender wants to add options when sending * @dccps_hc_tx_insert_options - sender wants to add options when sending
* @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3) * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3)
* @dccps_sync_scheduled - flag which signals "send out-of-band message soon"
* @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets
* @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing)
* @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs)
...@@ -503,6 +504,7 @@ struct dccp_sock { ...@@ -503,6 +504,7 @@ struct dccp_sock {
__u8 dccps_hc_rx_insert_options:1; __u8 dccps_hc_rx_insert_options:1;
__u8 dccps_hc_tx_insert_options:1; __u8 dccps_hc_tx_insert_options:1;
__u8 dccps_server_timewait:1; __u8 dccps_server_timewait:1;
__u8 dccps_sync_scheduled:1;
struct tasklet_struct dccps_xmitlet; struct tasklet_struct dccps_xmitlet;
struct timer_list dccps_xmit_timer; struct timer_list dccps_xmit_timer;
}; };
......
...@@ -9,18 +9,10 @@ ...@@ -9,18 +9,10 @@
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License; * Free Software Foundation; version 2 of the License;
*/ */
#include "ackvec.h"
#include "dccp.h" #include "dccp.h"
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/sock.h>
static struct kmem_cache *dccp_ackvec_slab; static struct kmem_cache *dccp_ackvec_slab;
static struct kmem_cache *dccp_ackvec_record_slab; static struct kmem_cache *dccp_ackvec_record_slab;
...@@ -92,6 +84,24 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum) ...@@ -92,6 +84,24 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum)
return 0; return 0;
} }
static struct dccp_ackvec_record *dccp_ackvec_lookup(struct list_head *av_list,
const u64 ackno)
{
struct dccp_ackvec_record *avr;
/*
* Exploit that records are inserted in descending order of sequence
* number, start with the oldest record first. If @ackno is `before'
* the earliest ack_ackno, the packet is too old to be considered.
*/
list_for_each_entry_reverse(avr, av_list, avr_node) {
if (avr->avr_ack_seqno == ackno)
return avr;
if (before48(ackno, avr->avr_ack_seqno))
break;
}
return NULL;
}
/* /*
* Buffer index and length computation using modulo-buffersize arithmetic. * Buffer index and length computation using modulo-buffersize arithmetic.
* Note that, as pointers move from right to left, head is `before' tail. * Note that, as pointers move from right to left, head is `before' tail.
...@@ -113,248 +123,253 @@ u16 dccp_ackvec_buflen(const struct dccp_ackvec *av) ...@@ -113,248 +123,253 @@ u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
return __ackvec_idx_sub(av->av_buf_tail, av->av_buf_head); return __ackvec_idx_sub(av->av_buf_tail, av->av_buf_head);
} }
/* /**
* If several packets are missing, the HC-Receiver may prefer to enter multiple * dccp_ackvec_update_old - Update previous state as per RFC 4340, 11.4.1
* bytes with run length 0, rather than a single byte with a larger run length; * @av: non-empty buffer to update
* this simplifies table updates if one of the missing packets arrives. * @distance: negative or zero distance of @seqno from buf_ackno downward
* @seqno: the (old) sequence number whose record is to be updated
* @state: state in which packet carrying @seqno was received
*/ */
static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, static void dccp_ackvec_update_old(struct dccp_ackvec *av, s64 distance,
const unsigned int packets, u64 seqno, enum dccp_ackvec_states state)
const unsigned char state)
{ {
long gap; u16 ptr = av->av_buf_head;
long new_head;
if (av->av_vec_len + packets > DCCPAV_MAX_ACKVEC_LEN) BUG_ON(distance > 0);
return -ENOBUFS; if (unlikely(dccp_ackvec_is_empty(av)))
return;
gap = packets - 1; do {
new_head = av->av_buf_head - packets; u8 runlen = dccp_ackvec_runlen(av->av_buf + ptr);
if (new_head < 0) { if (distance + runlen >= 0) {
if (gap > 0) { /*
memset(av->av_buf, DCCPAV_NOT_RECEIVED, * Only update the state if packet has not been received
gap + new_head + 1); * yet. This is OK as per the second table in RFC 4340,
gap = -new_head; * 11.4.1; i.e. here we are using the following table:
* RECEIVED
* 0 1 3
* S +---+---+---+
* T 0 | 0 | 0 | 0 |
* O +---+---+---+
* R 1 | 1 | 1 | 1 |
* E +---+---+---+
* D 3 | 0 | 1 | 3 |
* +---+---+---+
* The "Not Received" state was set by reserve_seats().
*/
if (av->av_buf[ptr] == DCCPAV_NOT_RECEIVED)
av->av_buf[ptr] = state;
else
dccp_pr_debug("Not changing %llu state to %u\n",
(unsigned long long)seqno, state);
break;
} }
new_head += DCCPAV_MAX_ACKVEC_LEN;
}
av->av_buf_head = new_head; distance += runlen + 1;
ptr = __ackvec_idx_add(ptr, 1);
if (gap > 0) } while (ptr != av->av_buf_tail);
memset(av->av_buf + av->av_buf_head + 1, }
DCCPAV_NOT_RECEIVED, gap);
av->av_buf[av->av_buf_head] = state; /* Mark @num entries after buf_head as "Not yet received". */
av->av_vec_len += packets; static void dccp_ackvec_reserve_seats(struct dccp_ackvec *av, u16 num)
return 0; {
u16 start = __ackvec_idx_add(av->av_buf_head, 1),
len = DCCPAV_MAX_ACKVEC_LEN - start;
/* check for buffer wrap-around */
if (num > len) {
memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, len);
start = 0;
num -= len;
}
if (num)
memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, num);
} }
/* /**
* Implements the RFC 4340, Appendix A * dccp_ackvec_add_new - Record one or more new entries in Ack Vector buffer
* @av: container of buffer to update (can be empty or non-empty)
* @num_packets: number of packets to register (must be >= 1)
* @seqno: sequence number of the first packet in @num_packets
* @state: state in which packet carrying @seqno was received
*/ */
int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, static void dccp_ackvec_add_new(struct dccp_ackvec *av, u32 num_packets,
const u64 ackno, const u8 state) u64 seqno, enum dccp_ackvec_states state)
{ {
u8 *cur_head = av->av_buf + av->av_buf_head, u32 num_cells = num_packets;
*buf_end = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
/*
* Check at the right places if the buffer is full, if it is, tell the
* caller to start dropping packets till the HC-Sender acks our ACK
* vectors, when we will free up space in av_buf.
*
* We may well decide to do buffer compression, etc, but for now lets
* just drop.
*
* From Appendix A.1.1 (`New Packets'):
*
* Of course, the circular buffer may overflow, either when the
* HC-Sender is sending data at a very high rate, when the
* HC-Receiver's acknowledgements are not reaching the HC-Sender,
* or when the HC-Sender is forgetting to acknowledge those acks
* (so the HC-Receiver is unable to clean up old state). In this
* case, the HC-Receiver should either compress the buffer (by
* increasing run lengths when possible), transfer its state to
* a larger buffer, or, as a last resort, drop all received
* packets, without processing them whatsoever, until its buffer
* shrinks again.
*/
/* See if this is the first ackno being inserted */ if (num_packets > DCCPAV_BURST_THRESH) {
if (av->av_vec_len == 0) { u32 lost_packets = num_packets - 1;
*cur_head = state;
av->av_vec_len = 1;
} else if (after48(ackno, av->av_buf_ackno)) {
const u64 delta = dccp_delta_seqno(av->av_buf_ackno, ackno);
DCCP_WARN("Warning: large burst loss (%u)\n", lost_packets);
/* /*
* Look if the state of this packet is the same as the * We received 1 packet and have a loss of size "num_packets-1"
* previous ackno and if so if we can bump the head len. * which we squeeze into num_cells-1 rather than reserving an
* entire byte for each lost packet.
* The reason is that the vector grows in O(burst_length); when
* it grows too large there will no room left for the payload.
* This is a trade-off: if a few packets out of the burst show
* up later, their state will not be changed; it is simply too
* costly to reshuffle/reallocate/copy the buffer each time.
* Should such problems persist, we will need to switch to a
* different underlying data structure.
*/ */
if (delta == 1 && dccp_ackvec_state(cur_head) == state && for (num_packets = num_cells = 1; lost_packets; ++num_cells) {
dccp_ackvec_runlen(cur_head) < DCCPAV_MAX_RUNLEN) u8 len = min(lost_packets, (u32)DCCPAV_MAX_RUNLEN);
*cur_head += 1;
else if (dccp_ackvec_set_buf_head_state(av, delta, state))
return -ENOBUFS;
} else {
/*
* A.1.2. Old Packets
*
* When a packet with Sequence Number S <= buf_ackno
* arrives, the HC-Receiver will scan the table for
* the byte corresponding to S. (Indexing structures
* could reduce the complexity of this scan.)
*/
u64 delta = dccp_delta_seqno(ackno, av->av_buf_ackno);
while (1) { av->av_buf_head = __ackvec_idx_sub(av->av_buf_head, 1);
const u8 len = dccp_ackvec_runlen(cur_head); av->av_buf[av->av_buf_head] = DCCPAV_NOT_RECEIVED | len;
/*
* valid packets not yet in av_buf have a reserved lost_packets -= len;
* entry, with a len equal to 0.
*/
if (*cur_head == DCCPAV_NOT_RECEIVED && delta == 0) {
dccp_pr_debug("Found %llu reserved seat!\n",
(unsigned long long)ackno);
*cur_head = state;
goto out;
}
/* len == 0 means one packet */
if (delta < len + 1)
goto out_duplicate;
delta -= len + 1;
if (++cur_head == buf_end)
cur_head = av->av_buf;
} }
} }
av->av_buf_ackno = ackno; if (num_cells + dccp_ackvec_buflen(av) >= DCCPAV_MAX_ACKVEC_LEN) {
out: DCCP_CRIT("Ack Vector buffer overflow: dropping old entries\n");
return 0; av->av_overflow = true;
}
av->av_buf_head = __ackvec_idx_sub(av->av_buf_head, num_packets);
if (av->av_overflow)
av->av_buf_tail = av->av_buf_head;
av->av_buf[av->av_buf_head] = state;
av->av_buf_ackno = seqno;
out_duplicate: if (num_packets > 1)
/* Duplicate packet */ dccp_ackvec_reserve_seats(av, num_packets - 1);
dccp_pr_debug("Received a dup or already considered lost "
"packet: %llu\n", (unsigned long long)ackno);
return -EILSEQ;
} }
static void dccp_ackvec_throw_record(struct dccp_ackvec *av, /**
struct dccp_ackvec_record *avr) * dccp_ackvec_input - Register incoming packet in the buffer
*/
void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb)
{ {
struct dccp_ackvec_record *next; u64 seqno = DCCP_SKB_CB(skb)->dccpd_seq;
enum dccp_ackvec_states state = DCCPAV_RECEIVED;
/* sort out vector length */ if (dccp_ackvec_is_empty(av)) {
if (av->av_buf_head <= avr->avr_ack_ptr) dccp_ackvec_add_new(av, 1, seqno, state);
av->av_vec_len = avr->avr_ack_ptr - av->av_buf_head; av->av_tail_ackno = seqno;
else
av->av_vec_len = DCCPAV_MAX_ACKVEC_LEN - 1 -
av->av_buf_head + avr->avr_ack_ptr;
/* free records */ } else {
list_for_each_entry_safe_from(avr, next, &av->av_records, avr_node) { s64 num_packets = dccp_delta_seqno(av->av_buf_ackno, seqno);
list_del(&avr->avr_node); u8 *current_head = av->av_buf + av->av_buf_head;
kmem_cache_free(dccp_ackvec_record_slab, avr);
}
}
void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, if (num_packets == 1 &&
const u64 ackno) dccp_ackvec_state(current_head) == state &&
{ dccp_ackvec_runlen(current_head) < DCCPAV_MAX_RUNLEN) {
struct dccp_ackvec_record *avr;
/* *current_head += 1;
* If we traverse backwards, it should be faster when we have large av->av_buf_ackno = seqno;
* windows. We will be receiving ACKs for stuff we sent a while back
* -sorbo. } else if (num_packets > 0) {
*/ dccp_ackvec_add_new(av, num_packets, seqno, state);
list_for_each_entry_reverse(avr, &av->av_records, avr_node) { } else {
if (ackno == avr->avr_ack_seqno) { dccp_ackvec_update_old(av, num_packets, seqno, state);
dccp_pr_debug("%s ACK packet 0, len=%d, ack_seqno=%llu, " }
"ack_ackno=%llu, ACKED!\n",
dccp_role(sk), avr->avr_ack_runlen,
(unsigned long long)avr->avr_ack_seqno,
(unsigned long long)avr->avr_ack_ackno);
dccp_ackvec_throw_record(av, avr);
break;
} else if (avr->avr_ack_seqno > ackno)
break; /* old news */
} }
} }
static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, /**
struct sock *sk, u64 *ackno, * dccp_ackvec_clear_state - Perform house-keeping / garbage-collection
const unsigned char len, * This routine is called when the peer acknowledges the receipt of Ack Vectors
const unsigned char *vector) * up to and including @ackno. While based on on section A.3 of RFC 4340, here
{ * are additional precautions to prevent corrupted buffer state. In particular,
unsigned char i; * we use tail_ackno to identify outdated records; it always marks the earliest
struct dccp_ackvec_record *avr; * packet of group (2) in 11.4.2.
*/
void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno)
{
struct dccp_ackvec_record *avr, *next;
u8 runlen_now, eff_runlen;
s64 delta;
/* Check if we actually sent an ACK vector */ avr = dccp_ackvec_lookup(&av->av_records, ackno);
if (list_empty(&av->av_records)) if (avr == NULL)
return; return;
/*
* Deal with outdated acknowledgments: this arises when e.g. there are
* several old records and the acks from the peer come in slowly. In
* that case we may still have records that pre-date tail_ackno.
*/
delta = dccp_delta_seqno(av->av_tail_ackno, avr->avr_ack_ackno);
if (delta < 0)
goto free_records;
/*
* Deal with overlapping Ack Vectors: don't subtract more than the
* number of packets between tail_ackno and ack_ackno.
*/
eff_runlen = delta < avr->avr_ack_runlen ? delta : avr->avr_ack_runlen;
i = len; runlen_now = dccp_ackvec_runlen(av->av_buf + avr->avr_ack_ptr);
/* /*
* XXX * The run length of Ack Vector cells does not decrease over time. If
* I think it might be more efficient to work backwards. See comment on * the run length is the same as at the time the Ack Vector was sent, we
* rcv_ackno. -sorbo. * free the ack_ptr cell. That cell can however not be freed if the run
* length has increased: in this case we need to move the tail pointer
* backwards (towards higher indices), to its next-oldest neighbour.
*/ */
avr = list_entry(av->av_records.next, struct dccp_ackvec_record, avr_node); if (runlen_now > eff_runlen) {
while (i--) {
const u8 rl = dccp_ackvec_runlen(vector);
u64 ackno_end_rl;
dccp_set_seqno(&ackno_end_rl, *ackno - rl); av->av_buf[avr->avr_ack_ptr] -= eff_runlen + 1;
av->av_buf_tail = __ackvec_idx_add(avr->avr_ack_ptr, 1);
/* This move may not have cleared the overflow flag. */
if (av->av_overflow)
av->av_overflow = (av->av_buf_head == av->av_buf_tail);
} else {
av->av_buf_tail = avr->avr_ack_ptr;
/* /*
* If our AVR sequence number is greater than the ack, go * We have made sure that avr points to a valid cell within the
* forward in the AVR list until it is not so. * buffer. This cell is either older than head, or equals head
* (empty buffer): in both cases we no longer have any overflow.
*/ */
list_for_each_entry_from(avr, &av->av_records, avr_node) { av->av_overflow = 0;
if (!after48(avr->avr_ack_seqno, *ackno)) }
goto found;
}
/* End of the av_records list, not found, exit */
break;
found:
if (between48(avr->avr_ack_seqno, ackno_end_rl, *ackno)) {
if (dccp_ackvec_state(vector) != DCCPAV_NOT_RECEIVED) {
dccp_pr_debug("%s ACK vector 0, len=%d, "
"ack_seqno=%llu, ack_ackno=%llu, "
"ACKED!\n",
dccp_role(sk), len,
(unsigned long long)
avr->avr_ack_seqno,
(unsigned long long)
avr->avr_ack_ackno);
dccp_ackvec_throw_record(av, avr);
break;
}
/*
* If it wasn't received, continue scanning... we might
* find another one.
*/
}
dccp_set_seqno(ackno, ackno_end_rl - 1); /*
++vector; * The peer has acknowledged up to and including ack_ackno. Hence the
* first packet in group (2) of 11.4.2 is the successor of ack_ackno.
*/
av->av_tail_ackno = ADD48(avr->avr_ack_ackno, 1);
free_records:
list_for_each_entry_safe_from(avr, next, &av->av_records, avr_node) {
list_del(&avr->avr_node);
kmem_cache_free(dccp_ackvec_record_slab, avr);
} }
} }
int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, /*
u64 *ackno, const u8 opt, const u8 *value, const u8 len) * Routines to keep track of Ack Vectors received in an skb
*/
int dccp_ackvec_parsed_add(struct list_head *head, u8 *vec, u8 len, u8 nonce)
{ {
if (len > DCCP_SINGLE_OPT_MAXLEN) struct dccp_ackvec_parsed *new = kmalloc(sizeof(*new), GFP_ATOMIC);
return -1;
if (new == NULL)
return -ENOBUFS;
new->vec = vec;
new->len = len;
new->nonce = nonce;
/* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */ list_add_tail(&new->node, head);
dccp_ackvec_check_rcv_ackvector(dccp_sk(sk)->dccps_hc_rx_ackvec, sk,
ackno, len, value);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_add);
void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks)
{
struct dccp_ackvec_parsed *cur, *next;
list_for_each_entry_safe(cur, next, parsed_chunks, node)
kfree(cur);
INIT_LIST_HEAD(parsed_chunks);
}
EXPORT_SYMBOL_GPL(dccp_ackvec_parsed_cleanup);
int __init dccp_ackvec_init(void) int __init dccp_ackvec_init(void)
{ {
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
/* Estimated minimum average Ack Vector length - used for updating MPS */ /* Estimated minimum average Ack Vector length - used for updating MPS */
#define DCCPAV_MIN_OPTLEN 16 #define DCCPAV_MIN_OPTLEN 16
/* Threshold for coping with large bursts of losses */
#define DCCPAV_BURST_THRESH (DCCPAV_MAX_ACKVEC_LEN / 8)
enum dccp_ackvec_states { enum dccp_ackvec_states {
DCCPAV_RECEIVED = 0x00, DCCPAV_RECEIVED = 0x00,
DCCPAV_ECN_MARKED = 0x40, DCCPAV_ECN_MARKED = 0x40,
...@@ -61,7 +64,6 @@ static inline u8 dccp_ackvec_state(const u8 *cell) ...@@ -61,7 +64,6 @@ static inline u8 dccp_ackvec_state(const u8 *cell)
* %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf * %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
* @av_overflow: if 1 then buf_head == buf_tail indicates buffer wraparound * @av_overflow: if 1 then buf_head == buf_tail indicates buffer wraparound
* @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously) * @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously)
* @av_veclen: length of the live portion of @av_buf
*/ */
struct dccp_ackvec { struct dccp_ackvec {
u8 av_buf[DCCPAV_MAX_ACKVEC_LEN]; u8 av_buf[DCCPAV_MAX_ACKVEC_LEN];
...@@ -72,7 +74,6 @@ struct dccp_ackvec { ...@@ -72,7 +74,6 @@ struct dccp_ackvec {
bool av_buf_nonce[DCCPAV_NUM_ACKVECS]; bool av_buf_nonce[DCCPAV_NUM_ACKVECS];
u8 av_overflow:1; u8 av_overflow:1;
struct list_head av_records; struct list_head av_records;
u16 av_vec_len;
}; };
/** struct dccp_ackvec_record - Records information about sent Ack Vectors /** struct dccp_ackvec_record - Records information about sent Ack Vectors
...@@ -98,29 +99,38 @@ struct dccp_ackvec_record { ...@@ -98,29 +99,38 @@ struct dccp_ackvec_record {
u8 avr_ack_nonce:1; u8 avr_ack_nonce:1;
}; };
struct sock;
struct sk_buff;
extern int dccp_ackvec_init(void); extern int dccp_ackvec_init(void);
extern void dccp_ackvec_exit(void); extern void dccp_ackvec_exit(void);
extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority); extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority);
extern void dccp_ackvec_free(struct dccp_ackvec *av); extern void dccp_ackvec_free(struct dccp_ackvec *av);
extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, extern void dccp_ackvec_input(struct dccp_ackvec *av, struct sk_buff *skb);
const u64 ackno, const u8 state);
extern void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av,
struct sock *sk, const u64 ackno);
extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
u64 *ackno, const u8 opt,
const u8 *value, const u8 len);
extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum); extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av); extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);
static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av) static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
{ {
return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail; return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail;
} }
/**
* struct dccp_ackvec_parsed - Record offsets of Ack Vectors in skb
* @vec: start of vector (offset into skb)
* @len: length of @vec
* @nonce: whether @vec had an ECN nonce of 0 or 1
* @node: FIFO - arranged in descending order of ack_ackno
* This structure is used by CCIDs to access Ack Vectors in a received skb.
*/
struct dccp_ackvec_parsed {
u8 *vec,
len,
nonce:1;
struct list_head node;
};
extern int dccp_ackvec_parsed_add(struct list_head *head,
u8 *vec, u8 len, u8 nonce);
extern void dccp_ackvec_parsed_cleanup(struct list_head *parsed_chunks);
#endif /* _ACKVEC_H */ #endif /* _ACKVEC_H */
...@@ -246,68 +246,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) ...@@ -246,68 +246,6 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len)
#endif #endif
} }
/* XXX Lame code duplication!
* returns -1 if none was found.
* else returns the next offset to use in the function call.
*/
static int ccid2_ackvector(struct sock *sk, struct sk_buff *skb, int offset,
unsigned char **vec, unsigned char *veclen)
{
const struct dccp_hdr *dh = dccp_hdr(skb);
unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
unsigned char *opt_ptr;
const unsigned char *opt_end = (unsigned char *)dh +
(dh->dccph_doff * 4);
unsigned char opt, len;
unsigned char *value;
BUG_ON(offset < 0);
options += offset;
opt_ptr = options;
if (opt_ptr >= opt_end)
return -1;
while (opt_ptr != opt_end) {
opt = *opt_ptr++;
len = 0;
value = NULL;
/* Check if this isn't a single byte option */
if (opt > DCCPO_MAX_RESERVED) {
if (opt_ptr == opt_end)
goto out_invalid_option;
len = *opt_ptr++;
if (len < 3)
goto out_invalid_option;
/*
* Remove the type and len fields, leaving
* just the value size
*/
len -= 2;
value = opt_ptr;
opt_ptr += len;
if (opt_ptr > opt_end)
goto out_invalid_option;
}
switch (opt) {
case DCCPO_ACK_VECTOR_0:
case DCCPO_ACK_VECTOR_1:
*vec = value;
*veclen = len;
return offset + (opt_ptr - options);
}
}
return -1;
out_invalid_option:
DCCP_BUG("Invalid option - this should not happen (previous parsing)!");
return -1;
}
/** /**
* ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm * ccid2_rtt_estimator - Sample RTT and compute RTO using RFC2988 algorithm
* This code is almost identical with TCP's tcp_rtt_estimator(), since * This code is almost identical with TCP's tcp_rtt_estimator(), since
...@@ -432,16 +370,28 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp) ...@@ -432,16 +370,28 @@ static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
ccid2_change_l_ack_ratio(sk, hc->tx_cwnd); ccid2_change_l_ack_ratio(sk, hc->tx_cwnd);
} }
static int ccid2_hc_tx_parse_options(struct sock *sk, u8 packet_type,
u8 option, u8 *optval, u8 optlen)
{
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
switch (option) {
case DCCPO_ACK_VECTOR_0:
case DCCPO_ACK_VECTOR_1:
return dccp_ackvec_parsed_add(&hc->tx_av_chunks, optval, optlen,
option - DCCPO_ACK_VECTOR_0);
}
return 0;
}
static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{ {
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); const bool sender_was_blocked = ccid2_cwnd_network_limited(hc);
struct dccp_ackvec_parsed *avp;
u64 ackno, seqno; u64 ackno, seqno;
struct ccid2_seq *seqp; struct ccid2_seq *seqp;
unsigned char *vector;
unsigned char veclen;
int offset = 0;
int done = 0; int done = 0;
unsigned int maxincr = 0; unsigned int maxincr = 0;
...@@ -475,17 +425,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -475,17 +425,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
} }
/* check forward path congestion */ /* check forward path congestion */
/* still didn't send out new data packets */ if (dccp_packet_without_ack(skb))
if (hc->tx_seqh == hc->tx_seqt)
return; return;
switch (DCCP_SKB_CB(skb)->dccpd_type) { /* still didn't send out new data packets */
case DCCP_PKT_ACK: if (hc->tx_seqh == hc->tx_seqt)
case DCCP_PKT_DATAACK: goto done;
break;
default:
return;
}
ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq; ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
if (after48(ackno, hc->tx_high_ack)) if (after48(ackno, hc->tx_high_ack))
...@@ -509,15 +454,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -509,15 +454,16 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2); maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2);
/* go through all ack vectors */ /* go through all ack vectors */
while ((offset = ccid2_ackvector(sk, skb, offset, list_for_each_entry(avp, &hc->tx_av_chunks, node) {
&vector, &veclen)) != -1) {
/* go through this ack vector */ /* go through this ack vector */
while (veclen--) { for (; avp->len--; avp->vec++) {
u64 ackno_end_rl = SUB48(ackno, dccp_ackvec_runlen(vector)); u64 ackno_end_rl = SUB48(ackno,
dccp_ackvec_runlen(avp->vec));
ccid2_pr_debug("ackvec start:%llu end:%llu\n", ccid2_pr_debug("ackvec %llu |%u,%u|\n",
(unsigned long long)ackno, (unsigned long long)ackno,
(unsigned long long)ackno_end_rl); dccp_ackvec_state(avp->vec) >> 6,
dccp_ackvec_runlen(avp->vec));
/* if the seqno we are analyzing is larger than the /* if the seqno we are analyzing is larger than the
* current ackno, then move towards the tail of our * current ackno, then move towards the tail of our
* seqnos. * seqnos.
...@@ -536,7 +482,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -536,7 +482,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* run length * run length
*/ */
while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) { while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
const u8 state = dccp_ackvec_state(vector); const u8 state = dccp_ackvec_state(avp->vec);
/* new packet received or marked */ /* new packet received or marked */
if (state != DCCPAV_NOT_RECEIVED && if (state != DCCPAV_NOT_RECEIVED &&
...@@ -563,7 +509,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -563,7 +509,6 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
break; break;
ackno = SUB48(ackno_end_rl, 1); ackno = SUB48(ackno_end_rl, 1);
vector++;
} }
if (done) if (done)
break; break;
...@@ -631,10 +576,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -631,10 +576,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
sk_stop_timer(sk, &hc->tx_rtotimer); sk_stop_timer(sk, &hc->tx_rtotimer);
else else
sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
done:
/* check if incoming Acks allow pending packets to be sent */ /* check if incoming Acks allow pending packets to be sent */
if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) if (sender_was_blocked && !ccid2_cwnd_network_limited(hc))
tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet); tasklet_schedule(&dccp_sk(sk)->dccps_xmitlet);
dccp_ackvec_parsed_cleanup(&hc->tx_av_chunks);
} }
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
...@@ -663,6 +609,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) ...@@ -663,6 +609,7 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
hc->tx_last_cong = ccid2_time_stamp; hc->tx_last_cong = ccid2_time_stamp;
setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
(unsigned long)sk); (unsigned long)sk);
INIT_LIST_HEAD(&hc->tx_av_chunks);
return 0; return 0;
} }
...@@ -696,16 +643,17 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) ...@@ -696,16 +643,17 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
} }
struct ccid_operations ccid2_ops = { struct ccid_operations ccid2_ops = {
.ccid_id = DCCPC_CCID2, .ccid_id = DCCPC_CCID2,
.ccid_name = "TCP-like", .ccid_name = "TCP-like",
.ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock), .ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock),
.ccid_hc_tx_init = ccid2_hc_tx_init, .ccid_hc_tx_init = ccid2_hc_tx_init,
.ccid_hc_tx_exit = ccid2_hc_tx_exit, .ccid_hc_tx_exit = ccid2_hc_tx_exit,
.ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet, .ccid_hc_tx_send_packet = ccid2_hc_tx_send_packet,
.ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent, .ccid_hc_tx_packet_sent = ccid2_hc_tx_packet_sent,
.ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv, .ccid_hc_tx_parse_options = ccid2_hc_tx_parse_options,
.ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock), .ccid_hc_tx_packet_recv = ccid2_hc_tx_packet_recv,
.ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv, .ccid_hc_rx_obj_size = sizeof(struct ccid2_hc_rx_sock),
.ccid_hc_rx_packet_recv = ccid2_hc_rx_packet_recv,
}; };
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG #ifdef CONFIG_IP_DCCP_CCID2_DEBUG
......
...@@ -55,6 +55,7 @@ struct ccid2_seq { ...@@ -55,6 +55,7 @@ struct ccid2_seq {
* @tx_rtt_seq: to decay RTTVAR at most once per flight * @tx_rtt_seq: to decay RTTVAR at most once per flight
* @tx_rpseq: last consecutive seqno * @tx_rpseq: last consecutive seqno
* @tx_rpdupack: dupacks since rpseq * @tx_rpdupack: dupacks since rpseq
* @tx_av_chunks: list of Ack Vectors received on current skb
*/ */
struct ccid2_hc_tx_sock { struct ccid2_hc_tx_sock {
u32 tx_cwnd; u32 tx_cwnd;
...@@ -79,6 +80,7 @@ struct ccid2_hc_tx_sock { ...@@ -79,6 +80,7 @@ struct ccid2_hc_tx_sock {
int tx_rpdupack; int tx_rpdupack;
u32 tx_last_cong; u32 tx_last_cong;
u64 tx_high_ack; u64 tx_high_ack;
struct list_head tx_av_chunks;
}; };
static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc) static inline bool ccid2_cwnd_network_limited(struct ccid2_hc_tx_sock *hc)
......
...@@ -160,13 +160,15 @@ static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb) ...@@ -160,13 +160,15 @@ static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb)
dccp_time_wait(sk, DCCP_TIME_WAIT, 0); dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
} }
static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) static void dccp_handle_ackvec_processing(struct sock *sk, struct sk_buff *skb)
{ {
struct dccp_sock *dp = dccp_sk(sk); struct dccp_ackvec *av = dccp_sk(sk)->dccps_hc_rx_ackvec;
if (dp->dccps_hc_rx_ackvec != NULL) if (av == NULL)
dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk, return;
DCCP_SKB_CB(skb)->dccpd_ack_seq); if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
dccp_ackvec_clear_state(av, DCCP_SKB_CB(skb)->dccpd_ack_seq);
dccp_ackvec_input(av, skb);
} }
static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb) static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb)
...@@ -365,21 +367,13 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb, ...@@ -365,21 +367,13 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
const struct dccp_hdr *dh, const unsigned len) const struct dccp_hdr *dh, const unsigned len)
{ {
struct dccp_sock *dp = dccp_sk(sk);
if (dccp_check_seqno(sk, skb)) if (dccp_check_seqno(sk, skb))
goto discard; goto discard;
if (dccp_parse_options(sk, NULL, skb)) if (dccp_parse_options(sk, NULL, skb))
return 1; return 1;
if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_handle_ackvec_processing(sk, skb);
dccp_event_ack_recv(sk, skb);
if (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
goto discard;
dccp_deliver_input_to_ccids(sk, skb); dccp_deliver_input_to_ccids(sk, skb);
return __dccp_rcv_established(sk, skb, dh, len); return __dccp_rcv_established(sk, skb, dh, len);
...@@ -631,14 +625,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, ...@@ -631,14 +625,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (dccp_parse_options(sk, NULL, skb)) if (dccp_parse_options(sk, NULL, skb))
return 1; return 1;
if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_handle_ackvec_processing(sk, skb);
dccp_event_ack_recv(sk, skb);
if (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
goto discard;
dccp_deliver_input_to_ccids(sk, skb); dccp_deliver_input_to_ccids(sk, skb);
} }
......
...@@ -54,7 +54,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, ...@@ -54,7 +54,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
const struct dccp_hdr *dh = dccp_hdr(skb); const struct dccp_hdr *dh = dccp_hdr(skb);
const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type; const u8 pkt_type = DCCP_SKB_CB(skb)->dccpd_type;
u64 ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb); unsigned char *options = (unsigned char *)dh + dccp_hdr_len(skb);
unsigned char *opt_ptr = options; unsigned char *opt_ptr = options;
const unsigned char *opt_end = (unsigned char *)dh + const unsigned char *opt_end = (unsigned char *)dh +
...@@ -129,14 +128,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, ...@@ -129,14 +128,6 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
if (rc) if (rc)
goto out_featneg_failed; goto out_featneg_failed;
break; break;
case DCCPO_ACK_VECTOR_0:
case DCCPO_ACK_VECTOR_1:
if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */
break;
if (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
goto out_invalid_option;
break;
case DCCPO_TIMESTAMP: case DCCPO_TIMESTAMP:
if (len != 4) if (len != 4)
goto out_invalid_option; goto out_invalid_option;
...@@ -226,6 +217,16 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, ...@@ -226,6 +217,16 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
pkt_type, opt, value, len)) pkt_type, opt, value, len))
goto out_invalid_option; goto out_invalid_option;
break; break;
case DCCPO_ACK_VECTOR_0:
case DCCPO_ACK_VECTOR_1:
if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */
break;
/*
* Ack vectors are processed by the TX CCID if it is
* interested. The RX CCID need not parse Ack Vectors,
* since it is only interested in clearing old state.
* Fall through.
*/
case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC: case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC:
if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk, if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
pkt_type, opt, value, len)) pkt_type, opt, value, len))
...@@ -429,6 +430,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) ...@@ -429,6 +430,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
{ {
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
const u16 buflen = dccp_ackvec_buflen(av); const u16 buflen = dccp_ackvec_buflen(av);
/* Figure out how many options do we need to represent the ackvec */ /* Figure out how many options do we need to represent the ackvec */
const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN); const u8 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN);
...@@ -437,10 +439,25 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) ...@@ -437,10 +439,25 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
const unsigned char *tail, *from; const unsigned char *tail, *from;
unsigned char *to; unsigned char *to;
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) if (dcb->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
DCCP_WARN("Lacking space for %u bytes on %s packet\n", len,
dccp_packet_name(dcb->dccpd_type));
return -1; return -1;
}
DCCP_SKB_CB(skb)->dccpd_opt_len += len; /*
* Since Ack Vectors are variable-length, we can not always predict
* their size. To catch exception cases where the space is running out
* on the skb, a separate Sync is scheduled to carry the Ack Vector.
*/
if (len > DCCPAV_MIN_OPTLEN &&
len + dcb->dccpd_opt_len + skb->len > dp->dccps_mss_cache) {
DCCP_WARN("No space left for Ack Vector (%u) on skb (%u+%u), "
"MPS=%u ==> reduce payload size?\n", len, skb->len,
dcb->dccpd_opt_len, dp->dccps_mss_cache);
dp->dccps_sync_scheduled = 1;
return 0;
}
dcb->dccpd_opt_len += len;
to = skb_push(skb, len); to = skb_push(skb, len);
len = buflen; len = buflen;
...@@ -481,7 +498,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) ...@@ -481,7 +498,7 @@ static int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
/* /*
* Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340. * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340.
*/ */
if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce)) if (dccp_ackvec_update_records(av, dcb->dccpd_seq, nonce))
return -ENOBUFS; return -ENOBUFS;
return 0; return 0;
} }
......
...@@ -283,6 +283,15 @@ static void dccp_xmit_packet(struct sock *sk) ...@@ -283,6 +283,15 @@ static void dccp_xmit_packet(struct sock *sk)
* any local drop will eventually be reported via receiver feedback. * any local drop will eventually be reported via receiver feedback.
*/ */
ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len); ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len);
/*
* If the CCID needs to transfer additional header options out-of-band
* (e.g. Ack Vectors or feature-negotiation options), it activates this
* flag to schedule a Sync. The Sync will automatically incorporate all
* currently pending header options, thus clearing the backlog.
*/
if (dp->dccps_sync_scheduled)
dccp_send_sync(sk, dp->dccps_gsr, DCCP_PKT_SYNC);
} }
/** /**
...@@ -636,6 +645,12 @@ void dccp_send_sync(struct sock *sk, const u64 ackno, ...@@ -636,6 +645,12 @@ void dccp_send_sync(struct sock *sk, const u64 ackno,
DCCP_SKB_CB(skb)->dccpd_type = pkt_type; DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno; DCCP_SKB_CB(skb)->dccpd_ack_seq = ackno;
/*
* Clear the flag in case the Sync was scheduled for out-of-band data,
* such as carrying a long Ack Vector.
*/
dccp_sk(sk)->dccps_sync_scheduled = 0;
dccp_transmit_skb(sk, skb); dccp_transmit_skb(sk, skb);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment