Fix for NR-Sack code. The code was NOT working properly when
enabled. Basically most of the operations were incorrect causing bad sacks when you enabled nr-sack. The fixes range across 4 files and unifiy most of the processing so that we only test nr_sack flags to decide which type of sack to generate. Optimization left for this is to combine the sack generation code and make it capable of generating either sack thus shrinking out a routine. Reviewed by: tuexen@freebsd.org
This commit is contained in:
parent
2430ab4629
commit
77acdc2565
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=205627
@ -46,24 +46,13 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/sctp_timer.h>
|
||||
|
||||
#define SCTP_CALC_TSN_TO_GAP(gap, tsn, mapping_tsn) do { \
|
||||
if ((compare_with_wrap(tsn, mapping_tsn, MAX_TSN)) || \
|
||||
(tsn == mapping_tsn)) { \
|
||||
if (tsn >= mapping_tsn) { \
|
||||
gap = tsn - mapping_tsn; \
|
||||
} else { \
|
||||
gap = (MAX_TSN - mapping_tsn) + tsn + 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define SCTP_REVERSE_OUT_TSN_PRES(nr_gap, tsn, asoc) do { \
|
||||
if (asoc->mapping_array_base_tsn == asoc->nr_mapping_array_base_tsn) { \
|
||||
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, nr_gap); \
|
||||
} else {\
|
||||
int lgap; \
|
||||
SCTP_CALC_TSN_TO_GAP(lgap, tsn, asoc->mapping_array_base_tsn); \
|
||||
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, lgap); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
* NOTES: On the outbound side of things I need to check the sack timer to
|
||||
* see if I should generate a sack into the chunk queue (if I have data to
|
||||
@ -304,6 +293,44 @@ sctp_build_ctl_cchunk(struct sctp_inpcb *inp,
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
|
||||
{
|
||||
uint32_t gap, i;
|
||||
int fnd = 0;
|
||||
|
||||
if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
|
||||
return;
|
||||
}
|
||||
SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
|
||||
#ifdef INVARIANTS
|
||||
if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
|
||||
printf("gap:%x tsn:%x\n", gap, tsn);
|
||||
sctp_print_mapping_array(asoc);
|
||||
panic("Things are really messed up now!!");
|
||||
}
|
||||
#endif
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
if (tsn == asoc->highest_tsn_inside_map) {
|
||||
/* We must back down to see what the new highest is */
|
||||
for (i = tsn - 1; compare_with_wrap(i, asoc->mapping_array_base_tsn, MAX_TSN); i--) {
|
||||
SCTP_CALC_TSN_TO_GAP(gap, i, asoc->mapping_array_base_tsn);
|
||||
if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
|
||||
asoc->highest_tsn_inside_map = i;
|
||||
fnd = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fnd) {
|
||||
asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* We are delivering currently from the reassembly queue. We must continue to
|
||||
@ -319,9 +346,6 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
int end = 0;
|
||||
int cntDel;
|
||||
|
||||
/* EY if any out-of-order delivered, then tag it nr on nr_map */
|
||||
uint32_t nr_tsn, nr_gap;
|
||||
|
||||
struct sctp_queued_to_read *control, *ctl, *ctlat;
|
||||
|
||||
if (stcb == NULL)
|
||||
@ -430,39 +454,7 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
}
|
||||
/* pull it we did it */
|
||||
TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
|
||||
/*
|
||||
* EY this is the chunk that should be tagged nr gapped
|
||||
* calculate the gap and such then tag this TSN nr
|
||||
* chk->rec.data.TSN_seq
|
||||
*/
|
||||
/*
|
||||
* EY!-TODO- this tsn should be tagged nr only if it is
|
||||
* out-of-order, the if statement should be modified
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
nr_tsn = chk->rec.data.TSN_seq;
|
||||
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
if ((nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
|
||||
/*
|
||||
* EY The 1st should never happen, as in
|
||||
* process_a_data_chunk method this check
|
||||
* should be done
|
||||
*/
|
||||
/*
|
||||
* EY The 2nd should never happen, because
|
||||
* nr_mapping_array is always expanded when
|
||||
* mapping_array is expanded
|
||||
*/
|
||||
printf("Impossible nr_gap ack range failed\n");
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
|
||||
if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = nr_tsn;
|
||||
}
|
||||
}
|
||||
sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
|
||||
if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
|
||||
asoc->fragmented_delivery_inprogress = 0;
|
||||
if ((chk->rec.data.rcv_flags & SCTP_DATA_UNORDERED) == 0) {
|
||||
@ -509,67 +501,11 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
asoc->size_on_all_streams -= ctl->length;
|
||||
sctp_ucount_decr(asoc->cnt_on_all_streams);
|
||||
strm->last_sequence_delivered++;
|
||||
/*
|
||||
* EY will be used to
|
||||
* calculate nr-gap
|
||||
*/
|
||||
nr_tsn = ctl->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
ctl,
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY -now something is
|
||||
* delivered, calculate
|
||||
* nr_gap and tag this tsn
|
||||
* NR
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
|
||||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
|
||||
/*
|
||||
* EY The
|
||||
* 1st
|
||||
* should
|
||||
* never
|
||||
* happen,
|
||||
* as in
|
||||
* process_a_
|
||||
* data_chunk
|
||||
* method
|
||||
* this
|
||||
* check
|
||||
* should be
|
||||
* done
|
||||
*/
|
||||
/*
|
||||
* EY The
|
||||
* 2nd
|
||||
* should
|
||||
* never
|
||||
* happen,
|
||||
* because
|
||||
* nr_mapping
|
||||
* _array is
|
||||
* always
|
||||
* expanded
|
||||
* when
|
||||
* mapping_ar
|
||||
* ray is
|
||||
* expanded
|
||||
*/
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
|
||||
if (compare_with_wrap(nr_tsn,
|
||||
asoc->highest_tsn_inside_nr_map,
|
||||
MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = nr_tsn;
|
||||
}
|
||||
}
|
||||
sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
|
||||
ctl = ctlat;
|
||||
} else {
|
||||
break;
|
||||
@ -618,9 +554,6 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
uint16_t nxt_todel;
|
||||
struct mbuf *oper;
|
||||
|
||||
/* EY- will be used to calculate nr-gap for a tsn */
|
||||
uint32_t nr_tsn, nr_gap;
|
||||
|
||||
queue_needed = 1;
|
||||
asoc->size_on_all_streams += control->length;
|
||||
sctp_ucount_incr(asoc->cnt_on_all_streams);
|
||||
@ -682,41 +615,12 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
asoc->size_on_all_streams -= control->length;
|
||||
sctp_ucount_decr(asoc->cnt_on_all_streams);
|
||||
strm->last_sequence_delivered++;
|
||||
/* EY will be used to calculate nr-gap */
|
||||
nr_tsn = control->sinfo_tsn;
|
||||
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be tagged nr gapped
|
||||
* calculate the gap and such then tag this TSN nr
|
||||
* chk->rec.data.TSN_seq
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
|
||||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
|
||||
printf("Impossible nr_tsn set 2?\n");
|
||||
/*
|
||||
* EY The 1st should never happen, as in
|
||||
* process_a_data_chunk method this check
|
||||
* should be done
|
||||
*/
|
||||
/*
|
||||
* EY The 2nd should never happen, because
|
||||
* nr_mapping_array is always expanded when
|
||||
* mapping_array is expanded
|
||||
*/
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
|
||||
if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = nr_tsn;
|
||||
}
|
||||
}
|
||||
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
|
||||
control = TAILQ_FIRST(&strm->inqueue);
|
||||
while (control != NULL) {
|
||||
/* all delivered */
|
||||
@ -738,47 +642,12 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
SCTP_STR_LOG_FROM_IMMED_DEL);
|
||||
}
|
||||
/* EY will be used to calculate nr-gap */
|
||||
nr_tsn = control->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1,
|
||||
SCTP_READ_LOCK_NOT_HELD,
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be
|
||||
* tagged nr gapped calculate the gap and
|
||||
* such then tag this TSN nr
|
||||
* chk->rec.data.TSN_seq
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
|
||||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
|
||||
/*
|
||||
* EY The 1st should never
|
||||
* happen, as in
|
||||
* process_a_data_chunk
|
||||
* method this check should
|
||||
* be done
|
||||
*/
|
||||
/*
|
||||
* EY The 2nd should never
|
||||
* happen, because
|
||||
* nr_mapping_array is
|
||||
* always expanded when
|
||||
* mapping_array is expanded
|
||||
*/
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
if (compare_with_wrap(nr_tsn,
|
||||
asoc->highest_tsn_inside_nr_map,
|
||||
MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = nr_tsn;
|
||||
}
|
||||
}
|
||||
sctp_mark_non_revokable(asoc, control->sinfo_tsn);
|
||||
control = at;
|
||||
continue;
|
||||
}
|
||||
@ -1586,9 +1455,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
/* struct sctp_tmit_chunk *chk; */
|
||||
struct sctp_tmit_chunk *chk;
|
||||
uint32_t tsn, gap;
|
||||
|
||||
/* EY - for nr_sack */
|
||||
uint32_t nr_gap;
|
||||
struct mbuf *dmbuf;
|
||||
int indx, the_len;
|
||||
int need_reasm_check = 0;
|
||||
@ -1640,14 +1506,12 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
/* EY - for nr_sack */
|
||||
nr_gap = gap;
|
||||
|
||||
if (compare_with_wrap(tsn, *high_tsn, MAX_TSN)) {
|
||||
*high_tsn = tsn;
|
||||
}
|
||||
/* See if we have received this one already */
|
||||
if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
|
||||
if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap) ||
|
||||
SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap)) {
|
||||
SCTP_STAT_INCR(sctps_recvdupdata);
|
||||
if (asoc->numduptsns < SCTP_MAX_DUP_TSNS) {
|
||||
/* Record a dup for the next outbound sack */
|
||||
@ -1714,7 +1578,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
#endif
|
||||
}
|
||||
/* now is it in the mapping array of what we have accepted? */
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) {
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN) &&
|
||||
compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
/* Nope not in the valid range dump it */
|
||||
sctp_set_rwnd(stcb, asoc);
|
||||
if ((asoc->cnt_on_all_streams +
|
||||
@ -1758,23 +1623,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_badsid);
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
|
||||
/* EY set this tsn present in nr_sack's nr_mapping_array */
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(gap, tsn, asoc);
|
||||
}
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) {
|
||||
/* we have a new high score */
|
||||
asoc->highest_tsn_inside_map = tsn;
|
||||
/* EY nr_sack version of the above */
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack)
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
if (tsn == (asoc->cumulative_tsn + 1)) {
|
||||
/* Update cum-ack */
|
||||
@ -1925,48 +1777,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
control, &stcb->sctp_socket->so_rcv,
|
||||
1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
|
||||
/*
|
||||
* EY here I should check if this delivered tsn is
|
||||
* out_of_order, if yes then update the nr_map
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
|
||||
/*
|
||||
* EY check if the mapping_array and nr_mapping
|
||||
* array are consistent
|
||||
*/
|
||||
if (asoc->mapping_array_base_tsn != asoc->nr_mapping_array_base_tsn)
|
||||
/*
|
||||
* printf("EY-IN
|
||||
* sctp_process_a_data_chunk(5): Something
|
||||
* is wrong the map base tsn" "\nEY-and
|
||||
* nr_map base tsn should be equal.");
|
||||
*/
|
||||
/* EY debugging block */
|
||||
{
|
||||
/*
|
||||
* printf("\nEY-Calculating an
|
||||
* nr_gap!!\nmapping_array_size = %d
|
||||
* nr_mapping_array_size = %d"
|
||||
* "\nEY-mapping_array_base = %d
|
||||
* nr_mapping_array_base =
|
||||
* %d\nEY-highest_tsn_inside_map = %d"
|
||||
* "highest_tsn_inside_nr_map = %d\nEY-TSN =
|
||||
* %d nr_gap = %d",asoc->mapping_array_size,
|
||||
* asoc->nr_mapping_array_size,
|
||||
* asoc->mapping_array_base_tsn,
|
||||
* asoc->nr_mapping_array_base_tsn,
|
||||
* asoc->highest_tsn_inside_map,
|
||||
* asoc->highest_tsn_inside_nr_map,tsn,nr_gap
|
||||
* );
|
||||
*/
|
||||
}
|
||||
/* EY - not %100 sure about the lock thing */
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, tsn, asoc);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
|
||||
/* for ordered, bump what we delivered */
|
||||
asoc->strmin[strmno].last_sequence_delivered++;
|
||||
@ -1977,6 +1787,10 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
SCTP_STR_LOG_FROM_EXPRS_DEL);
|
||||
}
|
||||
control = NULL;
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
goto finish_express_del;
|
||||
}
|
||||
failed_express_del:
|
||||
@ -2012,39 +1826,9 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
SCTP_PRINTF("Append fails end:%d\n", end);
|
||||
goto failed_pdapi_express_del;
|
||||
}
|
||||
/*
|
||||
* EY It is appended to the read queue in prev if
|
||||
* block here I should check if this delivered tsn
|
||||
* is out_of_order, if yes then update the nr_map
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
/* EY debugging block */
|
||||
{
|
||||
/*
|
||||
* printf("\nEY-Calculating an
|
||||
* nr_gap!!\nEY-mapping_array_size =
|
||||
* %d nr_mapping_array_size = %d"
|
||||
* "\nEY-mapping_array_base = %d
|
||||
* nr_mapping_array_base =
|
||||
* %d\nEY-highest_tsn_inside_map =
|
||||
* %d" "highest_tsn_inside_nr_map =
|
||||
* %d\nEY-TSN = %d nr_gap =
|
||||
* %d",asoc->mapping_array_size,
|
||||
* asoc->nr_mapping_array_size,
|
||||
* asoc->mapping_array_base_tsn,
|
||||
* asoc->nr_mapping_array_base_tsn,
|
||||
* asoc->highest_tsn_inside_map,
|
||||
* asoc->highest_tsn_inside_nr_map,ts
|
||||
* n,nr_gap);
|
||||
*/
|
||||
}
|
||||
/* EY - not %100 sure about the lock thing */
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, tsn, asoc);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_recvexpressm);
|
||||
control->sinfo_tsn = tsn;
|
||||
@ -2069,12 +1853,27 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
need_reasm_check = 1;
|
||||
}
|
||||
}
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
control = NULL;
|
||||
goto finish_express_del;
|
||||
}
|
||||
}
|
||||
failed_pdapi_express_del:
|
||||
control = NULL;
|
||||
if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
} else {
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_map = tsn;
|
||||
}
|
||||
}
|
||||
if ((chunk_flags & SCTP_DATA_NOT_FRAG) != SCTP_DATA_NOT_FRAG) {
|
||||
sctp_alloc_a_chunk(stcb, chk);
|
||||
if (chk == NULL) {
|
||||
@ -2263,56 +2062,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
control,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY It is added to the read queue in prev if block
|
||||
* here I should check if this delivered tsn is
|
||||
* out_of_order, if yes then update the nr_map
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
/*
|
||||
* EY check if the mapping_array and
|
||||
* nr_mapping array are consistent
|
||||
*/
|
||||
if (asoc->mapping_array_base_tsn != asoc->nr_mapping_array_base_tsn)
|
||||
/*
|
||||
* printf("EY-IN
|
||||
* sctp_process_a_data_chunk(6):
|
||||
* Something is wrong the map base
|
||||
* tsn" "\nEY-and nr_map base tsn
|
||||
* should be equal.");
|
||||
*/
|
||||
/*
|
||||
* EY - not %100 sure about the lock
|
||||
* thing, i think we don't need the
|
||||
* below,
|
||||
*/
|
||||
/* SCTP_TCB_LOCK_ASSERT(stcb); */
|
||||
{
|
||||
/*
|
||||
* printf("\nEY-Calculating an
|
||||
* nr_gap!!\nEY-mapping_array_size =
|
||||
* %d nr_mapping_array_size = %d"
|
||||
* "\nEY-mapping_array_base = %d
|
||||
* nr_mapping_array_base =
|
||||
* %d\nEY-highest_tsn_inside_map =
|
||||
* %d" "highest_tsn_inside_nr_map =
|
||||
* %d\nEY-TSN = %d nr_gap =
|
||||
* %d",asoc->mapping_array_size,
|
||||
* asoc->nr_mapping_array_size,
|
||||
* asoc->mapping_array_base_tsn,
|
||||
* asoc->nr_mapping_array_base_tsn,
|
||||
* asoc->highest_tsn_inside_map,
|
||||
* asoc->highest_tsn_inside_nr_map,ts
|
||||
* n,nr_gap);
|
||||
*/
|
||||
}
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, tsn, asoc);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* Special check for when streams are resetting. We
|
||||
@ -2384,13 +2134,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
}
|
||||
}
|
||||
finish_express_del:
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_map, MAX_TSN)) {
|
||||
/* we have a new high score */
|
||||
asoc->highest_tsn_inside_map = tsn;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(0, 2, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
}
|
||||
if (tsn == (asoc->cumulative_tsn + 1)) {
|
||||
/* Update cum-ack */
|
||||
asoc->cumulative_tsn = tsn;
|
||||
@ -2412,22 +2155,6 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
|
||||
asoc->highest_tsn_inside_map, SCTP_MAP_PREPARE_SLIDE);
|
||||
}
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, gap);
|
||||
|
||||
/*
|
||||
* EY - set tsn present in nr-map if doing nr-sacks and the tsn is
|
||||
* non-renegable
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack &&
|
||||
(SCTP_BASE_SYSCTL(sctp_do_drain) == 0)) {
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, tsn, asoc);
|
||||
if (compare_with_wrap(tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = tsn;
|
||||
}
|
||||
}
|
||||
/* check the special flag for stream resets */
|
||||
if (((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) &&
|
||||
((compare_with_wrap(asoc->cumulative_tsn, liste->tsn, MAX_TSN)) ||
|
||||
@ -2532,7 +2259,6 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
*/
|
||||
struct sctp_association *asoc;
|
||||
int at;
|
||||
uint8_t comb_byte;
|
||||
int last_all_ones = 0;
|
||||
int slide_from, slide_end, lgap, distance;
|
||||
|
||||
@ -2540,7 +2266,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
/* int nr_at; */
|
||||
/* int nr_last_all_ones = 0; */
|
||||
/* int nr_slide_from, nr_slide_end, nr_lgap, nr_distance; */
|
||||
uint32_t old_cumack, old_base, old_highest;
|
||||
uint32_t old_cumack, old_base, old_highest, highest_tsn;
|
||||
|
||||
asoc = &stcb->asoc;
|
||||
at = 0;
|
||||
@ -2553,30 +2279,23 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
* offset of the current cum-ack as the starting point.
|
||||
*/
|
||||
at = 0;
|
||||
for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) {
|
||||
/*
|
||||
* We must combine the renegable and non-renegable arrays
|
||||
* here to form a unified view of what is acked right now
|
||||
* (since they are kept separate
|
||||
*/
|
||||
comb_byte = asoc->mapping_array[slide_from] | asoc->nr_mapping_array[slide_from];
|
||||
if (comb_byte == 0xff) {
|
||||
for (slide_from = 0; slide_from < stcb->asoc.nr_mapping_array_size; slide_from++) {
|
||||
if (asoc->nr_mapping_array[slide_from] == 0xff) {
|
||||
at += 8;
|
||||
last_all_ones = 1;
|
||||
} else {
|
||||
/* there is a 0 bit */
|
||||
at += sctp_map_lookup_tab[comb_byte];
|
||||
at += sctp_map_lookup_tab[asoc->nr_mapping_array[slide_from]];
|
||||
last_all_ones = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at - last_all_ones);
|
||||
/* at is one off, since in the table a embedded -1 is present */
|
||||
asoc->cumulative_tsn = asoc->nr_mapping_array_base_tsn + (at - last_all_ones);
|
||||
at++;
|
||||
|
||||
if (compare_with_wrap(asoc->cumulative_tsn,
|
||||
asoc->highest_tsn_inside_map,
|
||||
MAX_TSN)) {
|
||||
if (compare_with_wrap(asoc->cumulative_tsn, asoc->highest_tsn_inside_map, MAX_TSN) &&
|
||||
compare_with_wrap(asoc->cumulative_tsn, asoc->highest_tsn_inside_nr_map, MAX_TSN)
|
||||
) {
|
||||
#ifdef INVARIANTS
|
||||
panic("huh, cumack 0x%x greater than high-tsn 0x%x in map",
|
||||
asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
|
||||
@ -2591,37 +2310,29 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn;
|
||||
#endif
|
||||
}
|
||||
if ((asoc->cumulative_tsn == asoc->highest_tsn_inside_map) && (at >= 8)) {
|
||||
if (compare_with_wrap(asoc->highest_tsn_inside_nr_map,
|
||||
asoc->highest_tsn_inside_map,
|
||||
MAX_TSN)) {
|
||||
highest_tsn = asoc->highest_tsn_inside_nr_map;
|
||||
} else {
|
||||
highest_tsn = asoc->highest_tsn_inside_map;
|
||||
}
|
||||
if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) {
|
||||
/* The complete array was completed by a single FR */
|
||||
/* higest becomes the cum-ack */
|
||||
/* highest becomes the cum-ack */
|
||||
int clr;
|
||||
|
||||
asoc->cumulative_tsn = asoc->highest_tsn_inside_map;
|
||||
/* clear the array */
|
||||
clr = (at >> 3) + 1;
|
||||
if (clr > asoc->mapping_array_size) {
|
||||
clr = asoc->mapping_array_size;
|
||||
}
|
||||
memset(asoc->mapping_array, 0, clr);
|
||||
/* base becomes one ahead of the cum-ack */
|
||||
memset(asoc->nr_mapping_array, 0, clr);
|
||||
|
||||
asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1;
|
||||
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
|
||||
|
||||
if (clr > asoc->nr_mapping_array_size)
|
||||
clr = asoc->nr_mapping_array_size;
|
||||
|
||||
memset(asoc->nr_mapping_array, 0, clr);
|
||||
/* base becomes one ahead of the cum-ack */
|
||||
asoc->nr_mapping_array_base_tsn = asoc->cumulative_tsn + 1;
|
||||
asoc->highest_tsn_inside_nr_map = asoc->cumulative_tsn;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(old_base, old_cumack, old_highest,
|
||||
SCTP_MAP_PREPARE_SLIDE);
|
||||
sctp_log_map(asoc->mapping_array_base_tsn, asoc->cumulative_tsn,
|
||||
asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_CLEARED);
|
||||
}
|
||||
asoc->nr_mapping_array_base_tsn = asoc->cumulative_tsn + 1;
|
||||
asoc->highest_tsn_inside_nr_map = asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
|
||||
} else if (at >= 8) {
|
||||
/* we can slide the mapping array down */
|
||||
/* slide_from holds where we hit the first NON 0xff byte */
|
||||
@ -2630,19 +2341,15 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
* now calculate the ceiling of the move using our highest
|
||||
* TSN value
|
||||
*/
|
||||
if (asoc->highest_tsn_inside_map >= asoc->mapping_array_base_tsn) {
|
||||
lgap = asoc->highest_tsn_inside_map -
|
||||
asoc->mapping_array_base_tsn;
|
||||
} else {
|
||||
lgap = (MAX_TSN - asoc->mapping_array_base_tsn) +
|
||||
asoc->highest_tsn_inside_map + 1;
|
||||
}
|
||||
slide_end = lgap >> 3;
|
||||
SCTP_CALC_TSN_TO_GAP(lgap, highest_tsn, asoc->mapping_array_base_tsn);
|
||||
slide_end = (lgap >> 3);
|
||||
if (slide_end < slide_from) {
|
||||
sctp_print_mapping_array(asoc);
|
||||
#ifdef INVARIANTS
|
||||
panic("impossible slide");
|
||||
#else
|
||||
printf("impossible slide?\n");
|
||||
printf("impossible slide lgap:%x slide_end:%x slide_from:%x? at:%d\n",
|
||||
lgap, slide_end, slide_from, at);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
@ -2682,30 +2389,21 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
for (ii = 0; ii < distance; ii++) {
|
||||
asoc->mapping_array[ii] =
|
||||
asoc->mapping_array[slide_from + ii];
|
||||
asoc->nr_mapping_array[ii] =
|
||||
asoc->nr_mapping_array[slide_from + ii];
|
||||
|
||||
}
|
||||
for (ii = distance; ii <= slide_end; ii++) {
|
||||
asoc->mapping_array[ii] = 0;
|
||||
asoc->nr_mapping_array[ii] = 0;
|
||||
}
|
||||
asoc->mapping_array_base_tsn += (slide_from << 3);
|
||||
asoc->nr_mapping_array_base_tsn += (slide_from << 3);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(asoc->mapping_array_base_tsn,
|
||||
asoc->cumulative_tsn, asoc->highest_tsn_inside_map,
|
||||
SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
/*
|
||||
* EY if doing nr_sacks then slide the
|
||||
* nr_mapping_array accordingly please
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
|
||||
for (ii = 0; ii < distance; ii++) {
|
||||
asoc->nr_mapping_array[ii] =
|
||||
asoc->nr_mapping_array[slide_from + ii];
|
||||
}
|
||||
for (ii = distance; ii <= slide_end; ii++) {
|
||||
asoc->nr_mapping_array[ii] = 0;
|
||||
}
|
||||
asoc->nr_mapping_array_base_tsn += (slide_from << 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -2736,8 +2434,7 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
|
||||
int is_a_gap;
|
||||
|
||||
/* is there a gap now ? */
|
||||
is_a_gap = compare_with_wrap(stcb->asoc.highest_tsn_inside_map,
|
||||
stcb->asoc.cumulative_tsn, MAX_TSN);
|
||||
is_a_gap = compare_with_wrap(highest_tsn, stcb->asoc.cumulative_tsn, MAX_TSN);
|
||||
|
||||
/*
|
||||
* CMT DAC algorithm: increase number of packets
|
||||
@ -5742,9 +5439,6 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc;
|
||||
int tt;
|
||||
|
||||
/* EY -used to calculate nr_gap information */
|
||||
uint32_t nr_tsn, nr_gap;
|
||||
|
||||
asoc = &stcb->asoc;
|
||||
tt = strmin->last_sequence_delivered;
|
||||
/*
|
||||
@ -5764,82 +5458,10 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
|
||||
/* deliver it to at least the delivery-q */
|
||||
if (stcb->sctp_socket) {
|
||||
/* EY need the tsn info for calculating nr */
|
||||
nr_tsn = ctl->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
ctl,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be
|
||||
* tagged nr gapped calculate the gap and
|
||||
* such then tag this TSN nr
|
||||
* chk->rec.data.TSN_seq
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
|
||||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
|
||||
/*
|
||||
* EY These should never
|
||||
* happen- explained before
|
||||
*/
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
|
||||
if (compare_with_wrap(nr_tsn,
|
||||
asoc->highest_tsn_inside_nr_map,
|
||||
MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = nr_tsn;
|
||||
}
|
||||
if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, nr_gap))
|
||||
/*
|
||||
* printf("In
|
||||
* sctp_kick_prsctp_reorder_q
|
||||
* ueue(7): Something wrong,
|
||||
* the TSN to be tagged"
|
||||
* "\nas NR is not even in
|
||||
* the mapping_array, or map
|
||||
* and nr_map are
|
||||
* inconsistent");
|
||||
*/
|
||||
/*
|
||||
* EY - not %100 sure about
|
||||
* the lock thing, don't
|
||||
* think its required
|
||||
*/
|
||||
/*
|
||||
* SCTP_TCB_LOCK_ASSERT(stcb)
|
||||
* ;
|
||||
*/
|
||||
{
|
||||
/*
|
||||
* printf("\nCalculating an
|
||||
* nr_gap!!\nmapping_array_si
|
||||
* ze = %d
|
||||
* nr_mapping_array_size =
|
||||
* %d" "\nmapping_array_base
|
||||
* = %d
|
||||
* nr_mapping_array_base =
|
||||
* %d\nhighest_tsn_inside_map
|
||||
* = %d"
|
||||
* "highest_tsn_inside_nr_map
|
||||
* = %d\nTSN = %d nr_gap =
|
||||
* %d",asoc->mapping_array_si
|
||||
* ze,
|
||||
* asoc->nr_mapping_array_siz
|
||||
* e,
|
||||
* asoc->mapping_array_base_t
|
||||
* sn,
|
||||
* asoc->nr_mapping_array_bas
|
||||
* e_tsn,
|
||||
* asoc->highest_tsn_inside_m
|
||||
* ap,
|
||||
* asoc->highest_tsn_inside_n
|
||||
* r_map,tsn,nr_gap);
|
||||
*/
|
||||
}
|
||||
}
|
||||
sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
|
||||
}
|
||||
} else {
|
||||
/* no more delivery now. */
|
||||
@ -5864,82 +5486,11 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
|
||||
/* deliver it to at least the delivery-q */
|
||||
strmin->last_sequence_delivered = ctl->sinfo_ssn;
|
||||
if (stcb->sctp_socket) {
|
||||
/* EY */
|
||||
nr_tsn = ctl->sinfo_tsn;
|
||||
sctp_add_to_readq(stcb->sctp_ep, stcb,
|
||||
ctl,
|
||||
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_HELD, SCTP_SO_NOT_LOCKED);
|
||||
/*
|
||||
* EY this is the chunk that should be
|
||||
* tagged nr gapped calculate the gap and
|
||||
* such then tag this TSN nr
|
||||
* chk->rec.data.TSN_seq
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
asoc->peer_supports_nr_sack) {
|
||||
SCTP_CALC_TSN_TO_GAP(nr_gap, nr_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
if ((nr_gap >= (SCTP_NR_MAPPING_ARRAY << 3)) ||
|
||||
(nr_gap >= (uint32_t) (asoc->nr_mapping_array_size << 3))) {
|
||||
/*
|
||||
* EY These should never
|
||||
* happen, explained before
|
||||
*/
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, nr_gap);
|
||||
SCTP_REVERSE_OUT_TSN_PRES(nr_gap, nr_tsn, asoc);
|
||||
if (compare_with_wrap(nr_tsn, asoc->highest_tsn_inside_nr_map,
|
||||
MAX_TSN))
|
||||
asoc->highest_tsn_inside_nr_map = nr_tsn;
|
||||
}
|
||||
if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, nr_gap))
|
||||
/*
|
||||
* printf("In
|
||||
* sctp_kick_prsctp_reorder_q
|
||||
* ueue(8): Something wrong,
|
||||
* the TSN to be tagged"
|
||||
* "\nas NR is not even in
|
||||
* the mapping_array, or map
|
||||
* and nr_map are
|
||||
* inconsistent");
|
||||
*/
|
||||
/*
|
||||
* EY - not %100 sure about
|
||||
* the lock thing, don't
|
||||
* think its required
|
||||
*/
|
||||
/*
|
||||
* SCTP_TCB_LOCK_ASSERT(stcb)
|
||||
* ;
|
||||
*/
|
||||
{
|
||||
/*
|
||||
* printf("\nCalculating an
|
||||
* nr_gap!!\nmapping_array_si
|
||||
* ze = %d
|
||||
* nr_mapping_array_size =
|
||||
* %d" "\nmapping_array_base
|
||||
* = %d
|
||||
* nr_mapping_array_base =
|
||||
* %d\nhighest_tsn_inside_map
|
||||
* = %d"
|
||||
* "highest_tsn_inside_nr_map
|
||||
* = %d\nTSN = %d nr_gap =
|
||||
* %d",asoc->mapping_array_si
|
||||
* ze,
|
||||
* asoc->nr_mapping_array_siz
|
||||
* e,
|
||||
* asoc->mapping_array_base_t
|
||||
* sn,
|
||||
* asoc->nr_mapping_array_bas
|
||||
* e_tsn,
|
||||
* asoc->highest_tsn_inside_m
|
||||
* ap,
|
||||
* asoc->highest_tsn_inside_n
|
||||
* r_map,tsn,nr_gap);
|
||||
*/
|
||||
}
|
||||
}
|
||||
sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
|
||||
|
||||
}
|
||||
tt = strmin->last_sequence_delivered + 1;
|
||||
} else {
|
||||
@ -6096,25 +5647,19 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
if (compare_with_wrap(new_cum_tsn, asoc->highest_tsn_inside_map,
|
||||
MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_map = new_cum_tsn;
|
||||
/* EY nr_mapping_array version of the above */
|
||||
/*
|
||||
* if(SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) &&
|
||||
* asoc->peer_supports_nr_sack)
|
||||
*/
|
||||
|
||||
}
|
||||
if (compare_with_wrap(new_cum_tsn, asoc->highest_tsn_inside_nr_map,
|
||||
MAX_TSN)) {
|
||||
asoc->highest_tsn_inside_nr_map = new_cum_tsn;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(0, 0, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* now we know the new TSN is more advanced, let's find the actual
|
||||
* gap
|
||||
*/
|
||||
SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn);
|
||||
SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->nr_mapping_array_base_tsn);
|
||||
asoc->cumulative_tsn = new_cum_tsn;
|
||||
if (gap >= m_size) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(0, 0, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
|
||||
struct mbuf *oper;
|
||||
|
||||
@ -6147,23 +5692,15 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
return;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_fwdtsn_map_over);
|
||||
|
||||
memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
|
||||
cumack_set_flag = 1;
|
||||
asoc->mapping_array_base_tsn = new_cum_tsn + 1;
|
||||
asoc->cumulative_tsn = asoc->highest_tsn_inside_map = new_cum_tsn;
|
||||
/* EY - nr_sack: nr_mapping_array version of the above */
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) {
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
asoc->nr_mapping_array_base_tsn = new_cum_tsn + 1;
|
||||
asoc->highest_tsn_inside_nr_map = new_cum_tsn;
|
||||
if (asoc->nr_mapping_array_size != asoc->mapping_array_size) {
|
||||
/*
|
||||
* printf("IN sctp_handle_forward_tsn:
|
||||
* Something is wrong the size of" "map and
|
||||
* nr_map should be equal!")
|
||||
*/ ;
|
||||
}
|
||||
}
|
||||
asoc->highest_tsn_inside_map = new_cum_tsn;
|
||||
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
asoc->nr_mapping_array_base_tsn = new_cum_tsn + 1;
|
||||
asoc->highest_tsn_inside_nr_map = new_cum_tsn;
|
||||
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
|
||||
sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
|
||||
}
|
||||
@ -6171,12 +5708,8 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
for (i = 0; i <= gap; i++) {
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack
|
||||
&& SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
|
||||
} else {
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, i);
|
||||
}
|
||||
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, i);
|
||||
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
|
||||
}
|
||||
/*
|
||||
* Now after marking all, slide thing forward but no sack
|
||||
|
@ -1860,9 +1860,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
|
||||
memset(asoc->mapping_array, 0,
|
||||
asoc->mapping_array_size);
|
||||
}
|
||||
/* EY 05/13/08 - nr_sack version of the above if statement */
|
||||
if (asoc->nr_mapping_array && SCTP_BASE_SYSCTL(sctp_nr_sack_on_off)
|
||||
&& asoc->peer_supports_nr_sack) {
|
||||
if (asoc->nr_mapping_array) {
|
||||
memset(asoc->nr_mapping_array, 0,
|
||||
asoc->nr_mapping_array_size);
|
||||
}
|
||||
@ -3515,16 +3513,10 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
|
||||
stcb->asoc.mapping_array_base_tsn = ntohl(resp->senders_next_tsn);
|
||||
memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
|
||||
|
||||
/*
|
||||
* EY 05/13/08 - nr_sack: to keep
|
||||
* nr_mapping array be consistent
|
||||
* with mapping_array
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack) {
|
||||
stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.nr_mapping_array_base_tsn = stcb->asoc.mapping_array_base_tsn;
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
}
|
||||
stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.nr_mapping_array_base_tsn = stcb->asoc.mapping_array_base_tsn;
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
|
||||
stcb->asoc.sending_seq = ntohl(resp->receivers_next_tsn);
|
||||
stcb->asoc.last_acked_seq = stcb->asoc.cumulative_tsn;
|
||||
|
||||
@ -3631,15 +3623,9 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb,
|
||||
stcb->asoc.tsn_last_delivered = stcb->asoc.cumulative_tsn = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.mapping_array_base_tsn = stcb->asoc.highest_tsn_inside_map + 1;
|
||||
memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
|
||||
/*
|
||||
* EY 05/13/08 -nr_sack: to keep nr_mapping array consistent
|
||||
* with mapping array
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack) {
|
||||
stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.nr_mapping_array_base_tsn = stcb->asoc.highest_tsn_inside_map + 1;
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
}
|
||||
stcb->asoc.highest_tsn_inside_nr_map = stcb->asoc.highest_tsn_inside_map;
|
||||
stcb->asoc.nr_mapping_array_base_tsn = stcb->asoc.highest_tsn_inside_map + 1;
|
||||
memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.nr_mapping_array_size);
|
||||
atomic_add_int(&stcb->asoc.sending_seq, 1);
|
||||
/* save off historical data for retrans */
|
||||
stcb->asoc.last_sending_seq[1] = stcb->asoc.last_sending_seq[0];
|
||||
|
@ -7871,19 +7871,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
|
||||
pf_hbflag = 1;
|
||||
}
|
||||
/* remove these chunks at the end */
|
||||
if (chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) {
|
||||
/* turn off the timer */
|
||||
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
|
||||
inp, stcb, net, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_1);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* EY -Nr-sack version of the above
|
||||
* if statement
|
||||
*/
|
||||
if ((SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack) &&
|
||||
(chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) { /* EY !?! */
|
||||
if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) ||
|
||||
(chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK)) {
|
||||
/* turn off the timer */
|
||||
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
|
||||
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
|
||||
@ -9885,6 +9874,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
|
||||
unsigned int num_gap_blocks = 0, space;
|
||||
int num_dups = 0;
|
||||
int space_req;
|
||||
uint32_t highest_tsn;
|
||||
|
||||
a_chk = NULL;
|
||||
asoc = &stcb->asoc;
|
||||
@ -9970,7 +9960,12 @@ sctp_send_sack(struct sctp_tcb *stcb)
|
||||
if (a_chk->whoTo) {
|
||||
atomic_add_int(&a_chk->whoTo->ref_count, 1);
|
||||
}
|
||||
if (asoc->highest_tsn_inside_map == asoc->cumulative_tsn) {
|
||||
if (compare_with_wrap(asoc->highest_tsn_inside_map, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
highest_tsn = asoc->highest_tsn_inside_map;
|
||||
} else {
|
||||
highest_tsn = asoc->highest_tsn_inside_nr_map;
|
||||
}
|
||||
if (highest_tsn == asoc->cumulative_tsn) {
|
||||
/* no gaps */
|
||||
space_req = sizeof(struct sctp_sack_chunk);
|
||||
} else {
|
||||
@ -10043,10 +10038,10 @@ sctp_send_sack(struct sctp_tcb *stcb)
|
||||
|
||||
gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk));
|
||||
|
||||
if (asoc->highest_tsn_inside_map > asoc->mapping_array_base_tsn)
|
||||
siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8;
|
||||
if (highest_tsn > asoc->mapping_array_base_tsn)
|
||||
siz = (((highest_tsn - asoc->mapping_array_base_tsn) + 1) + 7) / 8;
|
||||
else
|
||||
siz = (((MAX_TSN - asoc->mapping_array_base_tsn) + 1) + asoc->highest_tsn_inside_map + 7) / 8;
|
||||
siz = (((MAX_TSN - highest_tsn) + 1) + highest_tsn + 7) / 8;
|
||||
|
||||
if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) {
|
||||
offset = 1;
|
||||
@ -10063,10 +10058,10 @@ sctp_send_sack(struct sctp_tcb *stcb)
|
||||
*/
|
||||
jstart = 1;
|
||||
}
|
||||
if (compare_with_wrap(asoc->highest_tsn_inside_map, asoc->cumulative_tsn, MAX_TSN)) {
|
||||
if (compare_with_wrap(highest_tsn, asoc->cumulative_tsn, MAX_TSN)) {
|
||||
/* we have a gap .. maybe */
|
||||
for (i = 0; i < siz; i++) {
|
||||
selector = &sack_array[asoc->mapping_array[i]];
|
||||
selector = &sack_array[(asoc->mapping_array[i] | asoc->nr_mapping_array[i])];
|
||||
if (mergeable && selector->right_edge) {
|
||||
/*
|
||||
* Backup, left and right edges were ok to
|
||||
@ -10120,8 +10115,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
|
||||
*/
|
||||
int abort_flag = 0;
|
||||
|
||||
asoc->cumulative_tsn = asoc->highest_tsn_inside_map;
|
||||
sack->sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
|
||||
sctp_sack_check(stcb, 0, 0, &abort_flag);
|
||||
}
|
||||
}
|
||||
@ -10180,13 +10173,13 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
int mergeable = 0;
|
||||
int offset;
|
||||
caddr_t limit;
|
||||
uint32_t *dup;
|
||||
uint32_t *dup, highest_tsn;
|
||||
int limit_reached = 0;
|
||||
int seen_non_zero = 0;
|
||||
unsigned int i, jstart, siz, j;
|
||||
unsigned int num_gap_blocks = 0, num_nr_gap_blocks = 0, space;
|
||||
int num_dups = 0;
|
||||
int space_req;
|
||||
unsigned int reserved = 0;
|
||||
|
||||
a_chk = NULL;
|
||||
asoc = &stcb->asoc;
|
||||
@ -10272,7 +10265,12 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
if (a_chk->whoTo) {
|
||||
atomic_add_int(&a_chk->whoTo->ref_count, 1);
|
||||
}
|
||||
if (asoc->highest_tsn_inside_map == asoc->cumulative_tsn) {
|
||||
if (compare_with_wrap(asoc->highest_tsn_inside_map, asoc->highest_tsn_inside_nr_map, MAX_TSN)) {
|
||||
highest_tsn = asoc->highest_tsn_inside_map;
|
||||
} else {
|
||||
highest_tsn = asoc->highest_tsn_inside_nr_map;
|
||||
}
|
||||
if (highest_tsn == asoc->cumulative_tsn) {
|
||||
/* no gaps */
|
||||
space_req = sizeof(struct sctp_nr_sack_chunk);
|
||||
} else {
|
||||
@ -10371,6 +10369,7 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
if (compare_with_wrap(asoc->highest_tsn_inside_map, asoc->cumulative_tsn, MAX_TSN)) {
|
||||
/* we have a gap .. maybe */
|
||||
for (i = 0; i < siz; i++) {
|
||||
seen_non_zero = 1;
|
||||
selector = &sack_array[asoc->mapping_array[i]];
|
||||
if (mergeable && selector->right_edge) {
|
||||
/*
|
||||
@ -10418,22 +10417,8 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
jstart = 0;
|
||||
offset += 8;
|
||||
}
|
||||
if (num_gap_blocks == 0) {
|
||||
/*
|
||||
* slide not yet happened, and somehow we got called
|
||||
* to send a sack. Cumack needs to move up.
|
||||
*/
|
||||
int abort_flag = 0;
|
||||
|
||||
asoc->cumulative_tsn = asoc->highest_tsn_inside_map;
|
||||
nr_sack->nr_sack.cum_tsn_ack = htonl(asoc->cumulative_tsn);
|
||||
sctp_sack_check(stcb, 0, 0, &abort_flag);
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------filling the nr_gap_ack blocks----------------------------------------------------*/
|
||||
|
||||
/* EY - there will be gaps + nr_gaps if draining is possible */
|
||||
if ((SCTP_BASE_SYSCTL(sctp_do_drain)) && (limit_reached == 0)) {
|
||||
if (limit_reached == 0) {
|
||||
|
||||
mergeable = 0;
|
||||
|
||||
@ -10510,9 +10495,6 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------End of---filling the nr_gap_ack blocks----------------------------------------------------*/
|
||||
|
||||
/* now we must add any dups we are going to report. */
|
||||
if ((limit_reached == 0) && (asoc->numduptsns)) {
|
||||
dup = (uint32_t *) gap_descriptor;
|
||||
for (i = 0; i < asoc->numduptsns; i++) {
|
||||
@ -10530,10 +10512,6 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
* now that the chunk is prepared queue it to the control chunk
|
||||
* queue.
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) {
|
||||
num_nr_gap_blocks = num_gap_blocks;
|
||||
num_gap_blocks = 0;
|
||||
}
|
||||
a_chk->send_size = sizeof(struct sctp_nr_sack_chunk) +
|
||||
(num_gap_blocks + num_nr_gap_blocks) * sizeof(struct sctp_gap_ack_block) +
|
||||
num_dups * sizeof(int32_t);
|
||||
@ -10542,7 +10520,7 @@ sctp_send_nr_sack(struct sctp_tcb *stcb)
|
||||
nr_sack->nr_sack.num_gap_ack_blks = htons(num_gap_blocks);
|
||||
nr_sack->nr_sack.num_nr_gap_ack_blks = htons(num_nr_gap_blocks);
|
||||
nr_sack->nr_sack.num_dup_tsns = htons(num_dups);
|
||||
nr_sack->nr_sack.reserved = htons(reserved);
|
||||
nr_sack->nr_sack.reserved = 0;
|
||||
nr_sack->ch.chunk_length = htons(a_chk->send_size);
|
||||
TAILQ_INSERT_TAIL(&asoc->control_send_queue, a_chk, sctp_next);
|
||||
asoc->ctrl_queue_cnt++;
|
||||
|
@ -1175,7 +1175,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
asoc->discontinuity_time = asoc->start_time;
|
||||
/*
|
||||
* sa_ignore MEMLEAK {memory is put in the assoc mapping array and
|
||||
* freed later whe the association is freed.
|
||||
* freed later when the association is freed.
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
@ -1183,7 +1183,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
void
|
||||
sctp_print_mapping_array(struct sctp_association *asoc)
|
||||
{
|
||||
int i;
|
||||
int i, limit;
|
||||
|
||||
printf("Mapping size:%d baseTSN:%8.8x cumAck:%8.8x highestTSN:%8.8x\n",
|
||||
asoc->mapping_array_size,
|
||||
@ -1191,9 +1191,39 @@ sctp_print_mapping_array(struct sctp_association *asoc)
|
||||
asoc->cumulative_tsn,
|
||||
asoc->highest_tsn_inside_map
|
||||
);
|
||||
for (i = 0; i < asoc->mapping_array_size; i++) {
|
||||
printf("%8.8x ", asoc->mapping_array[i]);
|
||||
if (((i + 1) % 8) == 0)
|
||||
limit = asoc->mapping_array_size;
|
||||
for (i = asoc->mapping_array_size; i >= 0; i--) {
|
||||
if (asoc->mapping_array[i]) {
|
||||
limit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (limit == 0)
|
||||
limit = 1;
|
||||
for (i = 0; i < limit; i++) {
|
||||
printf("%2.2x ", asoc->mapping_array[i]);
|
||||
if (((i + 1) % 16) == 0)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
printf("NR Mapping size:%d baseTSN:%8.8x highestTSN:%8.8x\n",
|
||||
asoc->nr_mapping_array_size,
|
||||
asoc->nr_mapping_array_base_tsn,
|
||||
asoc->highest_tsn_inside_nr_map
|
||||
);
|
||||
limit = asoc->nr_mapping_array_size;
|
||||
for (i = asoc->nr_mapping_array_size; i >= 0; i--) {
|
||||
if (asoc->nr_mapping_array[i]) {
|
||||
limit = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (limit == 0)
|
||||
limit = 1;
|
||||
|
||||
for (i = 0; i < limit; i++) {
|
||||
printf("%2.2x ", asoc->nr_mapping_array[i]);
|
||||
if (((i + 1) % 16) == 0)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
Loading…
Reference in New Issue
Block a user