* Fix an accounting bug regarding SACK/NR-SACK chunks.

* Fix the generation of the SACK/NR-SACK gap lists.

MFC after: 3 days.
This commit is contained in:
Michael Tuexen 2010-11-06 13:30:54 +00:00
parent b790ac8809
commit 699437a2ba

View File

@ -9927,7 +9927,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
caddr_t limit;
uint32_t *dup;
int limit_reached = 0;
unsigned int i, sel_start, siz, j, starting_index;
unsigned int i, sel_start, siz, j;
unsigned int num_gap_blocks = 0, num_nr_gap_blocks = 0, space;
int num_dups = 0;
int space_req;
@ -9954,7 +9954,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
if (chk->rec.chunk_id.id == type) {
/* Hmm, found a sack already on queue, remove it */
TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
asoc->ctrl_queue_cnt++;
asoc->ctrl_queue_cnt--;
a_chk = chk;
if (a_chk->data) {
sctp_m_freem(a_chk->data);
@ -9993,15 +9993,13 @@ sctp_send_sack(struct sctp_tcb *stcb)
a_chk->whoTo = NULL;
if ((asoc->numduptsns) ||
(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)
) {
(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) {
/*-
* Ok, we have some duplicates or the destination for the
* sack is unreachable, lets see if we can select an
* alternate than asoc->last_data_chunk_from
*/
if ((!(asoc->last_data_chunk_from->dest_state &
SCTP_ADDR_NOT_REACHABLE)) &&
if ((!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) &&
(asoc->used_alt_onsack > asoc->numnets)) {
/* We used an alt last time, don't this time */
a_chk->whoTo = NULL;
@ -10120,53 +10118,25 @@ sctp_send_sack(struct sctp_tcb *stcb)
}
}
if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
offset = 1;
/*-
* The base TSN is intialized to be the first TSN the peer
* will send us. If the cum-ack is behind this then when they
* send us the next in sequence it will mark the base_tsn bit.
* Thus we need to use the very first selector and the offset
* is 1. Our table is built for this case.
*/
starting_index = 0;
if (((type == SCTP_SELECTIVE_ACK) &&
(((asoc->mapping_array[0] | asoc->nr_mapping_array[0]) & 0x01) == 0x00)) ||
((type == SCTP_NR_SELECTIVE_ACK) &&
((asoc->mapping_array[0] & 0x01) == 0x00))) {
sel_start = 0;
} else {
/*-
* we skip the first selector when the cum-ack is at or above the
* mapping array base. This is because the bits at the base or above
* are turned on and our first selector in the table assumes they are
* off. We thus will use the second selector (first is 0). We use
* the reverse of our macro to fix the offset, in bits, that our
* table is at. Note that this method assumes that the cum-tsn is
* within the first bit, i.e. its value is 0-7 which means the
* result to our offset will be either a 0 - -7. If the cumack
* is NOT in the first byte (0) (which it should be since we did
* a mapping array slide above) then we need to calculate the starting
* index i.e. which byte of the mapping array we should start at. We
* do this by dividing by 8 and pushing the remainder (mod) into offset.
* then we multiply the offset to be negative, since we need a negative
* offset into the selector table.
*/
SCTP_CALC_TSN_TO_GAP(offset, asoc->cumulative_tsn, asoc->mapping_array_base_tsn);
if (offset > 7) {
starting_index = offset / 8;
offset = offset % 8;
printf("Strange starting index is %d offset:%d (not 0/x)\n",
starting_index, offset);
} else {
starting_index = 0;
}
/* We need a negative offset in our table */
offset *= -1;
sel_start = 1;
}
if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
offset = 1;
} else {
offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn;
}
if (((type == SCTP_SELECTIVE_ACK) &&
compare_with_wrap(highest_tsn, asoc->cumulative_tsn, MAX_TSN)) ||
((type == SCTP_NR_SELECTIVE_ACK) &&
compare_with_wrap(asoc->highest_tsn_inside_map, asoc->cumulative_tsn, MAX_TSN))) {
/* we have a gap .. maybe */
for (i = starting_index; i < siz; i++) {
for (i = 0; i < siz; i++) {
if (type == SCTP_SELECTIVE_ACK) {
selector = &sack_array[asoc->mapping_array[i] | asoc->nr_mapping_array[i]];
} else {
@ -10224,26 +10194,22 @@ sctp_send_sack(struct sctp_tcb *stcb)
mergeable = 0;
if (asoc->highest_tsn_inside_nr_map > asoc->mapping_array_base_tsn)
if (asoc->highest_tsn_inside_nr_map > asoc->mapping_array_base_tsn) {
siz = (((asoc->highest_tsn_inside_nr_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8;
else
} else {
siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_nr_map + 7) / 8;
}
if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
offset = 1;
/*-
* cum-ack behind the mapping array, so we start and use all
* entries.
*/
if ((asoc->nr_mapping_array[0] & 0x01) == 0x00) {
sel_start = 0;
} else {
offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn;
/*-
* we skip the first one when the cum-ack is at or above the
* mapping array base. Note this only works if
*/
sel_start = 1;
}
if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
offset = 1;
} else {
offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn;
}
if (compare_with_wrap(asoc->highest_tsn_inside_nr_map, asoc->cumulative_tsn, MAX_TSN)) {
/* we have a gap .. maybe */
for (i = 0; i < siz; i++) {