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

sctp: implement generate_ftsn for sctp_stream_interleave

generate_ftsn is added as a member of sctp_stream_interleave, used to
create fwdtsn or ifwdtsn chunk according to abandoned chunks, called
in sctp_retransmit and sctp_outq_sack.

sctp_generate_iftsn works for ifwdtsn, and sctp_generate_fwdtsn is
still used for making fwdtsn.
Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarMarcelo R. Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2d07a49a
...@@ -47,6 +47,8 @@ struct sctp_stream_interleave { ...@@ -47,6 +47,8 @@ struct sctp_stream_interleave {
struct sctp_chunk *chunk, gfp_t gfp); struct sctp_chunk *chunk, gfp_t gfp);
void (*start_pd)(struct sctp_ulpq *ulpq, gfp_t gfp); void (*start_pd)(struct sctp_ulpq *ulpq, gfp_t gfp);
void (*abort_pd)(struct sctp_ulpq *ulpq, gfp_t gfp); void (*abort_pd)(struct sctp_ulpq *ulpq, gfp_t gfp);
/* (I-)FORWARD-TSN process */
void (*generate_ftsn)(struct sctp_outq *q, __u32 ctsn);
}; };
void sctp_stream_interleave_init(struct sctp_stream *stream); void sctp_stream_interleave_init(struct sctp_stream *stream);
......
...@@ -1100,6 +1100,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8); ...@@ -1100,6 +1100,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
void sctp_outq_uncork(struct sctp_outq *, gfp_t gfp); void sctp_outq_uncork(struct sctp_outq *, gfp_t gfp);
void sctp_prsctp_prune(struct sctp_association *asoc, void sctp_prsctp_prune(struct sctp_association *asoc,
struct sctp_sndrcvinfo *sinfo, int msg_len); struct sctp_sndrcvinfo *sinfo, int msg_len);
void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
/* Uncork and flush an outqueue. */ /* Uncork and flush an outqueue. */
static inline void sctp_outq_cork(struct sctp_outq *q) static inline void sctp_outq_cork(struct sctp_outq *q)
{ {
......
...@@ -67,8 +67,6 @@ static void sctp_mark_missing(struct sctp_outq *q, ...@@ -67,8 +67,6 @@ static void sctp_mark_missing(struct sctp_outq *q,
__u32 highest_new_tsn, __u32 highest_new_tsn,
int count_of_newacks); int count_of_newacks);
static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp); static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp);
/* Add data to the front of the queue. */ /* Add data to the front of the queue. */
...@@ -591,7 +589,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, ...@@ -591,7 +589,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* following the procedures outlined in C1 - C5. * following the procedures outlined in C1 - C5.
*/ */
if (reason == SCTP_RTXR_T3_RTX) if (reason == SCTP_RTXR_T3_RTX)
sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point); q->asoc->stream.si->generate_ftsn(q, q->asoc->ctsn_ack_point);
/* Flush the queues only on timeout, since fast_rtx is only /* Flush the queues only on timeout, since fast_rtx is only
* triggered during sack processing and the queue * triggered during sack processing and the queue
...@@ -942,6 +940,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -942,6 +940,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
case SCTP_CID_ECN_ECNE: case SCTP_CID_ECN_ECNE:
case SCTP_CID_ASCONF: case SCTP_CID_ASCONF:
case SCTP_CID_FWD_TSN: case SCTP_CID_FWD_TSN:
case SCTP_CID_I_FWD_TSN:
case SCTP_CID_RECONF: case SCTP_CID_RECONF:
status = sctp_packet_transmit_chunk(packet, chunk, status = sctp_packet_transmit_chunk(packet, chunk,
one_packet, gfp); one_packet, gfp);
...@@ -956,7 +955,8 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -956,7 +955,8 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* sender MUST assure that at least one T3-rtx * sender MUST assure that at least one T3-rtx
* timer is running. * timer is running.
*/ */
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) { if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN ||
chunk->chunk_hdr->type == SCTP_CID_I_FWD_TSN) {
sctp_transport_reset_t3_rtx(transport); sctp_transport_reset_t3_rtx(transport);
transport->last_time_sent = jiffies; transport->last_time_sent = jiffies;
} }
...@@ -1372,7 +1372,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) ...@@ -1372,7 +1372,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
asoc->peer.rwnd = sack_a_rwnd; asoc->peer.rwnd = sack_a_rwnd;
sctp_generate_fwdtsn(q, sack_ctsn); asoc->stream.si->generate_ftsn(q, sack_ctsn);
pr_debug("%s: sack cumulative tsn ack:0x%x\n", __func__, sack_ctsn); pr_debug("%s: sack cumulative tsn ack:0x%x\n", __func__, sack_ctsn);
pr_debug("%s: cumulative tsn ack of assoc:%p is 0x%x, " pr_debug("%s: cumulative tsn ack of assoc:%p is 0x%x, "
...@@ -1795,7 +1795,7 @@ static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist, ...@@ -1795,7 +1795,7 @@ static inline int sctp_get_skip_pos(struct sctp_fwdtsn_skip *skiplist,
} }
/* Create and add a fwdtsn chunk to the outq's control queue if needed. */ /* Create and add a fwdtsn chunk to the outq's control queue if needed. */
static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn) void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
{ {
struct sctp_association *asoc = q->asoc; struct sctp_association *asoc = q->asoc;
struct sctp_chunk *ftsn_chunk = NULL; struct sctp_chunk *ftsn_chunk = NULL;
......
...@@ -1082,6 +1082,77 @@ static void sctp_intl_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp) ...@@ -1082,6 +1082,77 @@ static void sctp_intl_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp)
sctp_ulpq_flush(ulpq); sctp_ulpq_flush(ulpq);
} }
static inline int sctp_get_skip_pos(struct sctp_ifwdtsn_skip *skiplist,
int nskips, __be16 stream, __u8 flags)
{
int i;
for (i = 0; i < nskips; i++)
if (skiplist[i].stream == stream &&
skiplist[i].flags == flags)
return i;
return i;
}
#define SCTP_FTSN_U_BIT 0x1
static void sctp_generate_iftsn(struct sctp_outq *q, __u32 ctsn)
{
struct sctp_ifwdtsn_skip ftsn_skip_arr[10];
struct sctp_association *asoc = q->asoc;
struct sctp_chunk *ftsn_chunk = NULL;
struct list_head *lchunk, *temp;
int nskips = 0, skip_pos;
struct sctp_chunk *chunk;
__u32 tsn;
if (!asoc->peer.prsctp_capable)
return;
if (TSN_lt(asoc->adv_peer_ack_point, ctsn))
asoc->adv_peer_ack_point = ctsn;
list_for_each_safe(lchunk, temp, &q->abandoned) {
chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list);
tsn = ntohl(chunk->subh.data_hdr->tsn);
if (TSN_lte(tsn, ctsn)) {
list_del_init(lchunk);
sctp_chunk_free(chunk);
} else if (TSN_lte(tsn, asoc->adv_peer_ack_point + 1)) {
__be16 sid = chunk->subh.idata_hdr->stream;
__be32 mid = chunk->subh.idata_hdr->mid;
__u8 flags = 0;
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
flags |= SCTP_FTSN_U_BIT;
asoc->adv_peer_ack_point = tsn;
skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0], nskips,
sid, flags);
ftsn_skip_arr[skip_pos].stream = sid;
ftsn_skip_arr[skip_pos].reserved = 0;
ftsn_skip_arr[skip_pos].flags = flags;
ftsn_skip_arr[skip_pos].mid = mid;
if (skip_pos == nskips)
nskips++;
if (nskips == 10)
break;
} else {
break;
}
}
if (asoc->adv_peer_ack_point > ctsn)
ftsn_chunk = sctp_make_ifwdtsn(asoc, asoc->adv_peer_ack_point,
nskips, &ftsn_skip_arr[0]);
if (ftsn_chunk) {
list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_OUTCTRLCHUNKS);
}
}
static struct sctp_stream_interleave sctp_stream_interleave_0 = { static struct sctp_stream_interleave sctp_stream_interleave_0 = {
.data_chunk_len = sizeof(struct sctp_data_chunk), .data_chunk_len = sizeof(struct sctp_data_chunk),
/* DATA process functions */ /* DATA process functions */
...@@ -1093,6 +1164,8 @@ static struct sctp_stream_interleave sctp_stream_interleave_0 = { ...@@ -1093,6 +1164,8 @@ static struct sctp_stream_interleave sctp_stream_interleave_0 = {
.renege_events = sctp_ulpq_renege, .renege_events = sctp_ulpq_renege,
.start_pd = sctp_ulpq_partial_delivery, .start_pd = sctp_ulpq_partial_delivery,
.abort_pd = sctp_ulpq_abort_pd, .abort_pd = sctp_ulpq_abort_pd,
/* FORWARD-TSN process functions */
.generate_ftsn = sctp_generate_fwdtsn,
}; };
static struct sctp_stream_interleave sctp_stream_interleave_1 = { static struct sctp_stream_interleave sctp_stream_interleave_1 = {
...@@ -1106,6 +1179,8 @@ static struct sctp_stream_interleave sctp_stream_interleave_1 = { ...@@ -1106,6 +1179,8 @@ static struct sctp_stream_interleave sctp_stream_interleave_1 = {
.renege_events = sctp_renege_events, .renege_events = sctp_renege_events,
.start_pd = sctp_intl_start_pd, .start_pd = sctp_intl_start_pd,
.abort_pd = sctp_intl_abort_pd, .abort_pd = sctp_intl_abort_pd,
/* I-FORWARD-TSN process functions */
.generate_ftsn = sctp_generate_iftsn,
}; };
void sctp_stream_interleave_init(struct sctp_stream *stream) void sctp_stream_interleave_init(struct sctp_stream *stream)
......
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