svn commit: r206137 - in head/sys: netinet netinet6
Michael Tuexen
tuexen at FreeBSD.org
Sat Apr 3 15:40:14 UTC 2010
Author: tuexen
Date: Sat Apr 3 15:40:14 2010
New Revision: 206137
URL: http://svn.freebsd.org/changeset/base/206137
Log:
* Fix some race condition in SACK/NR-SACK processing.
* Fix handling of mapping arrays when draining mbufs or processing
FORWARD-TSN chunks.
* Cleanup code (no duplicate code anymore for SACKs and NR-SACKs).
Part of this code was developed together with rrs.
MFC after: 2 weeks.
Modified:
head/sys/netinet/sctp_asconf.c
head/sys/netinet/sctp_constants.h
head/sys/netinet/sctp_indata.c
head/sys/netinet/sctp_indata.h
head/sys/netinet/sctp_input.c
head/sys/netinet/sctp_output.c
head/sys/netinet/sctp_output.h
head/sys/netinet/sctp_pcb.c
head/sys/netinet/sctp_pcb.h
head/sys/netinet/sctp_structs.h
head/sys/netinet/sctp_usrreq.c
head/sys/netinet/sctp_var.h
head/sys/netinet/sctputil.c
head/sys/netinet/sctputil.h
head/sys/netinet6/sctp6_usrreq.c
Modified: head/sys/netinet/sctp_asconf.c
==============================================================================
--- head/sys/netinet/sctp_asconf.c Sat Apr 3 12:34:32 2010 (r206136)
+++ head/sys/netinet/sctp_asconf.c Sat Apr 3 15:40:14 2010 (r206137)
@@ -556,9 +556,9 @@ sctp_process_asconf_set_primary(struct m
* PRIMARY with DELETE IP ADDRESS of the previous primary
* destination, unacknowledged DATA are retransmitted
* immediately to the new primary destination for seamless
- * handover. If the destination is UNCONFIRMED and marked
- * to REQ_PRIM, The retransmission occur when reception of
- * the HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in
+ * handover. If the destination is UNCONFIRMED and marked to
+ * REQ_PRIM, The retransmission occur when reception of the
+ * HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in
* sctp_input.c) Also, when change of the primary
* destination, it is better that all subsequent new DATA
* containing already queued DATA are transmitted to the new
@@ -1166,7 +1166,7 @@ sctp_path_check_and_react(struct sctp_tc
/*
* If number of local valid addresses is 1, the valid address is
- * probably newly added address. Several valid addresses in this
+ * probably newly added address. Several valid addresses in this
* association. A source address may not be changed. Additionally,
* they can be configured on a same interface as "alias" addresses.
* (by micchie)
@@ -1210,7 +1210,7 @@ sctp_path_check_and_react(struct sctp_tc
/*
* Check if the nexthop is corresponding to the new address.
* If the new address is corresponding to the current
- * nexthop, the path will be changed. If the new address is
+ * nexthop, the path will be changed. If the new address is
* NOT corresponding to the current nexthop, the path will
* not be changed.
*/
Modified: head/sys/netinet/sctp_constants.h
==============================================================================
--- head/sys/netinet/sctp_constants.h Sat Apr 3 12:34:32 2010 (r206136)
+++ head/sys/netinet/sctp_constants.h Sat Apr 3 15:40:14 2010 (r206137)
@@ -544,13 +544,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_INITIAL_MAPPING_ARRAY 16
/* how much we grow the mapping array each call */
#define SCTP_MAPPING_ARRAY_INCR 32
-/* EY 05/13/08 - nr_sack version of the previous 3 constants */
-/* Maximum the nr mapping array will grow to (TSN mapping array) */
-#define SCTP_NR_MAPPING_ARRAY 512
-/* size of the inital malloc on the nr mapping array */
-#define SCTP_INITIAL_NR_MAPPING_ARRAY 16
-/* how much we grow the nr mapping array each call */
-#define SCTP_NR_MAPPING_ARRAY_INCR 32
+
/*
* Here we define the timer types used by the implementation as arguments in
* the set/get timer type calls.
@@ -933,6 +927,13 @@ __FBSDID("$FreeBSD$");
#define SCTP_IS_TSN_PRESENT(arry, gap) ((arry[(gap >> 3)] >> (gap & 0x07)) & 0x01)
#define SCTP_SET_TSN_PRESENT(arry, gap) (arry[(gap >> 3)] |= (0x01 << ((gap & 0x07))))
#define SCTP_UNSET_TSN_PRESENT(arry, gap) (arry[(gap >> 3)] &= ((~(0x01 << ((gap & 0x07)))) & 0xff))
+#define SCTP_CALC_TSN_TO_GAP(gap, tsn, mapping_tsn) do { \
+ if (tsn >= mapping_tsn) { \
+ gap = tsn - mapping_tsn; \
+ } else { \
+ gap = (MAX_TSN - mapping_tsn) + tsn + 1; \
+ } \
+ } while(0)
#define SCTP_RETRAN_DONE -1
Modified: head/sys/netinet/sctp_indata.c
==============================================================================
--- head/sys/netinet/sctp_indata.c Sat Apr 3 12:34:32 2010 (r206136)
+++ head/sys/netinet/sctp_indata.c Sat Apr 3 15:40:14 2010 (r206137)
@@ -45,13 +45,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_uio.h>
#include <netinet/sctp_timer.h>
-#define SCTP_CALC_TSN_TO_GAP(gap, tsn, mapping_tsn) do { \
- if (tsn >= mapping_tsn) { \
- gap = tsn - mapping_tsn; \
- } else { \
- gap = (MAX_TSN - mapping_tsn) + tsn + 1; \
- } \
- } while(0)
/*
* NOTES: On the outbound side of things I need to check the sack timer to
@@ -303,13 +296,13 @@ sctp_mark_non_revokable(struct sctp_asso
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);
+#ifdef INVARIANTS
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)) {
@@ -317,7 +310,8 @@ sctp_mark_non_revokable(struct sctp_asso
}
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--) {
+ for (i = tsn - 1; (compare_with_wrap(i, asoc->mapping_array_base_tsn, MAX_TSN) ||
+ (i == asoc->mapping_array_base_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;
@@ -411,6 +405,7 @@ abandon:
end = 1;
else
end = 0;
+ sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
sctp_add_to_readq(stcb->sctp_ep,
stcb, control, &stcb->sctp_socket->so_rcv, end,
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
@@ -420,6 +415,7 @@ abandon:
end = 1;
else
end = 0;
+ sctp_mark_non_revokable(asoc, chk->rec.data.TSN_seq);
if (sctp_append_to_readq(stcb->sctp_ep, stcb,
stcb->asoc.control_pdapi,
chk->data, end, chk->rec.data.TSN_seq,
@@ -454,7 +450,6 @@ abandon:
}
/* pull it we did it */
TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
- 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) {
@@ -501,11 +496,11 @@ abandon:
asoc->size_on_all_streams -= ctl->length;
sctp_ucount_decr(asoc->cnt_on_all_streams);
strm->last_sequence_delivered++;
+ sctp_mark_non_revokable(asoc, 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);
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
ctl = ctlat;
} else {
break;
@@ -616,11 +611,11 @@ protocol_error:
sctp_ucount_decr(asoc->cnt_on_all_streams);
strm->last_sequence_delivered++;
+ sctp_mark_non_revokable(asoc, 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);
- sctp_mark_non_revokable(asoc, control->sinfo_tsn);
control = TAILQ_FIRST(&strm->inqueue);
while (control != NULL) {
/* all delivered */
@@ -641,13 +636,12 @@ protocol_error:
sctp_log_strm_del(control, NULL,
SCTP_STR_LOG_FROM_IMMED_DEL);
}
- /* EY will be used to calculate nr-gap */
+ sctp_mark_non_revokable(asoc, 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);
- sctp_mark_non_revokable(asoc, control->sinfo_tsn);
control = at;
continue;
}
@@ -965,8 +959,7 @@ sctp_queue_data_for_reasm(struct sctp_tc
*abort_flag = 1;
} else if ((asoc->fragment_flags & SCTP_DATA_UNORDERED) !=
SCTP_DATA_UNORDERED &&
- chk->rec.data.stream_seq !=
- asoc->ssn_of_pdapi) {
+ chk->rec.data.stream_seq != asoc->ssn_of_pdapi) {
/* Got to be the right STR Seq */
SCTPDBG(SCTP_DEBUG_INDATA1, "Gak, Evil plot, it IS not same stream seq %d vs %d\n",
chk->rec.data.stream_seq,
@@ -1623,7 +1616,6 @@ sctp_process_a_data_chunk(struct sctp_tc
}
SCTP_STAT_INCR(sctps_badsid);
SCTP_TCB_LOCK_ASSERT(stcb);
-
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;
@@ -1787,6 +1779,7 @@ sctp_process_a_data_chunk(struct sctp_tc
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;
@@ -1853,10 +1846,6 @@ failed_express_del:
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;
}
@@ -2059,10 +2048,10 @@ failed_pdapi_express_del:
/* ok, if we reach here we have passed the sanity checks */
if (chunk_flags & SCTP_DATA_UNORDERED) {
/* queue directly into socket buffer */
+ sctp_mark_non_revokable(asoc, 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);
-
} else {
/*
* Special check for when streams are resetting. We
@@ -2134,10 +2123,6 @@ failed_pdapi_express_del:
}
}
finish_express_del:
- if (tsn == (asoc->cumulative_tsn + 1)) {
- /* Update cum-ack */
- asoc->cumulative_tsn = tsn;
- }
if (last_chunk) {
*m = NULL;
}
@@ -2215,43 +2200,43 @@ finish_express_del:
}
int8_t sctp_map_lookup_tab[256] = {
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 4,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 5,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 4,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 6,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 4,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 5,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 4,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 3,
- -1, 0, -1, 1, -1, 0, -1, 2,
- -1, 0, -1, 1, -1, 0, -1, 7,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 5,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 6,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 5,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 7,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 5,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 6,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 5,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 4,
+ 0, 1, 0, 2, 0, 1, 0, 3,
+ 0, 1, 0, 2, 0, 1, 0, 8
};
void
-sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort_flag)
+sctp_slide_mapping_arrays(struct sctp_tcb *stcb)
{
/*
* Now we also need to check the mapping array in a couple of ways.
@@ -2259,7 +2244,6 @@ sctp_sack_check(struct sctp_tcb *stcb, i
*/
struct sctp_association *asoc;
int at;
- int last_all_ones = 0;
int slide_from, slide_end, lgap, distance;
/* EY nr_mapping array variables */
@@ -2279,19 +2263,16 @@ sctp_sack_check(struct sctp_tcb *stcb, i
* offset of the current cum-ack as the starting point.
*/
at = 0;
- for (slide_from = 0; slide_from < stcb->asoc.nr_mapping_array_size; slide_from++) {
+ for (slide_from = 0; slide_from < stcb->asoc.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[asoc->nr_mapping_array[slide_from]];
- last_all_ones = 0;
break;
}
}
- asoc->cumulative_tsn = asoc->nr_mapping_array_base_tsn + (at - last_all_ones);
- at++;
+ asoc->cumulative_tsn = asoc->mapping_array_base_tsn + (at - 1);
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)
@@ -2320,18 +2301,22 @@ sctp_sack_check(struct sctp_tcb *stcb, i
if ((asoc->cumulative_tsn == highest_tsn) && (at >= 8)) {
/* The complete array was completed by a single FR */
/* highest becomes the cum-ack */
- int clr;
+ int clr, i;
/* clear the array */
- clr = (at >> 3) + 1;
+ clr = ((at + 7) >> 3);
if (clr > asoc->mapping_array_size) {
clr = asoc->mapping_array_size;
}
memset(asoc->mapping_array, 0, clr);
memset(asoc->nr_mapping_array, 0, clr);
-
+ for (i = 0; i < asoc->mapping_array_size; i++) {
+ if ((asoc->mapping_array[i]) || (asoc->nr_mapping_array[i])) {
+ printf("Error Mapping array's not clean at clear\n");
+ sctp_print_mapping_array(asoc);
+ }
+ }
asoc->mapping_array_base_tsn = asoc->cumulative_tsn + 1;
- 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 */
@@ -2393,12 +2378,11 @@ sctp_sack_check(struct sctp_tcb *stcb, i
asoc->nr_mapping_array[slide_from + ii];
}
- for (ii = distance; ii <= slide_end; ii++) {
+ for (ii = distance; ii <= asoc->mapping_array_size; 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,
@@ -2406,95 +2390,95 @@ sctp_sack_check(struct sctp_tcb *stcb, i
}
}
}
+}
+
+
+void
+sctp_sack_check(struct sctp_tcb *stcb, int was_a_gap, int *abort_flag)
+{
+ struct sctp_association *asoc;
+ uint32_t highest_tsn;
+
+ asoc = &stcb->asoc;
+ 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;
+ }
+
/*
* Now we need to see if we need to queue a sack or just start the
* timer (if allowed).
*/
- if (ok_to_sack) {
- if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
- /*
- * Ok special case, in SHUTDOWN-SENT case. here we
- * maker sure SACK timer is off and instead send a
- * SHUTDOWN and a SACK
- */
- if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
- sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18);
- }
- sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
- /*
- * EY if nr_sacks used then send an nr-sack , a sack
- * otherwise
- */
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)
- sctp_send_nr_sack(stcb);
- else
- sctp_send_sack(stcb);
- } else {
- int is_a_gap;
+ if (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_SENT) {
+ /*
+ * Ok special case, in SHUTDOWN-SENT case. here we maker
+ * sure SACK timer is off and instead send a SHUTDOWN and a
+ * SACK
+ */
+ if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
+ sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
+ stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_INDATA + SCTP_LOC_18);
+ }
+ sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
+ sctp_send_sack(stcb);
+ } else {
+ int is_a_gap;
- /* is there a gap now ? */
- is_a_gap = compare_with_wrap(highest_tsn, stcb->asoc.cumulative_tsn, MAX_TSN);
+ /* is there a gap now ? */
+ is_a_gap = compare_with_wrap(highest_tsn, stcb->asoc.cumulative_tsn, MAX_TSN);
- /*
- * CMT DAC algorithm: increase number of packets
- * received since last ack
- */
- stcb->asoc.cmt_dac_pkts_rcvd++;
+ /*
+ * CMT DAC algorithm: increase number of packets received
+ * since last ack
+ */
+ stcb->asoc.cmt_dac_pkts_rcvd++;
- if ((stcb->asoc.send_sack == 1) || /* We need to send a
- * SACK */
- ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no
- * longer is one */
- (stcb->asoc.numduptsns) || /* we have dup's */
- (is_a_gap) || /* is still a gap */
- (stcb->asoc.delayed_ack == 0) || /* Delayed sack disabled */
- (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq) /* hit limit of pkts */
- ) {
+ if ((stcb->asoc.send_sack == 1) || /* We need to send a
+ * SACK */
+ ((was_a_gap) && (is_a_gap == 0)) || /* was a gap, but no
+ * longer is one */
+ (stcb->asoc.numduptsns) || /* we have dup's */
+ (is_a_gap) || /* is still a gap */
+ (stcb->asoc.delayed_ack == 0) || /* Delayed sack disabled */
+ (stcb->asoc.data_pkts_seen >= stcb->asoc.sack_freq) /* hit limit of pkts */
+ ) {
- if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off)) &&
- (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) &&
- (stcb->asoc.send_sack == 0) &&
- (stcb->asoc.numduptsns == 0) &&
- (stcb->asoc.delayed_ack) &&
- (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) {
+ if ((SCTP_BASE_SYSCTL(sctp_cmt_on_off)) &&
+ (SCTP_BASE_SYSCTL(sctp_cmt_use_dac)) &&
+ (stcb->asoc.send_sack == 0) &&
+ (stcb->asoc.numduptsns == 0) &&
+ (stcb->asoc.delayed_ack) &&
+ (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer))) {
- /*
- * CMT DAC algorithm: With CMT,
- * delay acks even in the face of
- *
- * reordering. Therefore, if acks that
- * do not have to be sent because of
- * the above reasons, will be
- * delayed. That is, acks that would
- * have been sent due to gap reports
- * will be delayed with DAC. Start
- * the delayed ack timer.
- */
- sctp_timer_start(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL);
- } else {
- /*
- * Ok we must build a SACK since the
- * timer is pending, we got our
- * first packet OR there are gaps or
- * duplicates.
- */
- (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
- /*
- * EY if nr_sacks used then send an
- * nr-sack , a sack otherwise
- */
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)
- sctp_send_nr_sack(stcb);
- else
- sctp_send_sack(stcb);
- }
+ /*
+ * CMT DAC algorithm: With CMT, delay acks
+ * even in the face of
+ *
+ * reordering. Therefore, if acks that do not
+ * have to be sent because of the above
+ * reasons, will be delayed. That is, acks
+ * that would have been sent due to gap
+ * reports will be delayed with DAC. Start
+ * the delayed ack timer.
+ */
+ sctp_timer_start(SCTP_TIMER_TYPE_RECV,
+ stcb->sctp_ep, stcb, NULL);
} else {
- if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
- sctp_timer_start(SCTP_TIMER_TYPE_RECV,
- stcb->sctp_ep, stcb, NULL);
- }
+ /*
+ * Ok we must build a SACK since the timer
+ * is pending, we got our first packet OR
+ * there are gaps or duplicates.
+ */
+ (void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
+ sctp_send_sack(stcb);
+ }
+ } else {
+ if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
+ sctp_timer_start(SCTP_TIMER_TYPE_RECV,
+ stcb->sctp_ep, stcb, NULL);
}
}
}
@@ -2834,14 +2818,7 @@ sctp_process_data(struct mbuf **mm, int
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
(void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
}
- /*
- * EY if nr_sacks used then send an nr-sack , a sack
- * otherwise
- */
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && stcb->asoc.peer_supports_nr_sack)
- sctp_send_nr_sack(stcb);
- else
- sctp_send_sack(stcb);
+ sctp_send_sack(stcb);
} else {
if (!SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
sctp_timer_start(SCTP_TIMER_TYPE_RECV,
@@ -2849,7 +2826,7 @@ sctp_process_data(struct mbuf **mm, int
}
}
} else {
- sctp_sack_check(stcb, 1, was_a_gap, &abort_flag);
+ sctp_sack_check(stcb, was_a_gap, &abort_flag);
}
if (abort_flag)
return (2);
@@ -2867,7 +2844,7 @@ sctp_process_segment_range(struct sctp_t
{
struct sctp_tmit_chunk *tp1;
unsigned int theTSN;
- int j, wake_him = 0;
+ int j, wake_him = 0, circled = 0;
/* Recover the tp1 we last saw */
tp1 = *p_tp1;
@@ -3045,12 +3022,6 @@ sctp_process_segment_range(struct sctp_t
}
/* NR Sack code here */
if (nr_sacking) {
- if (tp1->sent != SCTP_FORWARD_TSN_SKIP)
- tp1->sent = SCTP_DATAGRAM_NR_MARKED;
- /*
- * TAILQ_REMOVE(&asoc->sent_q
- * ueue, tp1, sctp_next);
- */
if (tp1->data) {
/*
* sa_ignore
@@ -3058,13 +3029,8 @@ sctp_process_segment_range(struct sctp_t
*/
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
sctp_m_freem(tp1->data);
+ tp1->data = NULL;
}
- tp1->data = NULL;
- /* asoc->sent_queue_cnt--; */
- /*
- * sctp_free_a_chunk(stcb,
- * tp1);
- */
wake_him++;
}
}
@@ -3075,11 +3041,16 @@ sctp_process_segment_range(struct sctp_t
break;
tp1 = TAILQ_NEXT(tp1, sctp_next);
+ if ((tp1 == NULL) && (circled == 0)) {
+ circled++;
+ tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
+ }
} /* end while (tp1) */
- /* In case the fragments were not in order we must reset */
if (tp1 == NULL) {
+ circled = 0;
tp1 = TAILQ_FIRST(&stcb->asoc.sent_queue);
}
+ /* In case the fragments were not in order we must reset */
} /* end for (j = fragStart */
*p_tp1 = tp1;
return (wake_him); /* Return value only used for nr-sack */
@@ -3158,6 +3129,9 @@ sctp_handle_segments(struct mbuf *m, int
} else {
non_revocable = 1;
}
+ if (i == num_seg) {
+ tp1 = NULL;
+ }
if (sctp_process_segment_range(stcb, &tp1, last_tsn, frag_strt, frag_end,
non_revocable, &num_frs, biggest_newly_acked_tsn,
this_sack_lowest_newack, ecn_seg_sums)) {
@@ -3961,6 +3935,7 @@ sctp_express_handle_sack(struct sctp_tcb
#ifdef INVARIANTS
panic("Impossible sack 1");
#else
+
*abort_now = 1;
/* XXX */
oper = sctp_get_mbuf_for_msg((sizeof(struct sctp_paramhdr) + sizeof(uint32_t)),
@@ -4439,50 +4414,6 @@ again:
}
}
-/* EY- nr_sack */
-/* Identifies the non-renegable tsns that are revoked*/
-static void
-sctp_check_for_nr_revoked(struct sctp_tcb *stcb,
- struct sctp_association *asoc, uint32_t cumack,
- uint32_t biggest_tsn_acked)
-{
- struct sctp_tmit_chunk *tp1;
-
- for (tp1 = TAILQ_FIRST(&asoc->sent_queue); tp1; tp1 = TAILQ_NEXT(tp1, sctp_next)) {
- if (compare_with_wrap(tp1->rec.data.TSN_seq, cumack,
- MAX_TSN)) {
- /*
- * ok this guy is either ACK or MARKED. If it is
- * ACKED it has been previously acked but not this
- * time i.e. revoked. If it is MARKED it was ACK'ed
- * again.
- */
- if (compare_with_wrap(tp1->rec.data.TSN_seq, biggest_tsn_acked,
- MAX_TSN))
- break;
-
-
- if (tp1->sent == SCTP_DATAGRAM_NR_ACKED) {
- /*
- * EY! a non-renegable TSN is revoked, need
- * to abort the association
- */
- /*
- * EY TODO: put in the code to abort the
- * assoc.
- */
- return;
- } else if (tp1->sent == SCTP_DATAGRAM_NR_MARKED) {
- /* it has been re-acked in this SACK */
- tp1->sent = SCTP_DATAGRAM_NR_ACKED;
- }
- }
- if (tp1->sent == SCTP_DATAGRAM_UNSENT)
- break;
- }
- return;
-}
-
void
sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
struct sctp_tcb *stcb, struct sctp_nets *net_from,
@@ -4588,22 +4519,23 @@ sctp_handle_sack(struct mbuf *m, int off
sctpchunk_listhead);
send_s = tp1->rec.data.TSN_seq + 1;
} else {
+ tp1 = NULL;
send_s = asoc->sending_seq;
}
if (cum_ack == send_s ||
compare_with_wrap(cum_ack, send_s, MAX_TSN)) {
-#ifndef INVARIANTS
struct mbuf *oper;
-#endif
-#ifdef INVARIANTS
- hopeless_peer:
- panic("Impossible sack 1");
-#else
/*
* no way, we have not even sent this TSN out yet.
* Peer is hopelessly messed up with us.
*/
+ printf("NEW cum_ack:%x send_s:%x is smaller or equal\n",
+ cum_ack, send_s);
+ if (tp1) {
+ printf("Got send_s from tsn:%x + 1 of tp1:%p\n",
+ tp1->rec.data.TSN_seq, tp1);
+ }
hopeless_peer:
*abort_now = 1;
/* XXX */
@@ -4624,7 +4556,6 @@ sctp_handle_sack(struct mbuf *m, int off
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
return;
-#endif
}
}
/**********************/
@@ -4844,6 +4775,10 @@ sctp_handle_sack(struct mbuf *m, int off
* peer is either confused or we are under
* attack. We must abort.
*/
+ printf("Hopeless peer! biggest_tsn_acked:%x largest seq:%x\n",
+ biggest_tsn_acked,
+ send_s);
+
goto hopeless_peer;
}
}
@@ -4991,15 +4926,9 @@ done_with_it:
*/
if ((tp1->sent == SCTP_DATAGRAM_NR_ACKED) ||
(tp1->sent == SCTP_DATAGRAM_NR_MARKED)) {
- /*
- * EY! - TODO: Something previously
- * nr_gapped is reneged, abort the
- * association
- */
- return;
+ continue;
}
- if ((tp1->sent > SCTP_DATAGRAM_RESEND) &&
- (tp1->sent < SCTP_FORWARD_TSN_SKIP)) {
+ if (tp1->sent == SCTP_DATAGRAM_ACKED) {
tp1->sent = SCTP_DATAGRAM_SENT;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) {
sctp_misc_ints(SCTP_FLIGHT_LOG_UP_REVOKE,
@@ -5028,15 +4957,11 @@ done_with_it:
}
asoc->saw_sack_with_frags = 0;
}
- if (num_seg)
+ if (num_seg || num_nr_seg)
asoc->saw_sack_with_frags = 1;
else
asoc->saw_sack_with_frags = 0;
- /* EY! - not sure about if there should be an IF */
- if (num_nr_seg > 0)
- sctp_check_for_nr_revoked(stcb, asoc, cum_ack, biggest_tsn_acked);
-
/* JRS - Use the congestion control given in the CC module */
asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
@@ -5457,11 +5382,10 @@ sctp_kick_prsctp_reorder_queue(struct sc
sctp_ucount_decr(asoc->cnt_on_all_streams);
/* deliver it to at least the delivery-q */
if (stcb->sctp_socket) {
- /* EY need the tsn info for calculating nr */
+ sctp_mark_non_revokable(asoc, 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);
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
}
} else {
/* no more delivery now. */
@@ -5486,10 +5410,10 @@ sctp_kick_prsctp_reorder_queue(struct sc
/* deliver it to at least the delivery-q */
strmin->last_sequence_delivered = ctl->sinfo_ssn;
if (stcb->sctp_socket) {
+ sctp_mark_non_revokable(asoc, 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);
- sctp_mark_non_revokable(asoc, ctl->sinfo_tsn);
}
tt = strmin->last_sequence_delivered + 1;
@@ -5593,7 +5517,8 @@ sctp_flush_reassm_for_str_seq(struct sct
void
sctp_handle_forward_tsn(struct sctp_tcb *stcb,
- struct sctp_forward_tsn_chunk *fwd, int *abort_flag, struct mbuf *m, int offset)
+ struct sctp_forward_tsn_chunk *fwd,
+ int *abort_flag, struct mbuf *m, int offset)
{
/*
* ISSUES that MUST be fixed for ECN! When we are the sender of the
@@ -5619,8 +5544,8 @@ sctp_handle_forward_tsn(struct sctp_tcb
* report where we are.
*/
struct sctp_association *asoc;
- uint32_t new_cum_tsn, gap;
- unsigned int i, fwd_sz, cumack_set_flag, m_size;
+ uint32_t new_cum_tsn, tsn, gap;
+ unsigned int i, fwd_sz, cumack_set_flag, m_size, fnd = 0;
uint32_t str_seq;
struct sctp_stream_in *strm;
struct sctp_tmit_chunk *chk, *at;
@@ -5657,7 +5582,7 @@ sctp_handle_forward_tsn(struct sctp_tcb
* 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->nr_mapping_array_base_tsn);
+ SCTP_CALC_TSN_TO_GAP(gap, new_cum_tsn, asoc->mapping_array_base_tsn);
asoc->cumulative_tsn = new_cum_tsn;
if (gap >= m_size) {
if ((long)gap > sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv)) {
@@ -5697,8 +5622,7 @@ sctp_handle_forward_tsn(struct sctp_tcb
asoc->mapping_array_base_tsn = new_cum_tsn + 1;
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;
+ memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size);
asoc->highest_tsn_inside_nr_map = new_cum_tsn;
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MAP_LOGGING_ENABLE) {
@@ -5710,14 +5634,32 @@ sctp_handle_forward_tsn(struct sctp_tcb
for (i = 0; i <= gap; i++) {
SCTP_UNSET_TSN_PRESENT(asoc->mapping_array, i);
SCTP_SET_TSN_PRESENT(asoc->nr_mapping_array, i);
+ /* FIX ME add something to set up highest TSN in map */
+ }
+ 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 (compare_with_wrap(new_cum_tsn, asoc->highest_tsn_inside_map, MAX_TSN) ||
+ new_cum_tsn == asoc->highest_tsn_inside_map) {
+ /* We must back down to see what the new highest is */
+ for (tsn = new_cum_tsn; (compare_with_wrap(tsn, asoc->mapping_array_base_tsn, MAX_TSN) ||
+ (tsn == asoc->mapping_array_base_tsn)); tsn--) {
+ SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
+ if (SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) {
+ asoc->highest_tsn_inside_map = tsn;
+ fnd = 1;
+ break;
+ }
+ }
+ if (!fnd) {
+ asoc->highest_tsn_inside_map = asoc->mapping_array_base_tsn - 1;
+ }
}
/*
* Now after marking all, slide thing forward but no sack
* please.
*/
- sctp_sack_check(stcb, 0, 0, abort_flag);
- if (*abort_flag)
- return;
+ sctp_slide_mapping_arrays(stcb);
}
/*************************************************************/
/* 2. Clear up re-assembly queue */
Modified: head/sys/netinet/sctp_indata.h
==============================================================================
--- head/sys/netinet/sctp_indata.h Sat Apr 3 12:34:32 2010 (r206136)
+++ head/sys/netinet/sctp_indata.h Sat Apr 3 15:40:14 2010 (r206137)
@@ -121,7 +121,9 @@ sctp_process_data(struct mbuf **, int, i
struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *, uint32_t *);
-void sctp_sack_check(struct sctp_tcb *, int, int, int *);
+void sctp_slide_mapping_arrays(struct sctp_tcb *stcb);
+
+void sctp_sack_check(struct sctp_tcb *, int, int *);
#endif
#endif
Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c Sat Apr 3 12:34:32 2010 (r206136)
+++ head/sys/netinet/sctp_input.c Sat Apr 3 15:40:14 2010 (r206137)
@@ -343,11 +343,6 @@ sctp_process_init(struct sctp_init_chunk
asoc->str_reset_seq_in = asoc->asconf_seq_in + 1;
asoc->mapping_array_base_tsn = ntohl(init->initial_tsn);
- /*
- * EY 05/13/08 - nr_sack: initialize nr_mapping array's base tsn
- * like above
- */
- asoc->nr_mapping_array_base_tsn = ntohl(init->initial_tsn);
asoc->tsn_last_delivered = asoc->cumulative_tsn = asoc->asconf_seq_in;
asoc->last_echo_tsn = asoc->asconf_seq_in;
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
@@ -1862,7 +1857,7 @@ sctp_process_cookie_existing(struct mbuf
}
if (asoc->nr_mapping_array) {
memset(asoc->nr_mapping_array, 0,
- asoc->nr_mapping_array_size);
+ asoc->mapping_array_size);
}
SCTP_TCB_UNLOCK(stcb);
SCTP_INP_INFO_WLOCK();
@@ -2027,7 +2022,7 @@ sctp_process_cookie_new(struct mbuf *m,
* socket is unbound and we must do an implicit bind. Since we are
* getting a cookie, we cannot be unbound.
*/
- stcb = sctp_aloc_assoc(inp, init_src, 0, &error,
+ stcb = sctp_aloc_assoc(inp, init_src, &error,
ntohl(initack_cp->init.initiate_tag), vrf_id,
(struct thread *)NULL
);
@@ -3236,13 +3231,10 @@ process_chunk_drop(struct sctp_tcb *stcb
}
break;
case SCTP_SELECTIVE_ACK:
+ case SCTP_NR_SELECTIVE_ACK:
/* resend the sack */
sctp_send_sack(stcb);
break;
- /* EY for nr_sacks */
- case SCTP_NR_SELECTIVE_ACK:
- sctp_send_nr_sack(stcb); /* EY resend the nr-sack */
- break;
case SCTP_HEARTBEAT_REQUEST:
/* resend a demand HB */
if ((stcb->asoc.overall_error_count + 3) < stcb->asoc.max_send_times) {
@@ -3514,8 +3506,7 @@ sctp_handle_stream_reset_response(struct
memset(stcb->asoc.mapping_array, 0, stcb->asoc.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);
+ memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.mapping_array_size);
stcb->asoc.sending_seq = ntohl(resp->receivers_next_tsn);
stcb->asoc.last_acked_seq = stcb->asoc.cumulative_tsn;
@@ -3624,8 +3615,7 @@ sctp_handle_str_reset_request_tsn(struct
stcb->asoc.mapping_array_base_tsn = stcb->asoc.highest_tsn_inside_map + 1;
memset(stcb->asoc.mapping_array, 0, stcb->asoc.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);
+ memset(stcb->asoc.nr_mapping_array, 0, stcb->asoc.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];
@@ -5636,7 +5626,7 @@ sctp_common_input_processing(struct mbuf
was_a_gap = 1;
}
stcb->asoc.send_sack = 1;
- sctp_sack_check(stcb, 1, was_a_gap, &abort_flag);
+ sctp_sack_check(stcb, was_a_gap, &abort_flag);
if (abort_flag) {
/* Again, we aborted so NO UNLOCK needed */
goto out_now;
Modified: head/sys/netinet/sctp_output.c
==============================================================================
--- head/sys/netinet/sctp_output.c Sat Apr 3 12:34:32 2010 (r206136)
+++ head/sys/netinet/sctp_output.c Sat Apr 3 15:40:14 2010 (r206137)
@@ -9003,6 +9003,11 @@ sctp_chunk_retransmission(struct sctp_in
/* No, not sent to this net or not ready for rtx */
continue;
}
+ if (chk->data == NULL) {
+ printf("TSN:%x chk->snd_count:%d chk->sent:%d can't retran - no data\n",
+ chk->rec.data.TSN_seq, chk->snd_count, chk->sent);
+ continue;
+ }
if ((SCTP_BASE_SYSCTL(sctp_max_retran_chunk)) &&
(chk->snd_count >= SCTP_BASE_SYSCTL(sctp_max_retran_chunk))) {
/* Gak, we have exceeded max unlucky retran, abort! */
@@ -9426,14 +9431,7 @@ sctp_chunk_output(struct sctp_inpcb *inp
* running, if so piggy-back the sack.
*/
if (SCTP_OS_TIMER_PENDING(&stcb->asoc.dack_timer.timer)) {
- /*
- * EY if nr_sacks used then send an nr-sack , a sack
- * otherwise
- */
- if (SCTP_BASE_SYSCTL(sctp_nr_sack_on_off) && asoc->peer_supports_nr_sack)
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list