aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/stream.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/stream.c')
-rw-r--r--net/sctp/stream.c82
1 files changed, 48 insertions, 34 deletions
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 3892e7630f3a..2936ed17bf9e 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -84,6 +84,19 @@ static void fa_zero(struct flex_array *fa, size_t index, size_t count)
84 } 84 }
85} 85}
86 86
87static size_t fa_index(struct flex_array *fa, void *elem, size_t count)
88{
89 size_t index = 0;
90
91 while (count--) {
92 if (elem == flex_array_get(fa, index))
93 break;
94 index++;
95 }
96
97 return index;
98}
99
87/* Migrates chunks from stream queues to new stream queues if needed, 100/* Migrates chunks from stream queues to new stream queues if needed,
88 * but not across associations. Also, removes those chunks to streams 101 * but not across associations. Also, removes those chunks to streams
89 * higher than the new max. 102 * higher than the new max.
@@ -131,8 +144,10 @@ static void sctp_stream_outq_migrate(struct sctp_stream *stream,
131 } 144 }
132 } 145 }
133 146
134 for (i = outcnt; i < stream->outcnt; i++) 147 for (i = outcnt; i < stream->outcnt; i++) {
135 kfree(SCTP_SO(stream, i)->ext); 148 kfree(SCTP_SO(stream, i)->ext);
149 SCTP_SO(stream, i)->ext = NULL;
150 }
136} 151}
137 152
138static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, 153static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
@@ -147,6 +162,13 @@ static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt,
147 162
148 if (stream->out) { 163 if (stream->out) {
149 fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt)); 164 fa_copy(out, stream->out, 0, min(outcnt, stream->outcnt));
165 if (stream->out_curr) {
166 size_t index = fa_index(stream->out, stream->out_curr,
167 stream->outcnt);
168
169 BUG_ON(index == stream->outcnt);
170 stream->out_curr = flex_array_get(out, index);
171 }
150 fa_free(stream->out); 172 fa_free(stream->out);
151 } 173 }
152 174
@@ -585,9 +607,9 @@ struct sctp_chunk *sctp_process_strreset_outreq(
585 struct sctp_strreset_outreq *outreq = param.v; 607 struct sctp_strreset_outreq *outreq = param.v;
586 struct sctp_stream *stream = &asoc->stream; 608 struct sctp_stream *stream = &asoc->stream;
587 __u32 result = SCTP_STRRESET_DENIED; 609 __u32 result = SCTP_STRRESET_DENIED;
588 __u16 i, nums, flags = 0;
589 __be16 *str_p = NULL; 610 __be16 *str_p = NULL;
590 __u32 request_seq; 611 __u32 request_seq;
612 __u16 i, nums;
591 613
592 request_seq = ntohl(outreq->request_seq); 614 request_seq = ntohl(outreq->request_seq);
593 615
@@ -615,6 +637,15 @@ struct sctp_chunk *sctp_process_strreset_outreq(
615 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ)) 637 if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
616 goto out; 638 goto out;
617 639
640 nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16);
641 str_p = outreq->list_of_streams;
642 for (i = 0; i < nums; i++) {
643 if (ntohs(str_p[i]) >= stream->incnt) {
644 result = SCTP_STRRESET_ERR_WRONG_SSN;
645 goto out;
646 }
647 }
648
618 if (asoc->strreset_chunk) { 649 if (asoc->strreset_chunk) {
619 if (!sctp_chunk_lookup_strreset_param( 650 if (!sctp_chunk_lookup_strreset_param(
620 asoc, outreq->response_seq, 651 asoc, outreq->response_seq,
@@ -637,32 +668,19 @@ struct sctp_chunk *sctp_process_strreset_outreq(
637 sctp_chunk_put(asoc->strreset_chunk); 668 sctp_chunk_put(asoc->strreset_chunk);
638 asoc->strreset_chunk = NULL; 669 asoc->strreset_chunk = NULL;
639 } 670 }
640
641 flags = SCTP_STREAM_RESET_INCOMING_SSN;
642 } 671 }
643 672
644 nums = (ntohs(param.p->length) - sizeof(*outreq)) / sizeof(__u16); 673 if (nums)
645 if (nums) {
646 str_p = outreq->list_of_streams;
647 for (i = 0; i < nums; i++) {
648 if (ntohs(str_p[i]) >= stream->incnt) {
649 result = SCTP_STRRESET_ERR_WRONG_SSN;
650 goto out;
651 }
652 }
653
654 for (i = 0; i < nums; i++) 674 for (i = 0; i < nums; i++)
655 SCTP_SI(stream, ntohs(str_p[i]))->mid = 0; 675 SCTP_SI(stream, ntohs(str_p[i]))->mid = 0;
656 } else { 676 else
657 for (i = 0; i < stream->incnt; i++) 677 for (i = 0; i < stream->incnt; i++)
658 SCTP_SI(stream, i)->mid = 0; 678 SCTP_SI(stream, i)->mid = 0;
659 }
660 679
661 result = SCTP_STRRESET_PERFORMED; 680 result = SCTP_STRRESET_PERFORMED;
662 681
663 *evp = sctp_ulpevent_make_stream_reset_event(asoc, 682 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
664 flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p, 683 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
665 GFP_ATOMIC);
666 684
667out: 685out:
668 sctp_update_strreset_result(asoc, result); 686 sctp_update_strreset_result(asoc, result);
@@ -738,9 +756,6 @@ struct sctp_chunk *sctp_process_strreset_inreq(
738 756
739 result = SCTP_STRRESET_PERFORMED; 757 result = SCTP_STRRESET_PERFORMED;
740 758
741 *evp = sctp_ulpevent_make_stream_reset_event(asoc,
742 SCTP_STREAM_RESET_INCOMING_SSN, nums, str_p, GFP_ATOMIC);
743
744out: 759out:
745 sctp_update_strreset_result(asoc, result); 760 sctp_update_strreset_result(asoc, result);
746err: 761err:
@@ -873,6 +888,14 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out(
873 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ)) 888 if (!(asoc->strreset_enable & SCTP_ENABLE_CHANGE_ASSOC_REQ))
874 goto out; 889 goto out;
875 890
891 in = ntohs(addstrm->number_of_streams);
892 incnt = stream->incnt + in;
893 if (!in || incnt > SCTP_MAX_STREAM)
894 goto out;
895
896 if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
897 goto out;
898
876 if (asoc->strreset_chunk) { 899 if (asoc->strreset_chunk) {
877 if (!sctp_chunk_lookup_strreset_param( 900 if (!sctp_chunk_lookup_strreset_param(
878 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) { 901 asoc, 0, SCTP_PARAM_RESET_ADD_IN_STREAMS)) {
@@ -896,14 +919,6 @@ struct sctp_chunk *sctp_process_strreset_addstrm_out(
896 } 919 }
897 } 920 }
898 921
899 in = ntohs(addstrm->number_of_streams);
900 incnt = stream->incnt + in;
901 if (!in || incnt > SCTP_MAX_STREAM)
902 goto out;
903
904 if (sctp_stream_alloc_in(stream, incnt, GFP_ATOMIC))
905 goto out;
906
907 stream->incnt = incnt; 922 stream->incnt = incnt;
908 923
909 result = SCTP_STRRESET_PERFORMED; 924 result = SCTP_STRRESET_PERFORMED;
@@ -973,9 +988,6 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
973 988
974 result = SCTP_STRRESET_PERFORMED; 989 result = SCTP_STRRESET_PERFORMED;
975 990
976 *evp = sctp_ulpevent_make_stream_change_event(asoc,
977 0, 0, ntohs(addstrm->number_of_streams), GFP_ATOMIC);
978
979out: 991out:
980 sctp_update_strreset_result(asoc, result); 992 sctp_update_strreset_result(asoc, result);
981err: 993err:
@@ -1036,10 +1048,10 @@ struct sctp_chunk *sctp_process_strreset_resp(
1036 sout->mid_uo = 0; 1048 sout->mid_uo = 0;
1037 } 1049 }
1038 } 1050 }
1039
1040 flags = SCTP_STREAM_RESET_OUTGOING_SSN;
1041 } 1051 }
1042 1052
1053 flags |= SCTP_STREAM_RESET_OUTGOING_SSN;
1054
1043 for (i = 0; i < stream->outcnt; i++) 1055 for (i = 0; i < stream->outcnt; i++)
1044 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; 1056 SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN;
1045 1057
@@ -1058,6 +1070,8 @@ struct sctp_chunk *sctp_process_strreset_resp(
1058 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 1070 nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) /
1059 sizeof(__u16); 1071 sizeof(__u16);
1060 1072
1073 flags |= SCTP_STREAM_RESET_INCOMING_SSN;
1074
1061 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags, 1075 *evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
1062 nums, str_p, GFP_ATOMIC); 1076 nums, str_p, GFP_ATOMIC);
1063 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) { 1077 } else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {