Skip to content

Commit 11ae76e

Browse files
lxindavem330
authored andcommitted
sctp: implement receiver-side procedures for the Reconf Response Parameter
This patch is to implement Receiver-Side Procedures for the Re-configuration Response Parameter in rfc6525 section 5.2.7. sctp_process_strreset_resp would process the response for any kind of reconf request, and the stream reconf is applied only when the response result is success. Signed-off-by: Xin Long <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c5c4ebb commit 11ae76e

File tree

3 files changed

+161
-3
lines changed

3 files changed

+161
-3
lines changed

include/net/sctp/sm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
305305
struct sctp_association *asoc,
306306
union sctp_params param,
307307
struct sctp_ulpevent **evp);
308+
struct sctp_chunk *sctp_process_strreset_resp(
309+
struct sctp_association *asoc,
310+
union sctp_params param,
311+
struct sctp_ulpevent **evp);
308312

309313
/* Prototypes for statetable processing. */
310314

net/sctp/sm_statefuns.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3881,9 +3881,9 @@ sctp_disposition_t sctp_sf_do_reconf(struct net *net,
38813881
else if (param.p->type == SCTP_PARAM_RESET_ADD_IN_STREAMS)
38823882
reply = sctp_process_strreset_addstrm_in(
38833883
(struct sctp_association *)asoc, param, &ev);
3884-
/* More handles for other types will be added here, by now it
3885-
* just ignores other types.
3886-
*/
3884+
else if (param.p->type == SCTP_PARAM_RESET_RESPONSE)
3885+
reply = sctp_process_strreset_resp(
3886+
(struct sctp_association *)asoc, param, &ev);
38873887

38883888
if (ev)
38893889
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,

net/sctp/stream.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,3 +675,157 @@ struct sctp_chunk *sctp_process_strreset_addstrm_in(
675675

676676
return chunk;
677677
}
678+
679+
struct sctp_chunk *sctp_process_strreset_resp(
680+
struct sctp_association *asoc,
681+
union sctp_params param,
682+
struct sctp_ulpevent **evp)
683+
{
684+
struct sctp_strreset_resp *resp = param.v;
685+
struct sctp_stream *stream = asoc->stream;
686+
struct sctp_transport *t;
687+
__u16 i, nums, flags = 0;
688+
sctp_paramhdr_t *req;
689+
__u32 result;
690+
691+
req = sctp_chunk_lookup_strreset_param(asoc, resp->response_seq, 0);
692+
if (!req)
693+
return NULL;
694+
695+
result = ntohl(resp->result);
696+
if (result != SCTP_STRRESET_PERFORMED) {
697+
/* if in progress, do nothing but retransmit */
698+
if (result == SCTP_STRRESET_IN_PROGRESS)
699+
return NULL;
700+
else if (result == SCTP_STRRESET_DENIED)
701+
flags = SCTP_STREAM_RESET_DENIED;
702+
else
703+
flags = SCTP_STREAM_RESET_FAILED;
704+
}
705+
706+
if (req->type == SCTP_PARAM_RESET_OUT_REQUEST) {
707+
struct sctp_strreset_outreq *outreq;
708+
__u16 *str_p = NULL;
709+
710+
outreq = (struct sctp_strreset_outreq *)req;
711+
nums = (ntohs(outreq->param_hdr.length) - sizeof(*outreq)) / 2;
712+
713+
if (result == SCTP_STRRESET_PERFORMED) {
714+
if (nums) {
715+
str_p = outreq->list_of_streams;
716+
for (i = 0; i < nums; i++)
717+
stream->out[ntohs(str_p[i])].ssn = 0;
718+
} else {
719+
for (i = 0; i < stream->outcnt; i++)
720+
stream->out[i].ssn = 0;
721+
}
722+
723+
flags = SCTP_STREAM_RESET_OUTGOING_SSN;
724+
}
725+
726+
for (i = 0; i < stream->outcnt; i++)
727+
stream->out[i].state = SCTP_STREAM_OPEN;
728+
729+
*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
730+
nums, str_p, GFP_ATOMIC);
731+
} else if (req->type == SCTP_PARAM_RESET_IN_REQUEST) {
732+
struct sctp_strreset_inreq *inreq;
733+
__u16 *str_p = NULL;
734+
735+
/* if the result is performed, it's impossible for inreq */
736+
if (result == SCTP_STRRESET_PERFORMED)
737+
return NULL;
738+
739+
inreq = (struct sctp_strreset_inreq *)req;
740+
nums = (ntohs(inreq->param_hdr.length) - sizeof(*inreq)) / 2;
741+
742+
str_p = inreq->list_of_streams;
743+
*evp = sctp_ulpevent_make_stream_reset_event(asoc, flags,
744+
nums, str_p, GFP_ATOMIC);
745+
} else if (req->type == SCTP_PARAM_RESET_TSN_REQUEST) {
746+
struct sctp_strreset_resptsn *resptsn;
747+
__u32 stsn, rtsn;
748+
749+
/* check for resptsn, as sctp_verify_reconf didn't do it*/
750+
if (ntohs(param.p->length) != sizeof(*resptsn))
751+
return NULL;
752+
753+
resptsn = (struct sctp_strreset_resptsn *)resp;
754+
stsn = ntohl(resptsn->senders_next_tsn);
755+
rtsn = ntohl(resptsn->receivers_next_tsn);
756+
757+
if (result == SCTP_STRRESET_PERFORMED) {
758+
__u32 mtsn = sctp_tsnmap_get_max_tsn_seen(
759+
&asoc->peer.tsn_map);
760+
761+
sctp_ulpq_reasm_flushtsn(&asoc->ulpq, mtsn);
762+
sctp_ulpq_abort_pd(&asoc->ulpq, GFP_ATOMIC);
763+
764+
sctp_tsnmap_init(&asoc->peer.tsn_map,
765+
SCTP_TSN_MAP_INITIAL,
766+
stsn, GFP_ATOMIC);
767+
768+
sctp_outq_free(&asoc->outqueue);
769+
770+
asoc->next_tsn = rtsn;
771+
asoc->ctsn_ack_point = asoc->next_tsn - 1;
772+
asoc->adv_peer_ack_point = asoc->ctsn_ack_point;
773+
774+
for (i = 0; i < stream->outcnt; i++)
775+
stream->out[i].ssn = 0;
776+
for (i = 0; i < stream->incnt; i++)
777+
stream->in[i].ssn = 0;
778+
}
779+
780+
for (i = 0; i < stream->outcnt; i++)
781+
stream->out[i].state = SCTP_STREAM_OPEN;
782+
783+
*evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags,
784+
stsn, rtsn, GFP_ATOMIC);
785+
} else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) {
786+
struct sctp_strreset_addstrm *addstrm;
787+
__u16 number;
788+
789+
addstrm = (struct sctp_strreset_addstrm *)req;
790+
nums = ntohs(addstrm->number_of_streams);
791+
number = stream->outcnt - nums;
792+
793+
if (result == SCTP_STRRESET_PERFORMED)
794+
for (i = number; i < stream->outcnt; i++)
795+
stream->out[i].state = SCTP_STREAM_OPEN;
796+
else
797+
stream->outcnt = number;
798+
799+
*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
800+
0, nums, GFP_ATOMIC);
801+
} else if (req->type == SCTP_PARAM_RESET_ADD_IN_STREAMS) {
802+
struct sctp_strreset_addstrm *addstrm;
803+
804+
/* if the result is performed, it's impossible for addstrm in
805+
* request.
806+
*/
807+
if (result == SCTP_STRRESET_PERFORMED)
808+
return NULL;
809+
810+
addstrm = (struct sctp_strreset_addstrm *)req;
811+
nums = ntohs(addstrm->number_of_streams);
812+
813+
*evp = sctp_ulpevent_make_stream_change_event(asoc, flags,
814+
nums, 0, GFP_ATOMIC);
815+
}
816+
817+
asoc->strreset_outstanding--;
818+
asoc->strreset_outseq++;
819+
820+
/* remove everything for this reconf request */
821+
if (!asoc->strreset_outstanding) {
822+
t = asoc->strreset_chunk->transport;
823+
if (del_timer(&t->reconf_timer))
824+
sctp_transport_put(t);
825+
826+
sctp_chunk_put(asoc->strreset_chunk);
827+
asoc->strreset_chunk = NULL;
828+
}
829+
830+
return NULL;
831+
}

0 commit comments

Comments
 (0)