Skip to content

Commit 8e0c3b7

Browse files
lxindavem330
authored andcommitted
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: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo R. Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 2d07a49 commit 8e0c3b7

File tree

4 files changed

+84
-6
lines changed

4 files changed

+84
-6
lines changed

include/net/sctp/stream_interleave.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ struct sctp_stream_interleave {
4747
struct sctp_chunk *chunk, gfp_t gfp);
4848
void (*start_pd)(struct sctp_ulpq *ulpq, gfp_t gfp);
4949
void (*abort_pd)(struct sctp_ulpq *ulpq, gfp_t gfp);
50+
/* (I-)FORWARD-TSN process */
51+
void (*generate_ftsn)(struct sctp_outq *q, __u32 ctsn);
5052
};
5153

5254
void sctp_stream_interleave_init(struct sctp_stream *stream);

include/net/sctp/structs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,6 +1100,7 @@ void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
11001100
void sctp_outq_uncork(struct sctp_outq *, gfp_t gfp);
11011101
void sctp_prsctp_prune(struct sctp_association *asoc,
11021102
struct sctp_sndrcvinfo *sinfo, int msg_len);
1103+
void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
11031104
/* Uncork and flush an outqueue. */
11041105
static inline void sctp_outq_cork(struct sctp_outq *q)
11051106
{

net/sctp/outqueue.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ static void sctp_mark_missing(struct sctp_outq *q,
6767
__u32 highest_new_tsn,
6868
int count_of_newacks);
6969

70-
static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
71-
7270
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp);
7371

7472
/* Add data to the front of the queue. */
@@ -591,7 +589,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
591589
* following the procedures outlined in C1 - C5.
592590
*/
593591
if (reason == SCTP_RTXR_T3_RTX)
594-
sctp_generate_fwdtsn(q, q->asoc->ctsn_ack_point);
592+
q->asoc->stream.si->generate_ftsn(q, q->asoc->ctsn_ack_point);
595593

596594
/* Flush the queues only on timeout, since fast_rtx is only
597595
* 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)
942940
case SCTP_CID_ECN_ECNE:
943941
case SCTP_CID_ASCONF:
944942
case SCTP_CID_FWD_TSN:
943+
case SCTP_CID_I_FWD_TSN:
945944
case SCTP_CID_RECONF:
946945
status = sctp_packet_transmit_chunk(packet, chunk,
947946
one_packet, gfp);
@@ -956,7 +955,8 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
956955
* sender MUST assure that at least one T3-rtx
957956
* timer is running.
958957
*/
959-
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN) {
958+
if (chunk->chunk_hdr->type == SCTP_CID_FWD_TSN ||
959+
chunk->chunk_hdr->type == SCTP_CID_I_FWD_TSN) {
960960
sctp_transport_reset_t3_rtx(transport);
961961
transport->last_time_sent = jiffies;
962962
}
@@ -1372,7 +1372,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
13721372

13731373
asoc->peer.rwnd = sack_a_rwnd;
13741374

1375-
sctp_generate_fwdtsn(q, sack_ctsn);
1375+
asoc->stream.si->generate_ftsn(q, sack_ctsn);
13761376

13771377
pr_debug("%s: sack cumulative tsn ack:0x%x\n", __func__, sack_ctsn);
13781378
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,
17951795
}
17961796

17971797
/* Create and add a fwdtsn chunk to the outq's control queue if needed. */
1798-
static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
1798+
void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
17991799
{
18001800
struct sctp_association *asoc = q->asoc;
18011801
struct sctp_chunk *ftsn_chunk = NULL;

net/sctp/stream_interleave.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,77 @@ static void sctp_intl_abort_pd(struct sctp_ulpq *ulpq, gfp_t gfp)
10821082
sctp_ulpq_flush(ulpq);
10831083
}
10841084

