Skip to content

Commit

Permalink
Fix the reported streams in a SCTP_STREAM_RESET_EVENT, if a
Browse files Browse the repository at this point in the history
sent incoming stream reset request was responded with failed
or denied.
Thanks to Peter Bostroem from Google for reporting the issue.

MFC after: 3 days
  • Loading branch information
tuexen committed Oct 16, 2014
1 parent e512086 commit aaaf794
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 17 deletions.
6 changes: 5 additions & 1 deletion sys/netinet/sctp_header.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,11 @@ struct sctp_pktdrop_chunk {

/**********STREAM RESET STUFF ******************/

struct sctp_stream_reset_request {
struct sctp_paramhdr ph;
uint32_t request_seq;
} SCTP_PACKED;

struct sctp_stream_reset_out_request {
struct sctp_paramhdr ph;
uint32_t request_seq; /* monotonically increasing seq no */
Expand All @@ -464,7 +469,6 @@ struct sctp_stream_reset_in_request {
uint16_t list_of_streams[]; /* if not all list of streams */
} SCTP_PACKED;


struct sctp_stream_reset_tsn_request {
struct sctp_paramhdr ph;
uint32_t request_seq;
Expand Down
33 changes: 18 additions & 15 deletions sys/netinet/sctp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -3496,12 +3496,12 @@ sctp_reset_out_streams(struct sctp_tcb *stcb, uint32_t number_entries, uint16_t
}


struct sctp_stream_reset_out_request *
struct sctp_stream_reset_request *
sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chunk **bchk)
{
struct sctp_association *asoc;
struct sctp_chunkhdr *ch;
struct sctp_stream_reset_out_request *r;
struct sctp_stream_reset_request *r;
struct sctp_tmit_chunk *chk;
int len, clen;

Expand All @@ -3524,15 +3524,15 @@ sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chu
}
clen = chk->send_size;
ch = mtod(chk->data, struct sctp_chunkhdr *);
r = (struct sctp_stream_reset_out_request *)(ch + 1);
r = (struct sctp_stream_reset_request *)(ch + 1);
if (ntohl(r->request_seq) == seq) {
/* found it */
return (r);
}
len = SCTP_SIZE32(ntohs(r->ph.param_length));
if (clen > (len + (int)sizeof(struct sctp_chunkhdr))) {
/* move to the next one, there can only be a max of two */
r = (struct sctp_stream_reset_out_request *)((caddr_t)r + len);
r = (struct sctp_stream_reset_request *)((caddr_t)r + len);
if (ntohl(r->request_seq) == seq) {
return (r);
}
Expand Down Expand Up @@ -3576,43 +3576,46 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
int lparm_len;
struct sctp_association *asoc = &stcb->asoc;
struct sctp_tmit_chunk *chk;
struct sctp_stream_reset_out_request *srparam;
struct sctp_stream_reset_request *req_param;
struct sctp_stream_reset_out_request *req_out_param;
struct sctp_stream_reset_in_request *req_in_param;
uint32_t number_entries;

if (asoc->stream_reset_outstanding == 0) {
/* duplicate */
return (0);
}
if (seq == stcb->asoc.str_reset_seq_out) {
srparam = sctp_find_stream_reset(stcb, seq, &chk);
if (srparam) {
req_param = sctp_find_stream_reset(stcb, seq, &chk);
if (req_param != NULL) {
stcb->asoc.str_reset_seq_out++;
type = ntohs(srparam->ph.param_type);
lparm_len = ntohs(srparam->ph.param_length);
type = ntohs(req_param->ph.param_type);
lparm_len = ntohs(req_param->ph.param_length);
if (type == SCTP_STR_RESET_OUT_REQUEST) {
req_out_param = (struct sctp_stream_reset_out_request *)req_param;
number_entries = (lparm_len - sizeof(struct sctp_stream_reset_out_request)) / sizeof(uint16_t);
asoc->stream_reset_out_is_outstanding = 0;
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) {
/* do it */
sctp_reset_out_streams(stcb, number_entries, srparam->list_of_streams);
sctp_reset_out_streams(stcb, number_entries, req_out_param->list_of_streams);
} else if (action == SCTP_STREAM_RESET_RESULT_DENIED) {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_OUT, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_OUT, stcb, number_entries, req_out_param->list_of_streams, SCTP_SO_NOT_LOCKED);
} else {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, req_out_param->list_of_streams, SCTP_SO_NOT_LOCKED);
}
} else if (type == SCTP_STR_RESET_IN_REQUEST) {
/* Answered my request */
req_in_param = (struct sctp_stream_reset_in_request *)req_param;
number_entries = (lparm_len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t);
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action == SCTP_STREAM_RESET_RESULT_DENIED) {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_DENIED_IN, stcb,
number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
number_entries, req_in_param->list_of_streams, SCTP_SO_NOT_LOCKED);
} else if (action != SCTP_STREAM_RESET_RESULT_PERFORMED) {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb,
number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
number_entries, req_in_param->list_of_streams, SCTP_SO_NOT_LOCKED);
}
} else if (type == SCTP_STR_RESET_ADD_OUT_STREAMS) {
/* Ok we now may have more streams */
Expand Down
2 changes: 1 addition & 1 deletion sys/netinet/sctp_input.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ sctp_common_input_processing(struct mbuf **, int, int, int,
uint8_t, uint32_t,
uint32_t, uint16_t);

struct sctp_stream_reset_out_request *
struct sctp_stream_reset_request *
sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq,
struct sctp_tmit_chunk **bchk);

Expand Down

0 comments on commit aaaf794

Please sign in to comment.