aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2017-05-31 04:36:31 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-02 13:56:26 -0400
commitcee360ab4dd66fc1de33a5fa1cb418fa21c27ce3 (patch)
treedb9b8575e7392b314e94a946590b71bb5c856e64
parent6e7da286e3513ac1e107ef8dffa5f254029d68e7 (diff)
sctp: define the member stream as an object instead of pointer in asoc
As Marcelo's suggestion, stream is a fixed size member of asoc and would not grow with more streams. To avoid an allocation for it, this patch is to define it as an object instead of pointer and update the places using it, also create sctp_stream_update() called in sctp_assoc_update() to migrate the stream info from one stream to another. Signed-off-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sctp/structs.h3
-rw-r--r--net/sctp/associola.c13
-rw-r--r--net/sctp/chunk.c4
-rw-r--r--net/sctp/outqueue.c10
-rw-r--r--net/sctp/proc.c4
-rw-r--r--net/sctp/sm_make_chunk.c2
-rw-r--r--net/sctp/sm_statefuns.c8
-rw-r--r--net/sctp/socket.c14
-rw-r--r--net/sctp/stream.c68
-rw-r--r--net/sctp/ulpqueue.c8
10 files changed, 65 insertions, 69 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index a8b38e123f97..c8dbf410c4f5 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -381,6 +381,7 @@ int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp);
381int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp); 381int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp);
382void sctp_stream_free(struct sctp_stream *stream); 382void sctp_stream_free(struct sctp_stream *stream);
383void sctp_stream_clear(struct sctp_stream *stream); 383void sctp_stream_clear(struct sctp_stream *stream);
384void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new);
384 385
385/* What is the current SSN number for this stream? */ 386/* What is the current SSN number for this stream? */
386#define sctp_ssn_peek(stream, type, sid) \ 387#define sctp_ssn_peek(stream, type, sid) \
@@ -1750,7 +1751,7 @@ struct sctp_association {
1750 __u32 default_rcv_context; 1751 __u32 default_rcv_context;
1751 1752
1752 /* Stream arrays */ 1753 /* Stream arrays */
1753 struct sctp_stream *stream; 1754 struct sctp_stream stream;
1754 1755
1755 /* All outbound chunks go through this structure. */ 1756 /* All outbound chunks go through this structure. */
1756 struct sctp_outq outqueue; 1757 struct sctp_outq outqueue;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 95238284c422..6625b15ab81a 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -291,7 +291,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
291 return asoc; 291 return asoc;
292 292
293stream_free: 293stream_free:
294 sctp_stream_free(asoc->stream); 294 sctp_stream_free(&asoc->stream);
295fail_init: 295fail_init:
296 sock_put(asoc->base.sk); 296 sock_put(asoc->base.sk);
297 sctp_endpoint_put(asoc->ep); 297 sctp_endpoint_put(asoc->ep);
@@ -365,7 +365,7 @@ void sctp_association_free(struct sctp_association *asoc)
365 sctp_tsnmap_free(&asoc->peer.tsn_map); 365 sctp_tsnmap_free(&asoc->peer.tsn_map);
366 366
367 /* Free stream information. */ 367 /* Free stream information. */
368 sctp_stream_free(asoc->stream); 368 sctp_stream_free(&asoc->stream);
369 369
370 if (asoc->strreset_chunk) 370 if (asoc->strreset_chunk)
371 sctp_chunk_free(asoc->strreset_chunk); 371 sctp_chunk_free(asoc->strreset_chunk);
@@ -1151,7 +1151,7 @@ void sctp_assoc_update(struct sctp_association *asoc,
1151 /* Reinitialize SSN for both local streams 1151 /* Reinitialize SSN for both local streams
1152 * and peer's streams. 1152 * and peer's streams.
1153 */ 1153 */
1154 sctp_stream_clear(asoc->stream); 1154 sctp_stream_clear(&asoc->stream);
1155 1155
1156 /* Flush the ULP reassembly and ordered queue. 1156 /* Flush the ULP reassembly and ordered queue.
1157 * Any data there will now be stale and will 1157 * Any data there will now be stale and will
@@ -1177,11 +1177,8 @@ void sctp_assoc_update(struct sctp_association *asoc,
1177 asoc->ctsn_ack_point = asoc->next_tsn - 1; 1177 asoc->ctsn_ack_point = asoc->next_tsn - 1;
1178 asoc->adv_peer_ack_point = asoc->ctsn_ack_point; 1178 asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
1179 1179
1180 if (sctp_state(asoc, COOKIE_WAIT)) { 1180 if (sctp_state(asoc, COOKIE_WAIT))
1181 sctp_stream_free(asoc->stream); 1181 sctp_stream_update(&asoc->stream, &new->stream);
1182 asoc->stream = new->stream;
1183 new->stream = NULL;
1184 }
1185 1182
1186 if (!asoc->assoc_id) { 1183 if (!asoc->assoc_id) {
1187 /* get a new association id since we don't have one 1184 /* get a new association id since we don't have one
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 697721a7a3f1..81466f6442e8 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -307,7 +307,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
307 if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) && 307 if (SCTP_PR_TTL_ENABLED(chunk->sinfo.sinfo_flags) &&
308 time_after(jiffies, chunk->msg->expires_at)) { 308 time_after(jiffies, chunk->msg->expires_at)) {
309 struct sctp_stream_out *streamout = 309 struct sctp_stream_out *streamout =
310 &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream]; 310 &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
311 311
312 if (chunk->sent_count) { 312 if (chunk->sent_count) {
313 chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++; 313 chunk->asoc->abandoned_sent[SCTP_PR_INDEX(TTL)]++;
@@ -320,7 +320,7 @@ int sctp_chunk_abandoned(struct sctp_chunk *chunk)
320 } else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) && 320 } else if (SCTP_PR_RTX_ENABLED(chunk->sinfo.sinfo_flags) &&
321 chunk->sent_count > chunk->sinfo.sinfo_timetolive) { 321 chunk->sent_count > chunk->sinfo.sinfo_timetolive) {
322 struct sctp_stream_out *streamout = 322 struct sctp_stream_out *streamout =
323 &chunk->asoc->stream->out[chunk->sinfo.sinfo_stream]; 323 &chunk->asoc->stream.out[chunk->sinfo.sinfo_stream];
324 324
325 chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++; 325 chunk->asoc->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
326 streamout->abandoned_sent[SCTP_PR_INDEX(RTX)]++; 326 streamout->abandoned_sent[SCTP_PR_INDEX(RTX)]++;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index fe4c3d462f6e..20299df163b9 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -363,7 +363,7 @@ static int sctp_prsctp_prune_sent(struct sctp_association *asoc,
363 sctp_insert_list(&asoc->outqueue.abandoned, 363 sctp_insert_list(&asoc->outqueue.abandoned,
364 &chk->transmitted_list); 364 &chk->transmitted_list);
365 365
366 streamout = &asoc->stream->out[chk->sinfo.sinfo_stream]; 366 streamout = &asoc->stream.out[chk->sinfo.sinfo_stream];
367 asoc->sent_cnt_removable--; 367 asoc->sent_cnt_removable--;
368 asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; 368 asoc->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
369 streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++; 369 streamout->abandoned_sent[SCTP_PR_INDEX(PRIO)]++;
@@ -400,9 +400,9 @@ static int sctp_prsctp_prune_unsent(struct sctp_association *asoc,
400 q->out_qlen -= chk->skb->len; 400 q->out_qlen -= chk->skb->len;
401 asoc->sent_cnt_removable--; 401 asoc->sent_cnt_removable--;
402 asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 402 asoc->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
403 if (chk->sinfo.sinfo_stream < asoc->stream->outcnt) { 403 if (chk->sinfo.sinfo_stream < asoc->stream.outcnt) {
404 struct sctp_stream_out *streamout = 404 struct sctp_stream_out *streamout =
405 &asoc->stream->out[chk->sinfo.sinfo_stream]; 405 &asoc->stream.out[chk->sinfo.sinfo_stream];
406 406
407 streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++; 407 streamout->abandoned_unsent[SCTP_PR_INDEX(PRIO)]++;
408 } 408 }
@@ -1036,7 +1036,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
1036 /* RFC 2960 6.5 Every DATA chunk MUST carry a valid 1036 /* RFC 2960 6.5 Every DATA chunk MUST carry a valid
1037 * stream identifier. 1037 * stream identifier.
1038 */ 1038 */
1039 if (chunk->sinfo.sinfo_stream >= asoc->stream->outcnt) { 1039 if (chunk->sinfo.sinfo_stream >= asoc->stream.outcnt) {
1040 1040
1041 /* Mark as failed send. */ 1041 /* Mark as failed send. */
1042 sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM); 1042 sctp_chunk_fail(chunk, SCTP_ERROR_INV_STRM);
@@ -1054,7 +1054,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
1054 continue; 1054 continue;
1055 } 1055 }
1056 1056
1057 if (asoc->stream->out[sid].state == SCTP_STREAM_CLOSED) { 1057 if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
1058 sctp_outq_head_data(q, chunk); 1058 sctp_outq_head_data(q, chunk);
1059 goto sctp_flush_out; 1059 goto sctp_flush_out;
1060 } 1060 }
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index a0b29d43627f..5a27d0f03df5 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -361,8 +361,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
361 sctp_seq_dump_remote_addrs(seq, assoc); 361 sctp_seq_dump_remote_addrs(seq, assoc);
362 seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d " 362 seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d "
363 "%8d %8d %8d %8d", 363 "%8d %8d %8d %8d",
364 assoc->hbinterval, assoc->stream->incnt, 364 assoc->hbinterval, assoc->stream.incnt,
365 assoc->stream->outcnt, assoc->max_retrans, 365 assoc->stream.outcnt, assoc->max_retrans,
366 assoc->init_retries, assoc->shutdown_retries, 366 assoc->init_retries, assoc->shutdown_retries,
367 assoc->rtx_data_chunks, 367 assoc->rtx_data_chunks,
368 atomic_read(&sk->sk_wmem_alloc), 368 atomic_read(&sk->sk_wmem_alloc),
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 92e332e17391..244181413bca 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1544,7 +1544,7 @@ void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
1544 1544
1545 /* All fragments will be on the same stream */ 1545 /* All fragments will be on the same stream */
1546 sid = ntohs(chunk->subh.data_hdr->stream); 1546 sid = ntohs(chunk->subh.data_hdr->stream);
1547 stream = chunk->asoc->stream; 1547 stream = &chunk->asoc->stream;
1548 1548
1549 /* Now assign the sequence number to the entire message. 1549 /* Now assign the sequence number to the entire message.
1550 * All fragments must have the same stream sequence number. 1550 * All fragments must have the same stream sequence number.
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index f863b5573e42..df73190da761 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3958,7 +3958,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net,
3958 3958
3959 /* Silently discard the chunk if stream-id is not valid */ 3959 /* Silently discard the chunk if stream-id is not valid */
3960 sctp_walk_fwdtsn(skip, chunk) { 3960 sctp_walk_fwdtsn(skip, chunk) {
3961 if (ntohs(skip->stream) >= asoc->stream->incnt) 3961 if (ntohs(skip->stream) >= asoc->stream.incnt)
3962 goto discard_noforce; 3962 goto discard_noforce;
3963 } 3963 }
3964 3964
@@ -4029,7 +4029,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
4029 4029
4030 /* Silently discard the chunk if stream-id is not valid */ 4030 /* Silently discard the chunk if stream-id is not valid */
4031 sctp_walk_fwdtsn(skip, chunk) { 4031 sctp_walk_fwdtsn(skip, chunk) {
4032 if (ntohs(skip->stream) >= asoc->stream->incnt) 4032 if (ntohs(skip->stream) >= asoc->stream.incnt)
4033 goto gen_shutdown; 4033 goto gen_shutdown;
4034 } 4034 }
4035 4035
@@ -6365,7 +6365,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
6365 * and discard the DATA chunk. 6365 * and discard the DATA chunk.
6366 */ 6366 */
6367 sid = ntohs(data_hdr->stream); 6367 sid = ntohs(data_hdr->stream);
6368 if (sid >= asoc->stream->incnt) { 6368 if (sid >= asoc->stream.incnt) {
6369 /* Mark tsn as received even though we drop it */ 6369 /* Mark tsn as received even though we drop it */
6370 sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); 6370 sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn));
6371 6371
@@ -6387,7 +6387,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
6387 * and is invalid. 6387 * and is invalid.
6388 */ 6388 */
6389 ssn = ntohs(data_hdr->ssn); 6389 ssn = ntohs(data_hdr->ssn);
6390 if (ordered && SSN_lt(ssn, sctp_ssn_peek(asoc->stream, in, sid))) 6390 if (ordered && SSN_lt(ssn, sctp_ssn_peek(&asoc->stream, in, sid)))
6391 return SCTP_IERROR_PROTO_VIOLATION; 6391 return SCTP_IERROR_PROTO_VIOLATION;
6392 6392
6393 /* Send the data up to the user. Note: Schedule the 6393 /* Send the data up to the user. Note: Schedule the
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index f16c8d97b7f3..0822046e4f3f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1920,7 +1920,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
1920 } 1920 }
1921 1921
1922 /* Check for invalid stream. */ 1922 /* Check for invalid stream. */
1923 if (sinfo->sinfo_stream >= asoc->stream->outcnt) { 1923 if (sinfo->sinfo_stream >= asoc->stream.outcnt) {
1924 err = -EINVAL; 1924 err = -EINVAL;
1925 goto out_free; 1925 goto out_free;
1926 } 1926 }
@@ -4497,8 +4497,8 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
4497 info->sctpi_rwnd = asoc->a_rwnd; 4497 info->sctpi_rwnd = asoc->a_rwnd;
4498 info->sctpi_unackdata = asoc->unack_data; 4498 info->sctpi_unackdata = asoc->unack_data;
4499 info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 4499 info->sctpi_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
4500 info->sctpi_instrms = asoc->stream->incnt; 4500 info->sctpi_instrms = asoc->stream.incnt;
4501 info->sctpi_outstrms = asoc->stream->outcnt; 4501 info->sctpi_outstrms = asoc->stream.outcnt;
4502 list_for_each(pos, &asoc->base.inqueue.in_chunk_list) 4502 list_for_each(pos, &asoc->base.inqueue.in_chunk_list)
4503 info->sctpi_inqueue++; 4503 info->sctpi_inqueue++;
4504 list_for_each(pos, &asoc->outqueue.out_chunk_list) 4504 list_for_each(pos, &asoc->outqueue.out_chunk_list)
@@ -4727,8 +4727,8 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len,
4727 status.sstat_unackdata = asoc->unack_data; 4727 status.sstat_unackdata = asoc->unack_data;
4728 4728
4729 status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map); 4729 status.sstat_penddata = sctp_tsnmap_pending(&asoc->peer.tsn_map);
4730 status.sstat_instrms = asoc->stream->incnt; 4730 status.sstat_instrms = asoc->stream.incnt;
4731 status.sstat_outstrms = asoc->stream->outcnt; 4731 status.sstat_outstrms = asoc->stream.outcnt;
4732 status.sstat_fragmentation_point = asoc->frag_point; 4732 status.sstat_fragmentation_point = asoc->frag_point;
4733 status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc); 4733 status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
4734 memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr, 4734 memcpy(&status.sstat_primary.spinfo_address, &transport->ipaddr,
@@ -6600,10 +6600,10 @@ static int sctp_getsockopt_pr_streamstatus(struct sock *sk, int len,
6600 goto out; 6600 goto out;
6601 6601
6602 asoc = sctp_id2assoc(sk, params.sprstat_assoc_id); 6602 asoc = sctp_id2assoc(sk, params.sprstat_assoc_id);
6603 if (!asoc || params.sprstat_sid >= asoc->stream->outcnt) 6603 if (!asoc || params.sprstat_sid >= asoc->stream.outcnt)
6604 goto out; 6604 goto out;
6605 6605
6606 streamout = &asoc->stream->out[params.sprstat_sid]; 6606 streamout = &asoc->stream.out[params.sprstat_sid];
6607 if (policy == SCTP_PR_SCTP_NONE) { 6607 if (policy == SCTP_PR_SCTP_NONE) {
6608 params.sprstat_abandoned_unsent = 0; 6608 params.sprstat_abandoned_unsent = 0;
6609 params.sprstat_abandoned_sent = 0; 6609 params.sprstat_abandoned_sent = 0;
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index dda53a293986..af6b49850344 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -37,30 +37,23 @@
37 37
38int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp) 38int sctp_stream_new(struct sctp_association *asoc, gfp_t gfp)
39{ 39{
40 struct sctp_stream *stream; 40 struct sctp_stream *stream = &asoc->stream;
41 int i; 41 int i;
42 42
43 stream = kzalloc(sizeof(*stream), gfp);
44 if (!stream)
45 return -ENOMEM;
46
47 stream->outcnt = asoc->c.sinit_num_ostreams; 43 stream->outcnt = asoc->c.sinit_num_ostreams;
48 stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); 44 stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
49 if (!stream->out) { 45 if (!stream->out)
50 kfree(stream);
51 return -ENOMEM; 46 return -ENOMEM;
52 } 47
53 for (i = 0; i < stream->outcnt; i++) 48 for (i = 0; i < stream->outcnt; i++)
54 stream->out[i].state = SCTP_STREAM_OPEN; 49 stream->out[i].state = SCTP_STREAM_OPEN;
55 50
56 asoc->stream = stream;
57
58 return 0; 51 return 0;
59} 52}
60 53
61int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp) 54int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp)
62{ 55{
63 struct sctp_stream *stream = asoc->stream; 56 struct sctp_stream *stream = &asoc->stream;
64 int i; 57 int i;
65 58
66 /* Initial stream->out size may be very big, so free it and alloc 59 /* Initial stream->out size may be very big, so free it and alloc
@@ -70,7 +63,7 @@ int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp)
70 stream->outcnt = asoc->c.sinit_num_ostreams; 63 stream->outcnt = asoc->c.sinit_num_ostreams;
71 stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp); 64 stream->out = kcalloc(stream->outcnt, sizeof(*stream->out), gfp);
72 if (!stream->out) 65 if (!stream->out)
73 goto nomem; 66 return -ENOMEM;
74 67
75 for (i = 0; i < stream->outcnt; i++) 68 for (i = 0; i < stream->outcnt; i++)
76 stream->out[i].state = SCTP_STREAM_OPEN; 69 stream->out[i].state = SCTP_STREAM_OPEN;
@@ -79,26 +72,17 @@ int sctp_stream_init(struct sctp_association *asoc, gfp_t gfp)
79 stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp); 72 stream->in = kcalloc(stream->incnt, sizeof(*stream->in), gfp);
80 if (!stream->in) { 73 if (!stream->in) {
81 kfree(stream->out); 74 kfree(stream->out);
82 goto nomem; 75 stream->out = NULL;
76 return -ENOMEM;
83 } 77 }
84 78
85 return 0; 79 return 0;
86
87nomem:
88 asoc->stream = NULL;
89 kfree(stream);
90
91 return -ENOMEM;
92} 80}
93 81
94void sctp_stream_free(struct sctp_stream *stream) 82void sctp_stream_free(struct sctp_stream *stream)
95{ 83{
96 if (unlikely(!stream))
97 return;
98
99 kfree(stream->out); 84 kfree(stream->out);
100 kfree(stream->in); 85 kfree(stream->in);
101 kfree(stream);
102} 86}
103 87
104void sctp_stream_clear(struct sctp_stream *stream) 88void sctp_stream_clear(struct sctp_stream *stream)
@@ -112,6 +96,19 @@ void sctp_stream_clear(struct sctp_stream *stream)
112 stream->in[i].ssn = 0; 96 stream->in[i].ssn = 0;
113} 97}
114 98
99void sctp_stream_update(struct sctp_stream *stream, struct sctp_stream *new)
100{
101 sctp_stream_free(stream);
102
103 stream->out = new->out;
104 stream->in = new->in;
105 stream->outcnt = new->outcnt;
106 stream->incnt = new->incnt;
107
108 new->out = NULL;
109 new->in = NULL;
110}
111
115static int sctp_send_reconf(struct sctp_association *asoc, 112static int sctp_send_reconf(struct sctp_association *asoc,
116 struct sctp_chunk *chunk) 113 struct sctp_chunk *chunk)
117{ 114{
@@ -128,7 +125,7 @@ static int sctp_send_reconf(struct sctp_association *asoc,
128int sctp_send_reset_streams(struct sctp_association *asoc, 125int sctp_send_reset_streams(struct sctp_association *asoc,
129 struct sctp_reset_streams *params) 126 struct sctp_reset_streams *params)
130{ 127{
131 struct sctp_stream *stream = asoc->stream; 128 struct sctp_stream *stream = &asoc->stream;
132 __u16 i, str_nums, *str_list; 129 __u16 i, str_nums, *str_list;
133 struct sctp_chunk *chunk; 130 struct sctp_chunk *chunk;
134 int retval = -EINVAL; 131 int retval = -EINVAL;
@@ -214,6 +211,7 @@ out:
214 211
215int sctp_send_reset_assoc(struct sctp_association *asoc) 212int sctp_send_reset_assoc(struct sctp_association *asoc)
216{ 213{
214 struct sctp_stream *stream = &asoc->stream;
217 struct sctp_chunk *chunk = NULL; 215 struct sctp_chunk *chunk = NULL;
218 int retval; 216 int retval;
219 __u16 i; 217 __u16 i;
@@ -230,8 +228,8 @@ int sctp_send_reset_assoc(struct sctp_association *asoc)
230 return -ENOMEM; 228 return -ENOMEM;
231 229
232 /* Block further xmit of data until this request is completed */ 230 /* Block further xmit of data until this request is completed */
233 for (i = 0; i < asoc->stream->outcnt; i++) 231 for (i = 0; i < stream->outcnt; i++)
234 asoc->stream->out[i].state = SCTP_STREAM_CLOSED; 232 stream->out[i].state = SCTP_STREAM_CLOSED;
235 233
236 asoc->strreset_chunk = chunk; 234 asoc->strreset_chunk = chunk;
237 sctp_chunk_hold(asoc->strreset_chunk); 235 sctp_chunk_hold(asoc->strreset_chunk);
@@ -241,8 +239,8 @@ int sctp_send_reset_assoc(struct sctp_association *asoc)
241 sctp_chunk_put(asoc->strreset_chunk); 239 sctp_chunk_put(asoc->strreset_chunk);
242 asoc->strreset_chunk = NULL; 240 asoc->strreset_chunk = NULL;
243 241
244 for (i = 0; i < asoc->stream->outcnt; i++) 242 for (i = 0; i < stream->outcnt; i++)
245 asoc->stream->out[i].state = SCTP_STREAM_OPEN; 243 stream->out[i].state = SCTP_STREAM_OPEN;
246 244
247 return retval; 245 return retval;
248 } 246 }
@@ -255,7 +253,7 @@ int sctp_send_reset_assoc(struct sctp_association *asoc)
255int sctp_send_add_streams(struct sctp_association *asoc, 253int sctp_send_add_streams(struct sctp_association *asoc,
256 struct sctp_add_streams *params) 254 struct sctp_add_streams *params)
257{ 255{
258 struct sctp_stream *stream = asoc->stream; 256 struct sctp_stream *stream = &asoc->stream;
259 struct sctp_chunk *chunk = NULL; 257 struct sctp_chunk *chunk = NULL;
260 int retval = -ENOMEM; 258 int retval = -ENOMEM;
261 __u32 outcnt, incnt; 259 __u32 outcnt, incnt;
@@ -357,7 +355,7 @@ struct sctp_chunk *sctp_process_strreset_outreq(
357 struct sctp_ulpevent **evp) 355 struct sctp_ulpevent **evp)
358{ 356{
359 struct sctp_strreset_outreq *outreq = param.v; 357 struct sctp_strreset_outreq *outreq = param.v;
360 struct sctp_stream *stream = asoc->stream; 358 struct sctp_stream *stream = &asoc->stream;
361 __u16 i, nums, flags = 0, *str_p = NULL; 359 __u16 i, nums, flags = 0, *str_p = NULL;
362 __u32 result = SCTP_STRRESET_DENIED; 360 __u32 result = SCTP_STRRESET_DENIED;
363 __u32 request_seq; 361 __u32 request_seq;
@@ -449,7 +447,7 @@ struct sctp_chunk *sctp_process_strreset_inreq(
449 struct sctp_ulpevent **evp) 447 struct sctp_ulpevent **evp)
450{ 448{
451 struct sctp_strreset_inreq *inreq = param.v; 449 struct sctp_strreset_inreq *inreq = param.v;
452 struct sctp_stream *stream = asoc->stream; 450 struct sctp_stream *stream = &asoc->stream;
453 __u32 result = SCTP_STRRESET_DENIED; 451 __u32 result = SCTP_STRRESET_DENIED;
454 struct sctp_chunk *chunk = NULL; 452 struct sctp_chunk *chunk = NULL;
455 __u16 i, nums, *str_p; 453 __u16 i, nums, *str_p;
@@ -523,7 +521,7 @@ struct sctp_chunk *sctp_process_strreset_tsnreq(
523{ 521{
524 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen; 522 __u32 init_tsn = 0, next_tsn = 0, max_tsn_seen;
525 struct sctp_strreset_tsnreq *tsnreq = param.v; 523 struct sctp_strreset_tsnreq *tsnreq = param.v;
526 struct sctp_stream *stream = asoc->stream; 524 struct sctp_stream *stream = &asoc->stream;
527 __u32 result = SCTP_STRRESET_DENIED; 525 __u32 result = SCTP_STRRESET_DENIED;
528 __u32 request_seq; 526 __u32 request_seq;
529 __u16 i; 527 __u16 i;
@@ -612,7 +610,7 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out(
612 struct sctp_ulpevent **evp) 610 struct sctp_ulpevent **evp)
613{ 611{
614 struct sctp_strreset_addstrm *addstrm = param.v; 612 struct sctp_strreset_addstrm *addstrm = param.v;
615 struct sctp_stream *stream = asoc->stream; 613 struct sctp_stream *stream = &asoc->stream;
616 __u32 result = SCTP_STRRESET_DENIED; 614 __u32 result = SCTP_STRRESET_DENIED;
617 struct sctp_stream_in *streamin; 615 struct sctp_stream_in *streamin;
618 __u32 request_seq, incnt; 616 __u32 request_seq, incnt;
@@ -687,7 +685,7 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
687 struct sctp_ulpevent **evp) 685 struct sctp_ulpevent **evp)
688{ 686{
689 struct sctp_strreset_addstrm *addstrm = param.v; 687 struct sctp_strreset_addstrm *addstrm = param.v;
690 struct sctp_stream *stream = asoc->stream; 688 struct sctp_stream *stream = &asoc->stream;
691 __u32 result = SCTP_STRRESET_DENIED; 689 __u32 result = SCTP_STRRESET_DENIED;
692 struct sctp_stream_out *streamout; 690 struct sctp_stream_out *streamout;
693 struct sctp_chunk *chunk = NULL; 691 struct sctp_chunk *chunk = NULL;
@@ -758,8 +756,8 @@ struct sctp_chunk *sctp_process_strreset_resp(
758 union sctp_params param, 756 union sctp_params param,
759 struct sctp_ulpevent **evp) 757 struct sctp_ulpevent **evp)
760{ 758{
759 struct sctp_stream *stream = &asoc->stream;
761 struct sctp_strreset_resp *resp = param.v; 760 struct sctp_strreset_resp *resp = param.v;
762 struct sctp_stream *stream = asoc->stream;
763 struct sctp_transport *t; 761 struct sctp_transport *t;
764 __u16 i, nums, flags = 0; 762 __u16 i, nums, flags = 0;
765 sctp_paramhdr_t *req; 763 sctp_paramhdr_t *req;
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index aa3624d50278..25f7e4140566 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -764,7 +764,7 @@ static void sctp_ulpq_retrieve_ordered(struct sctp_ulpq *ulpq,
764 __u16 sid, csid, cssn; 764 __u16 sid, csid, cssn;
765 765
766 sid = event->stream; 766 sid = event->stream;
767 stream = ulpq->asoc->stream; 767 stream = &ulpq->asoc->stream;
768 768
769 event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev; 769 event_list = (struct sk_buff_head *) sctp_event2skb(event)->prev;
770 770
@@ -858,7 +858,7 @@ static struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
858 /* Note: The stream ID must be verified before this routine. */ 858 /* Note: The stream ID must be verified before this routine. */
859 sid = event->stream; 859 sid = event->stream;
860 ssn = event->ssn; 860 ssn = event->ssn;
861 stream = ulpq->asoc->stream; 861 stream = &ulpq->asoc->stream;
862 862
863 /* Is this the expected SSN for this stream ID? */ 863 /* Is this the expected SSN for this stream ID? */
864 if (ssn != sctp_ssn_peek(stream, in, sid)) { 864 if (ssn != sctp_ssn_peek(stream, in, sid)) {
@@ -893,7 +893,7 @@ static void sctp_ulpq_reap_ordered(struct sctp_ulpq *ulpq, __u16 sid)
893 struct sk_buff_head *lobby = &ulpq->lobby; 893 struct sk_buff_head *lobby = &ulpq->lobby;
894 __u16 csid, cssn; 894 __u16 csid, cssn;
895 895
896 stream = ulpq->asoc->stream; 896 stream = &ulpq->asoc->stream;
897 897
898 /* We are holding the chunks by stream, by SSN. */ 898 /* We are holding the chunks by stream, by SSN. */
899 skb_queue_head_init(&temp); 899 skb_queue_head_init(&temp);
@@ -958,7 +958,7 @@ void sctp_ulpq_skip(struct sctp_ulpq *ulpq, __u16 sid, __u16 ssn)
958 struct sctp_stream *stream; 958 struct sctp_stream *stream;
959 959
960 /* Note: The stream ID must be verified before this routine. */ 960 /* Note: The stream ID must be verified before this routine. */
961 stream = ulpq->asoc->stream; 961 stream = &ulpq->asoc->stream;
962 962
963 /* Is this an old SSN? If so ignore. */ 963 /* Is this an old SSN? If so ignore. */
964 if (SSN_lt(ssn, sctp_ssn_peek(stream, in, sid))) 964 if (SSN_lt(ssn, sctp_ssn_peek(stream, in, sid)))