1085+
static inline int sctp_get_skip_pos(struct sctp_ifwdtsn_skip *skiplist,
1086+
int nskips, __be16 stream, __u8 flags)
1087+
{
1088+
int i;
1089+
1090+
for (i = 0; i < nskips; i++)
1091+
if (skiplist[i].stream == stream &&
1092+
skiplist[i].flags == flags)
1093+
return i;
1094+
1095+
return i;
1096+
}
1097+
1098+
#define SCTP_FTSN_U_BIT 0x1
1099+
static void sctp_generate_iftsn(struct sctp_outq *q, __u32 ctsn)
1100+
{
1101+
struct sctp_ifwdtsn_skip ftsn_skip_arr[10];
1102+
struct sctp_association *asoc = q->asoc;
1103+
struct sctp_chunk *ftsn_chunk = NULL;
1104+
struct list_head *lchunk, *temp;
1105+
int nskips = 0, skip_pos;
1106+
struct sctp_chunk *chunk;
1107+
__u32 tsn;
1108+
1109+
if (!asoc->peer.prsctp_capable)
1110+
return;
1111+
1112+
if (TSN_lt(asoc->adv_peer_ack_point, ctsn))
1113+
asoc->adv_peer_ack_point = ctsn;
1114+
1115+
list_for_each_safe(lchunk, temp, &q->abandoned) {
1116+
chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list);
1117+
tsn = ntohl(chunk->subh.data_hdr->tsn);
1118+
1119+
if (TSN_lte(tsn, ctsn)) {
1120+
list_del_init(lchunk);
1121+
sctp_chunk_free(chunk);
1122+
} else if (TSN_lte(tsn, asoc->adv_peer_ack_point + 1)) {
1123+
__be16 sid = chunk->subh.idata_hdr->stream;
1124+
__be32 mid = chunk->subh.idata_hdr->mid;
1125+
__u8 flags = 0;
1126+
1127+
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
1128+
flags |= SCTP_FTSN_U_BIT;
1129+
1130+
asoc->adv_peer_ack_point = tsn;
1131+
skip_pos = sctp_get_skip_pos(&ftsn_skip_arr[0], nskips,
1132+
sid, flags);
1133+
ftsn_skip_arr[skip_pos].stream = sid;
1134+
ftsn_skip_arr[skip_pos].reserved = 0;
1135+
ftsn_skip_arr[skip_pos].flags = flags;
1136+
ftsn_skip_arr[skip_pos].mid = mid;
1137+
if (skip_pos == nskips)
1138+
nskips++;
1139+
if (nskips == 10)
1140+
break;
1141+
} else {
1142+
break;
1143+
}
1144+
}
1145+
1146+
if (asoc->adv_peer_ack_point > ctsn)
1147+
ftsn_chunk = sctp_make_ifwdtsn(asoc, asoc->adv_peer_ack_point,
1148+
nskips, &ftsn_skip_arr[0]);
1149+
1150+
if (ftsn_chunk) {
1151+
list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
1152+
SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_OUTCTRLCHUNKS);
1153+
}
1154+
}
1155+
10851156
static struct sctp_stream_interleave sctp_stream_interleave_0 = {
10861157
.data_chunk_len = sizeof(struct sctp_data_chunk),
10871158
/* DATA process functions */
@@ -1093,6 +1164,8 @@ static struct sctp_stream_interleave sctp_stream_interleave_0 = {
10931164
.renege_events = sctp_ulpq_renege,
10941165
.start_pd = sctp_ulpq_partial_delivery,
10951166
.abort_pd = sctp_ulpq_abort_pd,
1167+
/* FORWARD-TSN process functions */
1168+
.generate_ftsn = sctp_generate_fwdtsn,
10961169
};
10971170

10981171
static struct sctp_stream_interleave sctp_stream_interleave_1 = {
@@ -1106,6 +1179,8 @@ static struct sctp_stream_interleave sctp_stream_interleave_1 = {
11061179
.renege_events = sctp_renege_events,
11071180
.start_pd = sctp_intl_start_pd,
11081181
.abort_pd = sctp_intl_abort_pd,
1182+
/* I-FORWARD-TSN process functions */
1183+
.generate_ftsn = sctp_generate_iftsn,
11091184
};
11101185

11111186
void sctp_stream_interleave_init(struct sctp_stream *stream)

0 commit comments

Comments
 (0)