diff options
Diffstat (limited to 'net/sctp/stream.c')
| -rw-r--r-- | net/sctp/stream.c | 82 |
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 | ||
| 87 | static 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 | ||
| 138 | static int sctp_stream_alloc_out(struct sctp_stream *stream, __u16 outcnt, | 153 | static 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 | ||
| 667 | out: | 685 | out: |
| 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 | |||
| 744 | out: | 759 | out: |
| 745 | sctp_update_strreset_result(asoc, result); | 760 | sctp_update_strreset_result(asoc, result); |
| 746 | err: | 761 | err: |
| @@ -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 | |||
| 979 | out: | 991 | out: |
| 980 | sctp_update_strreset_result(asoc, result); | 992 | sctp_update_strreset_result(asoc, result); |
| 981 | err: | 993 | err: |
| @@ -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) { |
