Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b484d8a5 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'sctp-prsctp-chunk-fixes'



Xin Long says:

====================
sctp: a couple of fixes for chunks abandoned in prsctp

Now when abandoning chunks in prsctp, it doesn't consider for frags in
one msg, which would cause peer can never receive the whole frags for
one msg to get them reassembled, these pieces of this msg will stay in
the reasm queue forever and block the following chunks' receiving.

This patchset is to fix them in patch 2 and 3, and also fix another
issue for prsctp in patch 1.
====================

Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6fef90c6 779edd73
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -503,7 +503,8 @@ struct sctp_datamsg {
	/* Did the messenge fail to send? */
	int send_error;
	u8 send_failed:1,
	   can_delay;	    /* should this message be Nagle delayed */
	   can_delay:1,	/* should this message be Nagle delayed */
	   abandoned:1;	/* should this message be abandoned */
};

struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
+11 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
	msg->send_failed = 0;
	msg->send_error = 0;
	msg->can_delay = 1;
	msg->abandoned = 0;
	msg->expires_at = 0;
	INIT_LIST_HEAD(&msg->chunks);
}
@@ -304,6 +305,13 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
	if (!chunk->asoc->peer.prsctp_capable)
		return 0;

	if (chunk->msg->abandoned)
		return 1;

	if (!chunk->has_tsn &&
	    !(chunk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG))
		return 0;

	if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
	    time_after(jiffies, chunk->msg->expires_at)) {
		struct sctp_stream_out *streamout =
@@ -316,6 +324,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
			chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
			streamout->ext->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
		}
		chunk->msg->abandoned = 1;
		return 1;
	} else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
		   chunk->sent_count > chunk->sinfo.sinfo_timetolive) {
@@ -324,10 +333,12 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)

		chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
		streamout->ext->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
		chunk->msg->abandoned = 1;
		return 1;
	} else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) &&
		   chunk->msg->expires_at &&
		   time_after(jiffies, chunk->msg->expires_at)) {
		chunk->msg->abandoned = 1;
		return 1;
	}
	/* PRIO policy is processed by sendmsg, not here */
+13 −6
Original line number Diff line number Diff line
@@ -364,10 +364,12 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
	list_for_each_entry_safe(chk, temp, queue, transmitted_list) {
		struct sctp_stream_out *streamout;

		if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
		    chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive)
		if (!chk->msg->abandoned &&
		    (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
		     chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive))
			continue;

		chk->msg->abandoned = 1;
		list_del_init(&chk->transmitted_list);
		sctp_insert_list(&asoc->outqueue.abandoned,
				 &chk->transmitted_list);
@@ -377,7 +379,8 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
		asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
		streamout->ext->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;

		if (!chk->tsn_gap_acked) {
		if (queue != &asoc->outqueue.retransmit &&
		    !chk->tsn_gap_acked) {
			if (chk->transport)
				chk->transport->flight_size -=
						sctp_data_size(chk);
@@ -403,10 +406,13 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
	q->sched->unsched_all(&asoc->stream);

	list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) {
		if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
		    chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive)
		if (!chk->msg->abandoned &&
		    (!(chk->chunk_hdr->flags & SCTP_DATA_FIRST_FRAG) ||
		     !SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
		     chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive))
			continue;

		chk->msg->abandoned = 1;
		sctp_sched_dequeue_common(q, chk);
		asoc->sent_cnt_removable--;
		asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
@@ -1434,7 +1440,8 @@ static void sctp_check_transmitted(struct sctp_outq *q,
			/* If this chunk has not been acked, stop
			 * considering it as 'outstanding'.
			 */
			if (!tchunk->tsn_gap_acked) {
			if (transmitted_queue != &q->retransmit &&
			    !tchunk->tsn_gap_acked) {
				if (tchunk->transport)
					tchunk->transport->flight_size -=
							sctp_data_size(tchunk);