Commit e5f61296 authored by Xin Long's avatar Xin Long Committed by David S. Miller

sctp: abandon the whole msg if one part of a fragmented message is abandoned

As rfc3758#section-3.1 demands:

   A3) When a TSN is "abandoned", if it is part of a fragmented message,
       all other TSN's within that fragmented message MUST be abandoned
       at the same time.

Besides, if it couldn't handle this, the rest frags would never get
assembled in peer side.

This patch supports it by adding abandoned flag in sctp_datamsg, when
one chunk is being abandoned, set chunk->msg->abandoned as well. Next
time when checking for abandoned, go checking chunk->msg->abandoned
first.
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d30fc512
...@@ -503,7 +503,8 @@ struct sctp_datamsg { ...@@ -503,7 +503,8 @@ struct sctp_datamsg {
/* Did the messenge fail to send? */ /* Did the messenge fail to send? */
int send_error; int send_error;
u8 send_failed:1, 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 *, struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
......
...@@ -53,6 +53,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg) ...@@ -53,6 +53,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
msg->send_failed = 0; msg->send_failed = 0;
msg->send_error = 0; msg->send_error = 0;
msg->can_delay = 1; msg->can_delay = 1;
msg->abandoned = 0;
msg->expires_at = 0; msg->expires_at = 0;
INIT_LIST_HEAD(&msg->chunks); INIT_LIST_HEAD(&msg->chunks);
} }
...@@ -304,6 +305,9 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk) ...@@ -304,6 +305,9 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
if (!chunk->asoc->peer.prsctp_capable) if (!chunk->asoc->peer.prsctp_capable)
return 0; return 0;
if (chunk->msg->abandoned)
return 1;
if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) && if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
time_after(jiffies, chunk->msg->expires_at)) { time_after(jiffies, chunk->msg->expires_at)) {
struct sctp_stream_out *streamout = struct sctp_stream_out *streamout =
...@@ -316,6 +320,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk) ...@@ -316,6 +320,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++; chunk->asoc->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
streamout->ext->abandoned_unsent[SCTP_PR_INDEX(TTL)]++; streamout->ext->abandoned_unsent[SCTP_PR_INDEX(TTL)]++;
} }
chunk->msg->abandoned = 1;
return 1; return 1;
} else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) && } else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
chunk->sent_count > chunk->sinfo.sinfo_timetolive) { chunk->sent_count > chunk->sinfo.sinfo_timetolive) {
...@@ -324,10 +329,12 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk) ...@@ -324,10 +329,12 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++; chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
streamout->ext->abandoned_sent[SCTP_PR_INDEX(RTX)]++; streamout->ext->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
chunk->msg->abandoned = 1;
return 1; return 1;
} else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) && } else if (!SCTP_PR_POLICY(chunk->sinfo.sinfo_flags) &&
chunk->msg->expires_at && chunk->msg->expires_at &&
time_after(jiffies, chunk->msg->expires_at)) { time_after(jiffies, chunk->msg->expires_at)) {
chunk->msg->abandoned = 1;
return 1; return 1;
} }
/* PRIO policy is processed by sendmsg, not here */ /* PRIO policy is processed by sendmsg, not here */
......
...@@ -364,10 +364,12 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc, ...@@ -364,10 +364,12 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
list_for_each_entry_safe(chk, temp, queue, transmitted_list) { list_for_each_entry_safe(chk, temp, queue, transmitted_list) {
struct sctp_stream_out *streamout; struct sctp_stream_out *streamout;
if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || if (!chk->msg->abandoned &&
chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive))
continue; continue;
chk->msg->abandoned = 1;
list_del_init(&chk->transmitted_list); list_del_init(&chk->transmitted_list);
sctp_insert_list(&asoc->outqueue.abandoned, sctp_insert_list(&asoc->outqueue.abandoned,
&chk->transmitted_list); &chk->transmitted_list);
...@@ -404,10 +406,12 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc, ...@@ -404,10 +406,12 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
q->sched->unsched_all(&asoc->stream); q->sched->unsched_all(&asoc->stream);
list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) { list_for_each_entry_safe(chk, temp, &q->out_chunk_list, list) {
if (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) || if (!chk->msg->abandoned &&
chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive) (!SCTP_PR_PRIO_ENABLED(chk->sinfo.sinfo_flags) ||
chk->sinfo.sinfo_timetolive <= sinfo->sinfo_timetolive))
continue; continue;
chk->msg->abandoned = 1;
sctp_sched_dequeue_common(q, chk); sctp_sched_dequeue_common(q, chk);
asoc->sent_cnt_removable--; asoc->sent_cnt_removable--;
asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment