Skip to content

Commit

Permalink
sctp: implement receiver-side procedures for the Outgoing SSN Reset R…
Browse files Browse the repository at this point in the history
…equest Parameter

This patch is to implement Receiver-Side Procedures for the Outgoing
SSN Reset Request Parameter described in rfc6525 section 5.2.2.

Note that some checks must be after request_seq check, as even those
checks fail, strreset_inseq still has to be increase by 1.

Signed-off-by: Xin Long <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
lxin authored and davem330 committed Feb 19, 2017
1 parent 35ea82d commit 8105447
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@ struct sctp_chunk *sctp_make_strreset_tsnresp(
void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *);

/* Prototypes for stream-processing functions. */
struct sctp_chunk *sctp_process_strreset_outreq(
struct sctp_association *asoc,
union sctp_params param,
struct sctp_ulpevent **evp);

/* Prototypes for statetable processing. */

int sctp_do_sm(struct net *net, sctp_event_t event_type, sctp_subtype_t subtype,
Expand Down
113 changes: 113 additions & 0 deletions net/sctp/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,116 @@ int sctp_send_add_streams(struct sctp_association *asoc,
out:
return retval;
}

static sctp_paramhdr_t *sctp_chunk_lookup_strreset_param(
struct sctp_association *asoc, __u32 resp_seq)
{
struct sctp_chunk *chunk = asoc->strreset_chunk;
struct sctp_reconf_chunk *hdr;
union sctp_params param;

if (ntohl(resp_seq) != asoc->strreset_outseq || !chunk)
return NULL;

hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
sctp_walk_params(param, hdr, params) {
/* sctp_strreset_tsnreq is actually the basic structure
* of all stream reconf params, so it's safe to use it
* to access request_seq.
*/
struct sctp_strreset_tsnreq *req = param.v;

if (req->request_seq == resp_seq)
return param.v;
}

return NULL;
}

struct sctp_chunk *sctp_process_strreset_outreq(
struct sctp_association *asoc,
union sctp_params param,
struct sctp_ulpevent **evp)
{
struct sctp_strreset_outreq *outreq = param.v;
struct sctp_stream *stream = asoc->stream;
__u16 i, nums, flags = 0, *str_p = NULL;
__u32 result = SCTP_STRRESET_DENIED;
__u32 request_seq;

request_seq = ntohl(outreq->request_seq);

if (ntohl(outreq->send_reset_at_tsn) >
sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)) {
result = SCTP_STRRESET_IN_PROGRESS;
goto out;
}

if (request_seq > asoc->strreset_inseq) {
result = SCTP_STRRESET_ERR_BAD_SEQNO;
goto out;
} else if (request_seq == asoc->strreset_inseq) {
asoc->strreset_inseq++;
}

/* Check strreset_enable after inseq inc, as sender cannot tell
* the peer doesn't enable strreset after receiving response with
* result denied, as well as to keep consistent with bsd.
*/
if (!(asoc->strreset_enable & SCTP_ENABLE_RESET_STREAM_REQ))
goto out;

if (asoc->strreset_chunk) {
sctp_paramhdr_t *param_hdr;
struct sctp_transport *t;

param_hdr = sctp_chunk_lookup_strreset_param(
asoc, outreq->response_seq);
if (!param_hdr || param_hdr->type !=
SCTP_PARAM_RESET_IN_REQUEST) {
/* same process with outstanding isn't 0 */
result = SCTP_STRRESET_ERR_IN_PROGRESS;
goto out;
}

asoc->strreset_outstanding--;
asoc->strreset_outseq++;

if (!asoc->strreset_outstanding) {
t = asoc->strreset_chunk->transport;
if (del_timer(&t->reconf_timer))
sctp_transport_put(t);

sctp_chunk_put(asoc->strreset_chunk);
asoc->strreset_chunk = NULL;
}

flags = SCTP_STREAM_RESET_INCOMING_SSN;
}

nums = (ntohs(param.p->length) - sizeof(*outreq)) / 2;
if (nums) {
str_p = outreq->list_of_streams;
for (i = 0; i < nums; i++) {
if (ntohs(str_p[i]) >= stream->incnt) {
result = SCTP_STRRESET_ERR_WRONG_SSN;
goto out;
}
}

for (i = 0; i < nums; i++)
stream->in[ntohs(str_p[i])].ssn = 0;
} else {
for (i = 0; i < stream->incnt; i++)
stream->in[i].ssn = 0;
}

result = SCTP_STRRESET_PERFORMED;

*evp = sctp_ulpevent_make_stream_reset_event(asoc,
flags | SCTP_STREAM_RESET_OUTGOING_SSN, nums, str_p,
GFP_ATOMIC);

out:
return sctp_make_strreset_resp(asoc, result, request_seq);
}

0 comments on commit 8105447

Please sign in to comment.