sctp: implement receiver-side procedures for the Outgoing SSN Reset Request 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 <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
35ea82d611
commit
8105447645
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user