Fixes several PR-SCTP releated bugs.
- When sending large PR-SCTP messages over a lossy link we would incorrectly calculate the fwd-tsn - When receiving large multipart pr-sctp packets we would incorrectly send back a SACK that would renege improperly on already received packets thus causing unneeded retransmissions.
This commit is contained in:
parent
d3df4af368
commit
0c0982b80c
@ -544,7 +544,7 @@ struct sctp_error_unrecognized_chunk {
|
||||
#define SCTP_THRESHOLD_LOGGING 0x02000000
|
||||
#define SCTP_LOG_AT_SEND_2_SCTP 0x04000000
|
||||
#define SCTP_LOG_AT_SEND_2_OUTQ 0x08000000
|
||||
|
||||
#define SCTP_LOG_TRY_ADVANCE 0x10000000
|
||||
|
||||
|
||||
#undef SCTP_PACKED
|
||||
|
@ -229,8 +229,8 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_THRESHOLD_CLEAR 120
|
||||
#define SCTP_THRESHOLD_INCR 121
|
||||
#define SCTP_FLIGHT_LOG_DWN_WP_FWD 122
|
||||
|
||||
#define SCTP_LOG_MAX_TYPES 123
|
||||
#define SCTP_FWD_TSN_CHECK 123
|
||||
#define SCTP_LOG_MAX_TYPES 124
|
||||
/*
|
||||
* To turn on various logging, you must first enable 'options KTR' and
|
||||
* you might want to bump the entires 'options KTR_ENTRIES=80000'.
|
||||
|
@ -3680,7 +3680,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
if (tp1->data != NULL) {
|
||||
(void)sctp_release_pr_sctp_chunk(stcb, tp1,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&asoc->sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
tp1 = TAILQ_NEXT(tp1, sctp_next);
|
||||
continue;
|
||||
@ -3693,7 +3693,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
if (tp1->data != NULL) {
|
||||
(void)sctp_release_pr_sctp_chunk(stcb, tp1,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&asoc->sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
tp1 = TAILQ_NEXT(tp1, sctp_next);
|
||||
continue;
|
||||
@ -4078,6 +4078,13 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
|
||||
/* no chance to advance, out of here */
|
||||
break;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
|
||||
if (tp1->sent == SCTP_FORWARD_TSN_SKIP) {
|
||||
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
|
||||
asoc->advanced_peer_ack_point,
|
||||
tp1->rec.data.TSN_seq, 0, 0);
|
||||
}
|
||||
}
|
||||
if (!PR_SCTP_ENABLED(tp1->flags)) {
|
||||
/*
|
||||
* We can't fwd-tsn past any that are reliable aka
|
||||
@ -4107,7 +4114,7 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
|
||||
if (tp1->data) {
|
||||
(void)sctp_release_pr_sctp_chunk(stcb, tp1,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&asoc->sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -4124,8 +4131,16 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
|
||||
*/
|
||||
if (tp1->sent == SCTP_FORWARD_TSN_SKIP) {
|
||||
/* advance PeerAckPoint goes forward */
|
||||
asoc->advanced_peer_ack_point = tp1->rec.data.TSN_seq;
|
||||
a_adv = tp1;
|
||||
if (compare_with_wrap(tp1->rec.data.TSN_seq,
|
||||
asoc->advanced_peer_ack_point,
|
||||
MAX_TSN)) {
|
||||
|
||||
asoc->advanced_peer_ack_point = tp1->rec.data.TSN_seq;
|
||||
a_adv = tp1;
|
||||
} else if (tp1->rec.data.TSN_seq == asoc->advanced_peer_ack_point) {
|
||||
/* No update but we do save the chk */
|
||||
a_adv = tp1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If it is still in RESEND we can advance no
|
||||
@ -4142,14 +4157,27 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
|
||||
return (a_adv);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
sctp_fs_audit(struct sctp_association *asoc)
|
||||
{
|
||||
struct sctp_tmit_chunk *chk;
|
||||
int inflight = 0, resend = 0, inbetween = 0, acked = 0, above = 0;
|
||||
int entry_flight, entry_cnt, ret;
|
||||
|
||||
entry_flight = asoc->total_flight;
|
||||
entry_cnt = asoc->total_flight_count;
|
||||
ret = 0;
|
||||
|
||||
if (asoc->pr_sctp_cnt >= asoc->sent_queue_cnt)
|
||||
return (0);
|
||||
|
||||
TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
|
||||
if (chk->sent < SCTP_DATAGRAM_RESEND) {
|
||||
printf("Chk TSN:%u size:%d inflight cnt:%d\n",
|
||||
chk->rec.data.TSN_seq,
|
||||
chk->send_size,
|
||||
chk->snd_count
|
||||
);
|
||||
inflight++;
|
||||
} else if (chk->sent == SCTP_DATAGRAM_RESEND) {
|
||||
resend++;
|
||||
@ -4166,10 +4194,15 @@ sctp_fs_audit(struct sctp_association *asoc)
|
||||
#ifdef INVARIANTS
|
||||
panic("Flight size-express incorrect? \n");
|
||||
#else
|
||||
SCTP_PRINTF("Flight size-express incorrect inflight:%d inbetween:%d\n",
|
||||
inflight, inbetween);
|
||||
printf("asoc->total_flight:%d cnt:%d\n",
|
||||
entry_flight, entry_cnt);
|
||||
|
||||
SCTP_PRINTF("Flight size-express incorrect F:%d I:%d R:%d Ab:%d ACK:%d\n",
|
||||
inflight, inbetween, resend, above, acked);
|
||||
ret = 1;
|
||||
#endif
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
@ -4590,20 +4623,26 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
(asoc->sent_queue_retran_cnt == 0) &&
|
||||
(win_probe_recovered == 0) &&
|
||||
(done_once == 0)) {
|
||||
/* huh, this should not happen */
|
||||
sctp_fs_audit(asoc);
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
/*
|
||||
* huh, this should not happen unless all packets are
|
||||
* PR-SCTP and marked to skip of course.
|
||||
*/
|
||||
if (sctp_fs_audit(asoc)) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
if (net->flight_size) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
done_once = 1;
|
||||
@ -4728,6 +4767,13 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
*/
|
||||
asoc->nonce_sum_check = 0;
|
||||
asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point;
|
||||
} else if (lchk) {
|
||||
/* try to FR fwd-tsn's that get lost too */
|
||||
lchk->rec.data.fwd_tsn_cnt++;
|
||||
if (lchk->rec.data.fwd_tsn_cnt > 3) {
|
||||
send_forward_tsn(stcb, asoc);
|
||||
lchk->rec.data.fwd_tsn_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lchk) {
|
||||
@ -4813,10 +4859,6 @@ sctp_handle_sack(struct mbuf *m, int offset,
|
||||
num_seg = ntohs(sack->num_gap_ack_blks);
|
||||
a_rwnd = rwnd;
|
||||
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
|
||||
sctp_misc_ints(SCTP_SACK_LOG_NORMAL, cum_ack,
|
||||
rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
|
||||
}
|
||||
/* CMT DAC algo */
|
||||
cmt_dac_flag = ch->ch.chunk_flags & SCTP_SACK_CMT_DAC;
|
||||
num_dup = ntohs(sack->num_dup_tsns);
|
||||
@ -5605,20 +5647,24 @@ sctp_handle_sack(struct mbuf *m, int offset,
|
||||
(asoc->sent_queue_retran_cnt == 0) &&
|
||||
(win_probe_recovered == 0) &&
|
||||
(done_once == 0)) {
|
||||
/* huh, this should not happen */
|
||||
sctp_fs_audit(asoc);
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
/*
|
||||
* huh, this should not happen unless all packets are
|
||||
* PR-SCTP and marked to skip of course.
|
||||
*/
|
||||
if (sctp_fs_audit(asoc)) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
done_once = 1;
|
||||
@ -5643,6 +5689,11 @@ sctp_handle_sack(struct mbuf *m, int offset,
|
||||
* on issues that will occur when the ECN NONCE
|
||||
* stuff is put into SCTP for cross checking.
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
|
||||
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
|
||||
0xee, cum_ack, asoc->advanced_peer_ack_point,
|
||||
old_adv_peer_ack_point);
|
||||
}
|
||||
if (compare_with_wrap(asoc->advanced_peer_ack_point, old_adv_peer_ack_point,
|
||||
MAX_TSN)) {
|
||||
send_forward_tsn(stcb, asoc);
|
||||
@ -5652,6 +5703,13 @@ sctp_handle_sack(struct mbuf *m, int offset,
|
||||
*/
|
||||
asoc->nonce_sum_check = 0;
|
||||
asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point;
|
||||
} else if (lchk) {
|
||||
/* try to FR fwd-tsn's that get lost too */
|
||||
lchk->rec.data.fwd_tsn_cnt++;
|
||||
if (lchk->rec.data.fwd_tsn_cnt > 3) {
|
||||
send_forward_tsn(stcb, asoc);
|
||||
lchk->rec.data.fwd_tsn_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lchk) {
|
||||
@ -6019,7 +6077,6 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
return;
|
||||
}
|
||||
SCTP_STAT_INCR(sctps_fwdtsn_map_over);
|
||||
slide_out:
|
||||
memset(stcb->asoc.mapping_array, 0, stcb->asoc.mapping_array_size);
|
||||
cumack_set_flag = 1;
|
||||
asoc->mapping_array_base_tsn = new_cum_tsn + 1;
|
||||
@ -6043,13 +6100,8 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
asoc->last_echo_tsn = asoc->highest_tsn_inside_map;
|
||||
} else {
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
if ((compare_with_wrap(((uint32_t) asoc->cumulative_tsn + gap), asoc->highest_tsn_inside_map, MAX_TSN)) ||
|
||||
(((uint32_t) asoc->cumulative_tsn + gap) == asoc->highest_tsn_inside_map)) {
|
||||
goto slide_out;
|
||||
} else {
|
||||
for (i = 0; i <= gap; i++) {
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, i);
|
||||
}
|
||||
for (i = 0; i <= gap; i++) {
|
||||
SCTP_SET_TSN_PRESENT(asoc->mapping_array, i);
|
||||
}
|
||||
/*
|
||||
* Now after marking all, slide thing forward but no sack
|
||||
@ -6059,7 +6111,6 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
if (*abort_flag)
|
||||
return;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* 2. Clear up re-assembly queue */
|
||||
/*************************************************************/
|
||||
@ -6083,9 +6134,9 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
|
||||
chk = TAILQ_FIRST(&asoc->reasmqueue);
|
||||
while (chk) {
|
||||
at = TAILQ_NEXT(chk, sctp_next);
|
||||
if (compare_with_wrap(asoc->cumulative_tsn,
|
||||
chk->rec.data.TSN_seq, MAX_TSN) ||
|
||||
asoc->cumulative_tsn == chk->rec.data.TSN_seq) {
|
||||
if ((compare_with_wrap(new_cum_tsn,
|
||||
chk->rec.data.TSN_seq, MAX_TSN)) ||
|
||||
(new_cum_tsn == chk->rec.data.TSN_seq)) {
|
||||
/* It needs to be tossed */
|
||||
TAILQ_REMOVE(&asoc->reasmqueue, chk, sctp_next);
|
||||
if (compare_with_wrap(chk->rec.data.TSN_seq,
|
||||
@ -6614,20 +6665,24 @@ sctp_express_handle_nr_sack(struct sctp_tcb *stcb, uint32_t cumack,
|
||||
(asoc->sent_queue_retran_cnt == 0) &&
|
||||
(win_probe_recovered == 0) &&
|
||||
(done_once == 0)) {
|
||||
/* huh, this should not happen */
|
||||
sctp_fs_audit(asoc);
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
/*
|
||||
* huh, this should not happen unless all packets are
|
||||
* PR-SCTP and marked to skip of course.
|
||||
*/
|
||||
if (sctp_fs_audit(asoc)) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
done_once = 1;
|
||||
@ -8170,20 +8225,24 @@ sctp_handle_nr_sack(struct mbuf *m, int offset,
|
||||
(asoc->sent_queue_retran_cnt == 0) &&
|
||||
(win_probe_recovered == 0) &&
|
||||
(done_once == 0)) {
|
||||
/* huh, this should not happen */
|
||||
sctp_fs_audit(asoc);
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
/*
|
||||
* huh, this should not happen unless all packets are
|
||||
* PR-SCTP and marked to skip of course.
|
||||
*/
|
||||
if (sctp_fs_audit(asoc)) {
|
||||
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
|
||||
net->flight_size = 0;
|
||||
}
|
||||
asoc->total_flight = 0;
|
||||
asoc->total_flight_count = 0;
|
||||
asoc->sent_queue_retran_cnt = 0;
|
||||
TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) {
|
||||
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
|
||||
sctp_flight_size_increase(tp1);
|
||||
sctp_total_flight_increase(stcb, tp1);
|
||||
} else if (tp1->sent == SCTP_DATAGRAM_RESEND) {
|
||||
asoc->sent_queue_retran_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
done_once = 1;
|
||||
@ -8221,6 +8280,13 @@ sctp_handle_nr_sack(struct mbuf *m, int offset,
|
||||
*/
|
||||
asoc->nonce_sum_check = 0;
|
||||
asoc->nonce_resync_tsn = asoc->advanced_peer_ack_point;
|
||||
} else if (lchk) {
|
||||
/* try to FR fwd-tsn's that get lost too */
|
||||
lchk->rec.data.fwd_tsn_cnt++;
|
||||
if (lchk->rec.data.fwd_tsn_cnt > 3) {
|
||||
send_forward_tsn(stcb, asoc);
|
||||
lchk->rec.data.fwd_tsn_cnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lchk) {
|
||||
|
@ -7513,7 +7513,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
|
||||
cause = SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_UNSENT;
|
||||
ret_spc = sctp_release_pr_sctp_chunk(stcb, chk,
|
||||
cause,
|
||||
&asoc->sent_queue, SCTP_SO_LOCKED);
|
||||
SCTP_SO_LOCKED);
|
||||
freed_spc += ret_spc;
|
||||
if (freed_spc >= dataout) {
|
||||
return;
|
||||
@ -7538,7 +7538,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
|
||||
|
||||
ret_spc = sctp_release_pr_sctp_chunk(stcb, chk,
|
||||
SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_UNSENT,
|
||||
&asoc->send_queue, SCTP_SO_LOCKED);
|
||||
SCTP_SO_LOCKED);
|
||||
|
||||
freed_spc += ret_spc;
|
||||
if (freed_spc >= dataout) {
|
||||
@ -8405,6 +8405,7 @@ sctp_clean_up_ctl(struct sctp_tcb *stcb, struct sctp_association *asoc)
|
||||
(chk->rec.chunk_id.id == SCTP_NR_SELECTIVE_ACK) || /* EY */
|
||||
(chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) ||
|
||||
(chk->rec.chunk_id.id == SCTP_HEARTBEAT_ACK) ||
|
||||
(chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN) ||
|
||||
(chk->rec.chunk_id.id == SCTP_SHUTDOWN) ||
|
||||
(chk->rec.chunk_id.id == SCTP_SHUTDOWN_ACK) ||
|
||||
(chk->rec.chunk_id.id == SCTP_OPERATION_ERROR) ||
|
||||
@ -8547,7 +8548,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
* when we took all the data the sender_all_done was
|
||||
* not set.
|
||||
*/
|
||||
if (sp->put_last_out == 0) {
|
||||
if ((sp->put_last_out == 0) && (sp->discard_rest == 0)) {
|
||||
SCTP_PRINTF("Gak, put out entire msg with NO end!-1\n");
|
||||
SCTP_PRINTF("sender_done:%d len:%d msg_comp:%d put_last_out:%d send_lock:%d\n",
|
||||
sp->sender_all_done,
|
||||
@ -8568,7 +8569,6 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
sp->data = NULL;
|
||||
}
|
||||
sctp_free_a_strmoq(stcb, sp);
|
||||
|
||||
/* we can't be locked to it */
|
||||
*locked = 0;
|
||||
stcb->asoc.locked_on_sending = NULL;
|
||||
@ -8596,6 +8596,29 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
*giveup = 1;
|
||||
to_move = 0;
|
||||
goto out_of;
|
||||
} else if (sp->discard_rest) {
|
||||
if (send_lock_up == 0) {
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
send_lock_up = 1;
|
||||
}
|
||||
/* Whack down the size */
|
||||
atomic_subtract_int(&stcb->asoc.total_output_queue_size, sp->length);
|
||||
if ((stcb->sctp_socket != NULL) && \
|
||||
((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
|
||||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) {
|
||||
atomic_subtract_int(&stcb->sctp_socket->so_snd.sb_cc, sp->length);
|
||||
}
|
||||
if (sp->data) {
|
||||
sctp_m_freem(sp->data);
|
||||
sp->data = NULL;
|
||||
sp->tail_mbuf = NULL;
|
||||
}
|
||||
sp->length = 0;
|
||||
sp->some_taken = 1;
|
||||
*locked = 1;
|
||||
*giveup = 1;
|
||||
to_move = 0;
|
||||
goto out_of;
|
||||
}
|
||||
}
|
||||
some_taken = sp->some_taken;
|
||||
@ -11533,6 +11556,7 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
{
|
||||
struct sctp_tmit_chunk *chk;
|
||||
struct sctp_forward_tsn_chunk *fwdtsn;
|
||||
uint32_t advance_peer_ack_point;
|
||||
|
||||
SCTP_TCB_LOCK_ASSERT(stcb);
|
||||
TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
|
||||
@ -11610,11 +11634,23 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
/* trim to a mtu size */
|
||||
cnt_of_space = asoc->smallest_mtu - ovh;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
|
||||
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
|
||||
0xff, 0, cnt_of_skipped,
|
||||
asoc->advanced_peer_ack_point);
|
||||
|
||||
}
|
||||
advance_peer_ack_point = asoc->advanced_peer_ack_point;
|
||||
if (cnt_of_space < space_needed) {
|
||||
/*-
|
||||
* ok we must trim down the chunk by lowering the
|
||||
* advance peer ack point.
|
||||
*/
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
|
||||
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
|
||||
0xff, 0xff, cnt_of_space,
|
||||
space_needed);
|
||||
}
|
||||
cnt_of_skipped = (cnt_of_space -
|
||||
((sizeof(struct sctp_forward_tsn_chunk)) /
|
||||
sizeof(struct sctp_strseq)));
|
||||
@ -11627,12 +11663,17 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
tp1 = TAILQ_NEXT(at, sctp_next);
|
||||
at = tp1;
|
||||
}
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOG_TRY_ADVANCE) {
|
||||
sctp_misc_ints(SCTP_FWD_TSN_CHECK,
|
||||
0xff, cnt_of_skipped, at->rec.data.TSN_seq,
|
||||
asoc->advanced_peer_ack_point);
|
||||
}
|
||||
last = at;
|
||||
/*-
|
||||
* last now points to last one I can report, update
|
||||
* peer ack point
|
||||
*/
|
||||
asoc->advanced_peer_ack_point = last->rec.data.TSN_seq;
|
||||
advance_peer_ack_point = last->rec.data.TSN_seq;
|
||||
space_needed -= (cnt_of_skipped * sizeof(struct sctp_strseq));
|
||||
}
|
||||
chk->send_size = space_needed;
|
||||
@ -11641,7 +11682,7 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
fwdtsn->ch.chunk_length = htons(chk->send_size);
|
||||
fwdtsn->ch.chunk_flags = 0;
|
||||
fwdtsn->ch.chunk_type = SCTP_FORWARD_CUM_TSN;
|
||||
fwdtsn->new_cumulative_tsn = htonl(asoc->advanced_peer_ack_point);
|
||||
fwdtsn->new_cumulative_tsn = htonl(advance_peer_ack_point);
|
||||
chk->send_size = (sizeof(struct sctp_forward_tsn_chunk) +
|
||||
(cnt_of_skipped * sizeof(struct sctp_strseq)));
|
||||
SCTP_BUF_LEN(chk->data) = chk->send_size;
|
||||
@ -11672,6 +11713,9 @@ send_forward_tsn(struct sctp_tcb *stcb,
|
||||
at = tp1;
|
||||
continue;
|
||||
}
|
||||
if (at->rec.data.TSN_seq == advance_peer_ack_point) {
|
||||
at->rec.data.fwd_tsn_cnt = 0;
|
||||
}
|
||||
strseq->stream = ntohs(at->rec.data.stream_number);
|
||||
strseq->sequence = ntohs(at->rec.data.stream_seq);
|
||||
strseq++;
|
||||
|
@ -767,7 +767,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
(void)sctp_release_pr_sctp_chunk(stcb,
|
||||
chk,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -779,7 +779,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
|
||||
(void)sctp_release_pr_sctp_chunk(stcb,
|
||||
chk,
|
||||
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
|
||||
&stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED);
|
||||
SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -96,7 +96,8 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
|
||||
#define sctp_alloc_a_strmoq(_stcb, _strmoq) { \
|
||||
(_strmoq) = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_strmoq), struct sctp_stream_queue_pending); \
|
||||
if ((_strmoq)) { \
|
||||
if ((_strmoq)) { \
|
||||
memset(_strmoq, 0, sizeof(struct sctp_stream_queue_pending)); \
|
||||
SCTP_INCR_STRMOQ_COUNT(); \
|
||||
(_strmoq)->holds_key_ref = 0; \
|
||||
} \
|
||||
@ -267,6 +268,7 @@ extern struct pr_usrreqs sctp_usrreqs;
|
||||
#else
|
||||
|
||||
#define sctp_total_flight_decrease(stcb, tp1) do { \
|
||||
tp1->window_probe = 0; \
|
||||
if (stcb->asoc.total_flight >= tp1->book_size) { \
|
||||
stcb->asoc.total_flight -= tp1->book_size; \
|
||||
if (stcb->asoc.total_flight_count > 0) \
|
||||
|
@ -3686,10 +3686,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
|
||||
while (chk) {
|
||||
TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next);
|
||||
asoc->sent_queue_cnt--;
|
||||
sctp_free_bufspace(stcb, asoc, chk, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
|
||||
SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
|
||||
if (chk->data) {
|
||||
if (chk->data != NULL) {
|
||||
sctp_free_bufspace(stcb, asoc, chk, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
|
||||
SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
@ -3704,9 +3704,10 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
|
||||
while (chk) {
|
||||
TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next);
|
||||
asoc->send_queue_cnt--;
|
||||
sctp_free_bufspace(stcb, asoc, chk, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
|
||||
if (chk->data) {
|
||||
if (chk->data != NULL) {
|
||||
sctp_free_bufspace(stcb, asoc, chk, 1);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
|
||||
SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
|
||||
sctp_m_freem(chk->data);
|
||||
chk->data = NULL;
|
||||
}
|
||||
@ -4630,64 +4631,46 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
|
||||
|
||||
int
|
||||
sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
|
||||
int reason, struct sctpchunk_listhead *queue, int so_locked
|
||||
int reason, int so_locked
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
#endif
|
||||
)
|
||||
{
|
||||
struct sctp_stream_out *strq;
|
||||
struct sctp_tmit_chunk *chk = NULL;
|
||||
struct sctp_stream_queue_pending *sp;
|
||||
uint16_t stream = 0, seq = 0;
|
||||
uint8_t foundeom = 0;
|
||||
int ret_sz = 0;
|
||||
int notdone;
|
||||
uint8_t foundeom = 0;
|
||||
int do_wakeup_routine = 0;
|
||||
|
||||
stream = tp1->rec.data.stream_number;
|
||||
seq = tp1->rec.data.stream_seq;
|
||||
do {
|
||||
ret_sz += tp1->book_size;
|
||||
tp1->sent = SCTP_FORWARD_TSN_SKIP;
|
||||
if (tp1->data) {
|
||||
if (tp1->data != NULL) {
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
struct socket *so;
|
||||
|
||||
#endif
|
||||
printf("Release PR-SCTP chunk tsn:%u flags:%x\n",
|
||||
tp1->rec.data.TSN_seq,
|
||||
(unsigned int)tp1->rec.data.rcv_flags);
|
||||
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
|
||||
sctp_flight_size_decrease(tp1);
|
||||
sctp_total_flight_decrease(stcb, tp1);
|
||||
stcb->asoc.peers_rwnd += tp1->send_size;
|
||||
stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh);
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked);
|
||||
sctp_m_freem(tp1->data);
|
||||
tp1->data = NULL;
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
so = SCTP_INP_SO(stcb->sctp_ep);
|
||||
if (!so_locked) {
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_SOCKET_LOCK(so, 1);
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
atomic_subtract_int(&stcb->asoc.refcnt, 1);
|
||||
if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
|
||||
/*
|
||||
* assoc was freed while we were
|
||||
* unlocked
|
||||
*/
|
||||
SCTP_SOCKET_UNLOCK(so, 1);
|
||||
return (ret_sz);
|
||||
}
|
||||
do_wakeup_routine = 1;
|
||||
if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
|
||||
stcb->asoc.sent_queue_cnt_removeable--;
|
||||
}
|
||||
#endif
|
||||
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
if (!so_locked) {
|
||||
SCTP_SOCKET_UNLOCK(so, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
|
||||
stcb->asoc.sent_queue_cnt_removeable--;
|
||||
}
|
||||
if (queue == &stcb->asoc.send_queue) {
|
||||
TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
|
||||
/* on to the sent queue */
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
|
||||
sctp_next);
|
||||
stcb->asoc.sent_queue_cnt++;
|
||||
}
|
||||
if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) ==
|
||||
SCTP_DATA_NOT_FRAG) {
|
||||
@ -4707,23 +4690,147 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
|
||||
tp1 = TAILQ_NEXT(tp1, sctp_next);
|
||||
}
|
||||
} while (tp1 && notdone);
|
||||
if ((foundeom == 0) && (queue == &stcb->asoc.sent_queue)) {
|
||||
if (foundeom == 0) {
|
||||
/*
|
||||
* The multi-part message was scattered across the send and
|
||||
* sent queue.
|
||||
*/
|
||||
next_on_sent:
|
||||
tp1 = TAILQ_FIRST(&stcb->asoc.send_queue);
|
||||
/*
|
||||
* recurse throught the send_queue too, starting at the
|
||||
* beginning.
|
||||
*/
|
||||
if (tp1) {
|
||||
ret_sz += sctp_release_pr_sctp_chunk(stcb, tp1, reason,
|
||||
&stcb->asoc.send_queue, so_locked);
|
||||
} else {
|
||||
SCTP_PRINTF("hmm, nothing on the send queue and no EOM?\n");
|
||||
if ((tp1) &&
|
||||
(tp1->rec.data.stream_number == stream) &&
|
||||
(tp1->rec.data.stream_seq == seq)
|
||||
) {
|
||||
/*
|
||||
* save to chk in case we have some on stream out
|
||||
* queue. If so and we have an un-transmitted one we
|
||||
* don't have to fudge the TSN.
|
||||
*/
|
||||
chk = tp1;
|
||||
ret_sz += tp1->book_size;
|
||||
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked);
|
||||
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
|
||||
sctp_m_freem(tp1->data);
|
||||
tp1->data = NULL;
|
||||
if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) {
|
||||
foundeom = 1;
|
||||
}
|
||||
do_wakeup_routine = 1;
|
||||
tp1->sent = SCTP_FORWARD_TSN_SKIP;
|
||||
TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next);
|
||||
/*
|
||||
* on to the sent queue so we can wait for it to be
|
||||
* passed by.
|
||||
*/
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1,
|
||||
sctp_next);
|
||||
stcb->asoc.send_queue_cnt--;
|
||||
stcb->asoc.sent_queue_cnt++;
|
||||
goto next_on_sent;
|
||||
}
|
||||
}
|
||||
if (foundeom == 0) {
|
||||
/*
|
||||
* Still no eom found. That means there is stuff left on the
|
||||
* stream out queue.. yuck.
|
||||
*/
|
||||
strq = &stcb->asoc.strmout[stream];
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
sp = TAILQ_FIRST(&strq->outqueue);
|
||||
while (sp->strseq <= seq) {
|
||||
/* Check if its our SEQ */
|
||||
if (sp->strseq == seq) {
|
||||
sp->discard_rest = 1;
|
||||
/*
|
||||
* We may need to put a chunk on the queue
|
||||
* that holds the TSN that would have been
|
||||
* sent with the LAST bit.
|
||||
*/
|
||||
if (chk == NULL) {
|
||||
/* Yep, we have to */
|
||||
sctp_alloc_a_chunk(stcb, chk);
|
||||
if (chk == NULL) {
|
||||
/*
|
||||
* we are hosed. All we can
|
||||
* do is nothing.. which
|
||||
* will cause an abort if
|
||||
* the peer is paying
|
||||
* attention.
|
||||
*/
|
||||
goto oh_well;
|
||||
}
|
||||
memset(chk, 0, sizeof(*chk));
|
||||
chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG;
|
||||
chk->sent = SCTP_FORWARD_TSN_SKIP;
|
||||
chk->asoc = &stcb->asoc;
|
||||
chk->rec.data.stream_seq = sp->strseq;
|
||||
chk->rec.data.stream_number = sp->stream;
|
||||
chk->rec.data.payloadtype = sp->ppid;
|
||||
chk->rec.data.context = sp->context;
|
||||
chk->flags = sp->act_flags;
|
||||
chk->addr_over = sp->addr_over;
|
||||
chk->whoTo = sp->net;
|
||||
atomic_add_int(&chk->whoTo->ref_count, 1);
|
||||
chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1);
|
||||
stcb->asoc.pr_sctp_cnt++;
|
||||
chk->pr_sctp_on = 1;
|
||||
TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next);
|
||||
stcb->asoc.sent_queue_cnt++;
|
||||
} else {
|
||||
chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG;
|
||||
}
|
||||
oh_well:
|
||||
if (sp->data) {
|
||||
/*
|
||||
* Pull any data to free up the SB
|
||||
* and allow sender to "add more"
|
||||
* whilc we will throw away :-)
|
||||
*/
|
||||
sctp_free_spbufspace(stcb, &stcb->asoc,
|
||||
sp);
|
||||
ret_sz += sp->length;
|
||||
do_wakeup_routine = 1;
|
||||
sp->some_taken = 1;
|
||||
sctp_m_freem(sp->data);
|
||||
sp->length = 0;
|
||||
sp->data = NULL;
|
||||
sp->tail_mbuf = NULL;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
/* Next one please */
|
||||
sp = TAILQ_NEXT(sp, next);
|
||||
}
|
||||
} /* End while */
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
}
|
||||
if (do_wakeup_routine) {
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
so = SCTP_INP_SO(stcb->sctp_ep);
|
||||
if (!so_locked) {
|
||||
atomic_add_int(&stcb->asoc.refcnt, 1);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
SCTP_SOCKET_LOCK(so, 1);
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
atomic_subtract_int(&stcb->asoc.refcnt, 1);
|
||||
if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
|
||||
/* assoc was freed while we were unlocked */
|
||||
SCTP_SOCKET_UNLOCK(so, 1);
|
||||
return (ret_sz);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
|
||||
#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
|
||||
if (!so_locked) {
|
||||
SCTP_SOCKET_UNLOCK(so, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return (ret_sz);
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
|
||||
|
||||
int
|
||||
sctp_release_pr_sctp_chunk(struct sctp_tcb *, struct sctp_tmit_chunk *,
|
||||
int, struct sctpchunk_listhead *, int
|
||||
int, int
|
||||
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
|
||||
SCTP_UNUSED
|
||||
#endif
|
||||
@ -287,7 +287,6 @@ do { \
|
||||
#define sctp_free_spbufspace(stcb, asoc, sp) \
|
||||
do { \
|
||||
if (sp->data != NULL) { \
|
||||
atomic_subtract_int(&(asoc)->chunks_on_out_queue, 1); \
|
||||
if ((asoc)->total_output_queue_size >= sp->length) { \
|
||||
atomic_subtract_int(&(asoc)->total_output_queue_size, sp->length); \
|
||||
} else { \
|
||||
|
Loading…
Reference in New Issue
Block a user