Make stream our stream reset implementation

compliant to RFC6525.

MFC after:	1 month
This commit is contained in:
Randall Stewart 2012-03-29 13:36:53 +00:00
parent 7fb26c47df
commit c4e848b770
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=233660
13 changed files with 551 additions and 217 deletions

View File

@ -155,8 +155,22 @@ struct sctp_paramhdr {
* field.
*/
/* these should probably go into sockets API */
#define SCTP_RESET_STREAMS 0x00001004 /* wo */
#define SCTP_ENABLE_STREAM_RESET 0x00000900 /* struct
* sctp_assoc_value */
#define SCTP_RESET_STREAMS 0x00000901 /* struct
* sctp_reset_streams */
#define SCTP_RESET_ASSOC 0x00000902 /* sctp_assoc_t */
#define SCTP_ADD_STREAMS 0x00000903 /* struct
* sctp_add_streams */
/* For enable stream reset */
#define SCTP_ENABLE_RESET_STREAM_REQ 0x00000001
#define SCTP_ENABLE_RESET_ASSOC_REQ 0x00000002
#define SCTP_ENABLE_CHANGE_ASSOC_REQ 0x00000004
#define SCTP_ENABLE_VALUE_MASK 0x00000007
/* For reset streams */
#define SCTP_STREAM_RESET_INCOMING 0x00000001
#define SCTP_STREAM_RESET_OUTGOING 0x00000002
/* here on down are more implementation specific */

View File

@ -418,7 +418,8 @@ __FBSDID("$FreeBSD$");
#define SCTP_STR_RESET_IN_REQUEST 0x000e
#define SCTP_STR_RESET_TSN_REQUEST 0x000f
#define SCTP_STR_RESET_RESPONSE 0x0010
#define SCTP_STR_RESET_ADD_STREAMS 0x0011
#define SCTP_STR_RESET_ADD_OUT_STREAMS 0x0011
#define SCTP_STR_RESET_ADD_IN_STREAMS 0x0012
#define SCTP_MAX_RESET_PARAMS 2
#define SCTP_STREAM_RESET_TSN_DELTA 0x1000

View File

@ -501,7 +501,7 @@ struct sctp_stream_reset_add_strm {
#define SCTP_STREAM_RESET_NOTHING 0x00000000 /* Nothing for me to do */
#define SCTP_STREAM_RESET_PERFORMED 0x00000001 /* Did it */
#define SCTP_STREAM_RESET_DENIED 0x00000002 /* refused to do it */
#define SCTP_STREAM_RESET_REJECT 0x00000002 /* refused to do it */
#define SCTP_STREAM_RESET_ERROR_STR 0x00000003 /* bad Stream no */
#define SCTP_STREAM_RESET_TRY_LATER 0x00000004 /* collision, try again */
#define SCTP_STREAM_RESET_BAD_SEQNO 0x00000005 /* bad str-reset seq no */

View File

@ -2790,6 +2790,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
inp->sctp_ecn_enable = (*inp_p)->sctp_ecn_enable;
inp->partial_delivery_point = (*inp_p)->partial_delivery_point;
inp->sctp_context = (*inp_p)->sctp_context;
inp->local_strreset_support = (*inp_p)->local_strreset_support;
inp->inp_starting_point_for_iterator = NULL;
/*
* copy in the authentication parameters from the
@ -3612,20 +3613,35 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action != SCTP_STREAM_RESET_PERFORMED) {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb,
number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
}
} else if (type == SCTP_STR_RESET_ADD_STREAMS) {
} else if (type == SCTP_STR_RESET_ADD_OUT_STREAMS) {
/* Ok we now may have more streams */
int num_stream;
num_stream = stcb->asoc.strm_pending_add_size;
if (num_stream > (stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt)) {
/* TSNH */
num_stream = stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt;
}
stcb->asoc.strm_pending_add_size = 0;
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action == SCTP_STREAM_RESET_PERFORMED) {
/* Put the new streams into effect */
stcb->asoc.streamoutcnt = stcb->asoc.strm_realoutsize;
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD_OK, stcb,
(uint32_t) stcb->asoc.streamoutcnt, NULL, SCTP_SO_NOT_LOCKED);
stcb->asoc.streamoutcnt += num_stream;
sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0);
} else {
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD_FAIL, stcb,
(uint32_t) stcb->asoc.streamoutcnt, NULL, SCTP_SO_NOT_LOCKED);
sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt,
SCTP_STREAM_CHANGED_DENIED);
}
} else if (type == SCTP_STR_RESET_ADD_IN_STREAMS) {
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action != SCTP_STREAM_RESET_PERFORMED) {
sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt,
SCTP_STREAM_CHANGED_DENIED);
}
} else if (type == SCTP_STR_RESET_TSN_REQUEST) {
/**
@ -3667,7 +3683,10 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
sctp_reset_out_streams(stcb, 0, (uint16_t *) NULL);
sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL);
sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0);
} else {
sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1),
SCTP_STREAM_RESET_FAILED);
}
}
/* get rid of the request and get the request flags */
@ -3700,8 +3719,7 @@ sctp_handle_str_reset_request_in(struct sctp_tcb *stcb,
if (trunc) {
/* Can't do it, since they exceeded our buffer size */
asoc->last_reset_action[1] = asoc->last_reset_action[0];
asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
asoc->last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
} else if (stcb->asoc.stream_reset_out_is_outstanding == 0) {
len = ntohs(req->ph.param_length);
number_entries = ((len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t));
@ -3723,8 +3741,8 @@ sctp_handle_str_reset_request_in(struct sctp_tcb *stcb,
/* Can't do it, since we have sent one out */
asoc->last_reset_action[1] = asoc->last_reset_action[0];
asoc->last_reset_action[0] = SCTP_STREAM_RESET_TRY_LATER;
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
}
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
asoc->str_reset_seq_in++;
} else if (asoc->str_reset_seq_in - 1 == seq) {
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
@ -3786,7 +3804,7 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb,
sctp_reset_in_stream(stcb, 0, (uint16_t *) NULL);
stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
sctp_notify_stream_reset_tsn(stcb, stcb->asoc.sending_seq, (stcb->asoc.mapping_array_base_tsn + 1), 0);
asoc->str_reset_seq_in++;
} else if (asoc->str_reset_seq_in - 1 == seq) {
sctp_add_stream_reset_result_tsn(chk, seq, asoc->last_reset_action[0],
@ -3831,12 +3849,10 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
/* move the reset action back one */
asoc->last_reset_action[1] = asoc->last_reset_action[0];
if (trunc) {
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
asoc->last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
} else if (SCTP_TSN_GE(asoc->cumulative_tsn, tsn)) {
/* we can do it now */
sctp_reset_in_stream(stcb, number_entries, req->list_of_streams);
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_PERFORMED);
asoc->last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
} else {
/*
@ -3851,8 +3867,8 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
siz, SCTP_M_STRESET);
if (liste == NULL) {
/* gak out of memory */
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_REJECT);
asoc->last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
return;
}
liste->tsn = tsn;
@ -3860,9 +3876,9 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
memcpy(&liste->req, req,
(sizeof(struct sctp_stream_reset_out_request) + (number_entries * sizeof(uint16_t))));
TAILQ_INSERT_TAIL(&asoc->resetHead, liste, next_resp);
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_PERFORMED);
asoc->last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
}
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
asoc->str_reset_seq_in++;
} else if ((asoc->str_reset_seq_in - 1) == seq) {
/*
@ -3889,7 +3905,7 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
* Peer is requesting to add more streams. If its within our
* max-streams we will allow it.
*/
uint16_t num_stream, i;
uint32_t num_stream, i;
uint32_t seq;
struct sctp_association *asoc = &stcb->asoc;
struct sctp_queued_to_read *ctl, *nctl;
@ -3900,12 +3916,12 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
/* Now what would be the new total? */
if (asoc->str_reset_seq_in == seq) {
num_stream += stcb->asoc.streamincnt;
if (num_stream > stcb->asoc.max_inbound_streams) {
if ((num_stream > stcb->asoc.max_inbound_streams) ||
(num_stream > 0xffff)) {
/* We must reject it they ask for to many */
denied:
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
} else {
/* Ok, we can do that :-) */
struct sctp_stream_in *oldstrm;
@ -3941,13 +3957,12 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
SCTP_FREE(oldstrm, SCTP_M_STRMI);
/* update the size */
stcb->asoc.streamincnt = num_stream;
/* Send the ack */
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_PERFORMED);
stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK, stcb,
(uint32_t) stcb->asoc.streamincnt, NULL, SCTP_SO_NOT_LOCKED);
sctp_notify_stream_reset_add(stcb, stcb->asoc.streamincnt, stcb->asoc.streamoutcnt, 0);
}
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
asoc->str_reset_seq_in++;
} else if ((asoc->str_reset_seq_in - 1) == seq) {
/*
* one seq back, just echo back last action since my
@ -3966,6 +3981,63 @@ sctp_handle_str_reset_add_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *ch
}
}
static void
sctp_handle_str_reset_add_out_strm(struct sctp_tcb *stcb, struct sctp_tmit_chunk *chk,
struct sctp_stream_reset_add_strm *str_add)
{
/*
* Peer is requesting to add more streams. If its within our
* max-streams we will allow it.
*/
uint16_t num_stream;
uint32_t seq;
struct sctp_association *asoc = &stcb->asoc;
/* Get the number. */
seq = ntohl(str_add->request_seq);
num_stream = ntohs(str_add->number_of_streams);
/* Now what would be the new total? */
if (asoc->str_reset_seq_in == seq) {
if (stcb->asoc.stream_reset_outstanding) {
/* We must reject it we have something pending */
stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
} else {
/* Ok, we can do that :-) */
int mychk;
mychk = stcb->asoc.streamoutcnt;
mychk += num_stream;
if (mychk < 0x10000) {
stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_PERFORMED;
if (sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, 1, num_stream, 0, 1)) {
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
}
} else {
stcb->asoc.last_reset_action[1] = stcb->asoc.last_reset_action[0];
stcb->asoc.last_reset_action[0] = SCTP_STREAM_RESET_REJECT;
}
}
sctp_add_stream_reset_result(chk, seq, stcb->asoc.last_reset_action[0]);
asoc->str_reset_seq_in++;
} else if ((asoc->str_reset_seq_in - 1) == seq) {
/*
* one seq back, just echo back last action since my
* response was lost.
*/
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
} else if ((asoc->str_reset_seq_in - 2) == seq) {
/*
* two seq back, just echo back last action since my
* response was lost.
*/
sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[1]);
} else {
sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_BAD_SEQNO);
}
}
#ifdef __GNUC__
__attribute__((noinline))
#endif
@ -3977,7 +4049,7 @@ __attribute__((noinline))
struct sctp_paramhdr pstore;
uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE];
uint32_t seq;
uint32_t seq = 0;
int num_req = 0;
int trunc = 0;
struct sctp_tmit_chunk *chk;
@ -4041,7 +4113,6 @@ __attribute__((noinline))
} else {
trunc = 0;
}
if (num_param > SCTP_MAX_RESET_PARAMS) {
/* hit the max of parameters already sorry.. */
break;
@ -4059,26 +4130,29 @@ __attribute__((noinline))
}
}
sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc);
} else if (ptype == SCTP_STR_RESET_ADD_STREAMS) {
} else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) {
struct sctp_stream_reset_add_strm *str_add;
str_add = (struct sctp_stream_reset_add_strm *)ph;
num_req++;
sctp_handle_str_reset_add_strm(stcb, chk, str_add);
} else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) {
struct sctp_stream_reset_add_strm *str_add;
str_add = (struct sctp_stream_reset_add_strm *)ph;
num_req++;
sctp_handle_str_reset_add_out_strm(stcb, chk, str_add);
} else if (ptype == SCTP_STR_RESET_IN_REQUEST) {
struct sctp_stream_reset_in_request *req_in;
num_req++;
req_in = (struct sctp_stream_reset_in_request *)ph;
sctp_handle_str_reset_request_in(stcb, chk, req_in, trunc);
} else if (ptype == SCTP_STR_RESET_TSN_REQUEST) {
struct sctp_stream_reset_tsn_request *req_tsn;
num_req++;
req_tsn = (struct sctp_stream_reset_tsn_request *)ph;
if (sctp_handle_str_reset_request_tsn(stcb, chk, req_tsn)) {
ret_code = 1;
goto strres_nochunk;

View File

@ -11716,7 +11716,7 @@ sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk,
}
static void
sctp_add_a_stream(struct sctp_tmit_chunk *chk,
sctp_add_an_out_stream(struct sctp_tmit_chunk *chk,
uint32_t seq,
uint16_t adding)
{
@ -11733,7 +11733,7 @@ sctp_add_a_stream(struct sctp_tmit_chunk *chk,
len = sizeof(struct sctp_stream_reset_add_strm);
/* Fill it out. */
addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_STREAMS);
addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_OUT_STREAMS);
addstr->ph.param_length = htons(len);
addstr->request_seq = htonl(seq);
addstr->number_of_streams = htons(adding);
@ -11748,15 +11748,49 @@ sctp_add_a_stream(struct sctp_tmit_chunk *chk,
return;
}
static void
sctp_add_an_in_stream(struct sctp_tmit_chunk *chk,
uint32_t seq,
uint16_t adding)
{
int len, old_len;
struct sctp_chunkhdr *ch;
struct sctp_stream_reset_add_strm *addstr;
ch = mtod(chk->data, struct sctp_chunkhdr *);
old_len = len = SCTP_SIZE32(ntohs(ch->chunk_length));
/* get to new offset for the param. */
addstr = (struct sctp_stream_reset_add_strm *)((caddr_t)ch + len);
/* now how long will this param be? */
len = sizeof(struct sctp_stream_reset_add_strm);
/* Fill it out. */
addstr->ph.param_type = htons(SCTP_STR_RESET_ADD_IN_STREAMS);
addstr->ph.param_length = htons(len);
addstr->request_seq = htonl(seq);
addstr->number_of_streams = htons(adding);
addstr->reserved = 0;
/* now fix the chunk length */
ch->chunk_length = htons(len + old_len);
chk->send_size = len + old_len;
chk->book_size = SCTP_SIZE32(chk->send_size);
chk->book_size_scale = 0;
SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
return;
}
int
sctp_send_str_reset_req(struct sctp_tcb *stcb,
int number_entries, uint16_t * list,
uint8_t send_out_req,
uint32_t resp_seq,
uint8_t send_in_req,
uint8_t send_tsn_req,
uint8_t add_stream,
uint16_t adding
uint16_t adding_o,
uint16_t adding_i, uint8_t peer_asked
)
{
@ -11823,18 +11857,86 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
seq = stcb->asoc.str_reset_seq_out;
if (send_out_req) {
sctp_add_stream_reset_out(chk, number_entries, list,
seq, resp_seq, (stcb->asoc.sending_seq - 1));
seq, (stcb->asoc.str_reset_seq_in - 1), (stcb->asoc.sending_seq - 1));
asoc->stream_reset_out_is_outstanding = 1;
seq++;
asoc->stream_reset_outstanding++;
}
if (add_stream) {
sctp_add_a_stream(chk, seq, adding);
if ((add_stream & 1) &&
((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < adding_o)) {
/* Need to allocate more */
struct sctp_stream_out *oldstream;
struct sctp_stream_queue_pending *sp, *nsp;
int i;
oldstream = stcb->asoc.strmout;
/* get some more */
SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
((stcb->asoc.streamoutcnt + adding_o) * sizeof(struct sctp_stream_out)),
SCTP_M_STRMO);
if (stcb->asoc.strmout == NULL) {
uint8_t x;
stcb->asoc.strmout = oldstream;
/* Turn off the bit */
x = add_stream & 0xfe;
add_stream = x;
goto skip_stuff;
}
/*
* Ok now we proceed with copying the old out stuff and
* initializing the new stuff.
*/
SCTP_TCB_SEND_LOCK(stcb);
stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1);
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent;
stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
/* now anything on those queues? */
TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
}
/* Now move assoc pointers too */
if (stcb->asoc.last_out_stream == &oldstream[i]) {
stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
}
if (stcb->asoc.locked_on_sending == &oldstream[i]) {
stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
}
}
/* now the new streams */
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + adding_o); i++) {
stcb->asoc.strmout[i].next_sequence_sent = 0x0;
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
}
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + adding_o;
SCTP_FREE(oldstream, SCTP_M_STRMO);
SCTP_TCB_SEND_UNLOCK(stcb);
}
skip_stuff:
if ((add_stream & 1) && (adding_o > 0)) {
asoc->strm_pending_add_size = adding_o;
asoc->peer_req_out = peer_asked;
sctp_add_an_out_stream(chk, seq, adding_o);
seq++;
asoc->stream_reset_outstanding++;
}
if ((add_stream & 2) && (adding_i > 0)) {
sctp_add_an_in_stream(chk, seq, adding_i);
seq++;
asoc->stream_reset_outstanding++;
}
if (send_in_req) {
sctp_add_stream_reset_in(chk, number_entries, list, seq);
seq++;
asoc->stream_reset_outstanding++;
}
if (send_tsn_req) {
@ -11842,7 +11944,6 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
asoc->stream_reset_outstanding++;
}
asoc->str_reset = chk;
/* insert the chunk for sending */
TAILQ_INSERT_TAIL(&asoc->control_send_queue,
chk,

View File

@ -194,15 +194,13 @@ sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk,
int
sctp_send_str_reset_req(struct sctp_tcb *stcb,
int number_entries,
uint16_t * list,
int number_entries, uint16_t * list,
uint8_t send_out_req,
uint32_t resp_seq,
uint8_t send_in_req,
uint8_t send_tsn_req,
uint8_t add_str,
uint16_t adding);
uint8_t add_stream,
uint16_t adding_o,
uint16_t adding_i, uint8_t from_peer);
void
sctp_send_abort(struct mbuf *, int, struct sctphdr *, uint32_t,

View File

@ -399,6 +399,7 @@ struct sctp_inpcb {
uint32_t sctp_frag_point;
uint32_t partial_delivery_point;
uint32_t sctp_context;
uint8_t local_strreset_support;
uint32_t sctp_cmt_on_off;
uint32_t sctp_ecn_enable;
struct sctp_nonpad_sndrcvinfo def_send;

View File

@ -127,6 +127,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
n_inp->sctp_ecn_enable = inp->sctp_ecn_enable;
n_inp->partial_delivery_point = inp->partial_delivery_point;
n_inp->sctp_context = inp->sctp_context;
n_inp->local_strreset_support = inp->local_strreset_support;
n_inp->inp_starting_point_for_iterator = NULL;
/* copy in the authentication parameters from the original endpoint */
if (n_inp->sctp_ep.local_hmacs)
@ -202,6 +203,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
n_inp->sctp_ecn_enable = inp->sctp_ecn_enable;
n_inp->partial_delivery_point = inp->partial_delivery_point;
n_inp->sctp_context = inp->sctp_context;
n_inp->local_strreset_support = inp->local_strreset_support;
n_inp->inp_starting_point_for_iterator = NULL;
/* copy in the authentication parameters from the original endpoint */

View File

@ -1095,6 +1095,7 @@ struct sctp_association {
uint16_t streamincnt;
uint16_t streamoutcnt;
uint16_t strm_realoutsize;
uint16_t strm_pending_add_size;
/* my maximum number of retrans of INIT and SEND */
/* copied from SCTP but should be individually setable */
uint16_t max_init_times;
@ -1156,6 +1157,9 @@ struct sctp_association {
/* Flag to tell if ECN is allowed */
uint8_t ecn_allowed;
/* Did the peer make the stream config (add out) request */
uint8_t peer_req_out;
/* flag to indicate if peer can do asconf */
uint8_t peer_supports_asconf;
/* EY - flag to indicate if peer can do nr_sack */
@ -1166,6 +1170,7 @@ struct sctp_association {
uint8_t peer_supports_auth;
/* stream resets are supported by the peer */
uint8_t peer_supports_strreset;
uint8_t local_strreset_support;
uint8_t peer_supports_nat;
/*

View File

@ -438,23 +438,51 @@ struct sctp_sender_dry_event {
/*
* stream reset event
* Stream reset event - subscribe to SCTP_STREAM_RESET_EVENT
*/
struct sctp_stream_reset_event {
uint16_t strreset_type;
uint16_t strreset_flags;
uint32_t strreset_length;
sctp_assoc_t strreset_assoc_id;
uint16_t strreset_list[];
uint16_t strreset_stream_list[];
};
/* flags in strreset_flags field */
#define SCTP_STRRESET_INBOUND_STR 0x0001
#define SCTP_STRRESET_OUTBOUND_STR 0x0002
#define SCTP_STRRESET_ALL_STREAMS 0x0004
#define SCTP_STRRESET_STREAM_LIST 0x0008
#define SCTP_STRRESET_FAILED 0x0010
#define SCTP_STRRESET_ADD_STREAM 0x0020
/* flags in stream_reset_event (strreset_flags) */
#define SCTP_STREAM_RESET_DENIED 0x0004 /* SCTP_STRRESET_FAILED */
#define SCTP_STREAM_RESET_FAILED 0x0008 /* SCTP_STRRESET_FAILED */
#define SCTP_STREAM_CHANGED_DENIED 0x0010
/*
* Assoc reset event - subscribe to SCTP_ASSOC_RESET_EVENT
*/
struct sctp_assoc_reset_event {
uint16_t assocreset_type;
uint16_t assocreset_flags;
uint32_t assocreset_length;
sctp_assoc_t assocreset_assoc_id;
uint32_t assocreset_local_tsn;
uint32_t assocreset_remote_tsn;
};
#define SCTP_ASSOC_RESET_DENIED 0x0004
#define SCTP_ASSOC_RESET_FAILED 0x0008
/*
* Stream change event - subscribe to SCTP_STREAM_CHANGE_EVENT
*/
struct sctp_stream_change_event {
uint16_t strchange_type;
uint16_t strchange_flags;
uint32_t strchange_length;
sctp_assoc_t strchange_assoc_id;
uint16_t strchange_instrms;
uint16_t strchange_outstrms;
};
#define SCTP_STREAM_CHANGE_DENIED 0x0004
#define SCTP_STREAM_CHANGE_FAILED 0x0008
/* SCTP notification event */
struct sctp_tlv {
@ -477,6 +505,9 @@ union sctp_notification {
struct sctp_authkey_event sn_auth_event;
struct sctp_sender_dry_event sn_sender_dry_event;
struct sctp_stream_reset_event sn_strreset_event;
struct sctp_assoc_reset_event sn_assocreset_event;
struct sctp_stream_change_event sn_strchange_event;
};
/* notification types */
@ -493,6 +524,9 @@ union sctp_notification {
#define SCTP_STREAM_RESET_EVENT 0x0009
#define SCTP_SENDER_DRY_EVENT 0x000a
#define SCTP_NOTIFICATIONS_STOPPED_EVENT 0x000b /* we don't send this */
#define SCTP_ASSOC_RESET_EVENT 0x000c
#define SCTP_STREAM_CHANGE_EVENT 0x000d
/*
* socket option structs
*/
@ -707,19 +741,18 @@ struct sctp_blk_args {
*/
#define SCTP_MAX_EXPLICT_STR_RESET 1000
#define SCTP_RESET_LOCAL_RECV 0x0001
#define SCTP_RESET_LOCAL_SEND 0x0002
#define SCTP_RESET_BOTH 0x0003
#define SCTP_RESET_TSN 0x0004
#define SCTP_RESET_ADD_STREAMS 0x0005
struct sctp_stream_reset {
sctp_assoc_t strrst_assoc_id;
uint16_t strrst_flags;
uint16_t strrst_num_streams; /* 0 == ALL */
uint16_t strrst_list[]; /* list if strrst_num_streams is not 0 */
struct sctp_reset_streams {
sctp_assoc_t srs_assoc_id;
uint16_t srs_flags;
uint16_t srs_number_streams; /* 0 == ALL */
uint16_t srs_stream_list[]; /* list if strrst_num_streams is not 0 */
};
struct sctp_add_streams {
sctp_assoc_t sas_assoc_id;
uint16_t sas_instrms;
uint16_t sas_outstrms;
};
struct sctp_get_nonce_values {
sctp_assoc_t gn_assoc_id;

View File

@ -4088,17 +4088,52 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
}
case SCTP_ENABLE_STREAM_RESET:
{
struct sctp_assoc_value *av;
uint8_t set_value = 0;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
set_value = av->assoc_value & SCTP_ENABLE_VALUE_MASK;
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
stcb->asoc.local_strreset_support = set_value;
SCTP_TCB_UNLOCK(stcb);
} else {
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
(av->assoc_id == SCTP_FUTURE_ASSOC) ||
(av->assoc_id == SCTP_ALL_ASSOC)) {
SCTP_INP_WLOCK(inp);
inp->local_strreset_support = set_value;
SCTP_INP_WUNLOCK(inp);
}
if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
(av->assoc_id == SCTP_ALL_ASSOC)) {
SCTP_INP_RLOCK(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
SCTP_TCB_LOCK(stcb);
stcb->asoc.local_strreset_support = set_value;
SCTP_TCB_UNLOCK(stcb);
}
SCTP_INP_RUNLOCK(inp);
}
}
break;
}
case SCTP_RESET_STREAMS:
{
struct sctp_stream_reset *strrst;
uint8_t send_in = 0, send_tsn = 0, send_out = 0,
addstream = 0;
uint16_t addstrmcnt = 0;
int i;
struct sctp_reset_streams *strrst;
int i, send_out = 0;
int send_in = 0;
SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
SCTP_FIND_STCB(inp, stcb, strrst->strrst_assoc_id);
SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize);
SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id);
if (stcb == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
@ -4107,13 +4142,19 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
if (stcb->asoc.peer_supports_strreset == 0) {
/*
* Peer does not support it, we return
* protocol not supported since this is true
* for this feature and this peer, not the
* socket request in general.
* Peer does not support the chunk type.
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPROTONOSUPPORT);
error = EPROTONOSUPPORT;
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
SCTP_TCB_UNLOCK(stcb);
break;
}
if (!(stcb->asoc.local_strreset_support & SCTP_ENABLE_RESET_STREAM_REQ)) {
/*
* User did not enable the operation.
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
error = EPERM;
SCTP_TCB_UNLOCK(stcb);
break;
}
@ -4123,133 +4164,141 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_TCB_UNLOCK(stcb);
break;
}
if (strrst->strrst_flags == SCTP_RESET_LOCAL_RECV) {
if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) {
send_in = 1;
} else if (strrst->strrst_flags == SCTP_RESET_LOCAL_SEND) {
}
if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) {
send_out = 1;
} else if (strrst->strrst_flags == SCTP_RESET_BOTH) {
send_in = 1;
send_out = 1;
} else if (strrst->strrst_flags == SCTP_RESET_TSN) {
send_tsn = 1;
} else if (strrst->strrst_flags == SCTP_RESET_ADD_STREAMS) {
if (send_tsn ||
send_in ||
send_out) {
/* We can't do that and add streams */
error = EINVAL;
goto skip_stuff;
}
if (stcb->asoc.stream_reset_outstanding) {
error = EBUSY;
goto skip_stuff;
}
addstream = 1;
/* We allocate here */
addstrmcnt = strrst->strrst_num_streams;
if ((int)(addstrmcnt + stcb->asoc.streamoutcnt) > 0xffff) {
/* You can't have more than 64k */
error = EINVAL;
goto skip_stuff;
}
if ((stcb->asoc.strm_realoutsize - stcb->asoc.streamoutcnt) < addstrmcnt) {
/* Need to allocate more */
struct sctp_stream_out *oldstream;
struct sctp_stream_queue_pending *sp,
*nsp;
oldstream = stcb->asoc.strmout;
/* get some more */
SCTP_MALLOC(stcb->asoc.strmout, struct sctp_stream_out *,
((stcb->asoc.streamoutcnt + addstrmcnt) * sizeof(struct sctp_stream_out)),
SCTP_M_STRMO);
if (stcb->asoc.strmout == NULL) {
stcb->asoc.strmout = oldstream;
error = ENOMEM;
goto skip_stuff;
}
/*
* Ok now we proceed with copying
* the old out stuff and
* initializing the new stuff.
*/
SCTP_TCB_SEND_LOCK(stcb);
stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 0, 1);
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].next_sequence_sent = oldstream[i].next_sequence_sent;
stcb->asoc.strmout[i].last_msg_incomplete = oldstream[i].last_msg_incomplete;
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], &oldstream[i]);
/*
* now anything on those
* queues?
*/
TAILQ_FOREACH_SAFE(sp, &oldstream[i].outqueue, next, nsp) {
TAILQ_REMOVE(&oldstream[i].outqueue, sp, next);
TAILQ_INSERT_TAIL(&stcb->asoc.strmout[i].outqueue, sp, next);
}
/*
* Now move assoc pointers
* too
*/
if (stcb->asoc.last_out_stream == &oldstream[i]) {
stcb->asoc.last_out_stream = &stcb->asoc.strmout[i];
}
if (stcb->asoc.locked_on_sending == &oldstream[i]) {
stcb->asoc.locked_on_sending = &stcb->asoc.strmout[i];
}
}
/* now the new streams */
stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
for (i = stcb->asoc.streamoutcnt; i < (stcb->asoc.streamoutcnt + addstrmcnt); i++) {
stcb->asoc.strmout[i].next_sequence_sent = 0x0;
TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
}
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
SCTP_FREE(oldstream, SCTP_M_STRMO);
}
SCTP_TCB_SEND_UNLOCK(stcb);
goto skip_stuff;
} else {
}
if ((send_in == 0) && (send_out == 0)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
SCTP_TCB_UNLOCK(stcb);
break;
}
for (i = 0; i < strrst->strrst_num_streams; i++) {
for (i = 0; i < strrst->srs_number_streams; i++) {
if ((send_in) &&
(strrst->strrst_list[i] > stcb->asoc.streamincnt)) {
(strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto get_out;
break;
}
if ((send_out) &&
(strrst->strrst_list[i] > stcb->asoc.streamoutcnt)) {
(strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
goto get_out;
break;
}
}
skip_stuff:
if (error) {
get_out:
SCTP_TCB_UNLOCK(stcb);
break;
}
error = sctp_send_str_reset_req(stcb, strrst->strrst_num_streams,
strrst->strrst_list,
send_out, (stcb->asoc.str_reset_seq_in - 3),
send_in, send_tsn, addstream, addstrmcnt);
error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams,
strrst->srs_stream_list,
send_out, send_in, 0, 0, 0, 0, 0);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
break;
}
case SCTP_ADD_STREAMS:
{
struct sctp_add_streams *stradd;
uint8_t addstream = 0;
uint16_t add_o_strmcnt = 0;
uint16_t add_i_strmcnt = 0;
SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize);
SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id);
if (stcb == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
break;
}
if ((stradd->sas_outstrms == 0) &&
(stradd->sas_instrms == 0)) {
error = EINVAL;
goto skip_stuff;
}
if (stradd->sas_outstrms) {
addstream = 1;
/* We allocate here */
add_o_strmcnt = stradd->sas_outstrms;
if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) {
/* You can't have more than 64k */
error = EINVAL;
goto skip_stuff;
}
}
if (stradd->sas_instrms) {
int cnt;
addstream |= 2;
/*
* We allocate inside
* sctp_send_str_reset_req()
*/
add_i_strmcnt = stradd->sas_instrms;
cnt = add_i_strmcnt;
cnt += stcb->asoc.streamincnt;
if (cnt > 0x0000ffff) {
/* You can't have more than 64k */
error = EINVAL;
goto skip_stuff;
}
if (cnt > (int)stcb->asoc.max_inbound_streams) {
/* More than you are allowed */
error = EINVAL;
goto skip_stuff;
}
}
error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
skip_stuff:
SCTP_TCB_UNLOCK(stcb);
break;
}
case SCTP_RESET_ASSOC:
{
uint32_t *value;
SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize);
SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) * value);
if (stcb == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
break;
}
if (stcb->asoc.peer_supports_strreset == 0) {
/*
* Peer does not support the chunk type.
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
SCTP_TCB_UNLOCK(stcb);
break;
}
if (!(stcb->asoc.local_strreset_support & SCTP_ENABLE_RESET_ASSOC_REQ)) {
/*
* User did not enable the operation.
*/
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM);
error = EPERM;
SCTP_TCB_UNLOCK(stcb);
break;
}
if (stcb->asoc.stream_reset_outstanding) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY);
error = EALREADY;
SCTP_TCB_UNLOCK(stcb);
break;
}
error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0);
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
break;
}
case SCTP_CONNECT_X:
if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);

View File

@ -978,8 +978,8 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->free_chunk_cnt = 0;
asoc->iam_blocking = 0;
asoc->context = m->sctp_context;
asoc->local_strreset_support = m->local_strreset_support;
asoc->def_send = m->def_send;
asoc->delayed_ack = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
asoc->sack_freq = m->sctp_ep.sctp_sack_freq;
@ -3206,36 +3206,42 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
}
static void
sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag)
void
sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag)
{
struct mbuf *m_notify;
struct sctp_queued_to_read *control;
struct sctp_stream_reset_event *strreset;
struct sctp_stream_change_event *stradd;
int len;
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) {
/* event not enabled */
return;
}
if ((stcb->asoc.peer_req_out) && flag) {
/* Peer made the request, don't tell the local user */
stcb->asoc.peer_req_out = 0;
return;
}
stcb->asoc.peer_req_out = 0;
m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
if (m_notify == NULL)
/* no space left */
return;
SCTP_BUF_LEN(m_notify) = 0;
len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t));
len = sizeof(struct sctp_stream_change_event);
if (len > M_TRAILINGSPACE(m_notify)) {
/* never enough room */
sctp_m_freem(m_notify);
return;
}
strreset = mtod(m_notify, struct sctp_stream_reset_event *);
strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
strreset->strreset_flags = SCTP_STRRESET_ADD_STREAM | flag;
strreset->strreset_length = len;
strreset->strreset_assoc_id = sctp_get_associd(stcb);
strreset->strreset_list[0] = number_entries;
stradd = mtod(m_notify, struct sctp_stream_change_event *);
stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT;
stradd->strchange_flags = flag;
stradd->strchange_length = len;
stradd->strchange_assoc_id = sctp_get_associd(stcb);
stradd->strchange_instrms = numberin;
stradd->strchange_outstrms = numberout;
SCTP_BUF_LEN(m_notify) = len;
SCTP_BUF_NEXT(m_notify) = NULL;
if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
@ -3261,6 +3267,62 @@ sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
}
void
sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag)
{
struct mbuf *m_notify;
struct sctp_queued_to_read *control;
struct sctp_assoc_reset_event *strasoc;
int len;
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) {
/* event not enabled */
return;
}
m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA);
if (m_notify == NULL)
/* no space left */
return;
SCTP_BUF_LEN(m_notify) = 0;
len = sizeof(struct sctp_assoc_reset_event);
if (len > M_TRAILINGSPACE(m_notify)) {
/* never enough room */
sctp_m_freem(m_notify);
return;
}
strasoc = mtod(m_notify, struct sctp_assoc_reset_event *);
strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT;
strasoc->assocreset_flags = flag;
strasoc->assocreset_length = len;
strasoc->assocreset_assoc_id = sctp_get_associd(stcb);
strasoc->assocreset_local_tsn = sending_tsn;
strasoc->assocreset_remote_tsn = recv_tsn;
SCTP_BUF_LEN(m_notify) = len;
SCTP_BUF_NEXT(m_notify) = NULL;
if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) {
/* no space */
sctp_m_freem(m_notify);
return;
}
/* append to socket */
control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination,
0, 0, stcb->asoc.context, 0, 0, 0,
m_notify);
if (control == NULL) {
/* no memory */
sctp_m_freem(m_notify);
return;
}
control->spec_flags = M_NOTIFICATION;
control->length = SCTP_BUF_LEN(m_notify);
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
&stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
}
static void
sctp_notify_stream_reset(struct sctp_tcb *stcb,
@ -3288,18 +3350,14 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
}
strreset = mtod(m_notify, struct sctp_stream_reset_event *);
strreset->strreset_type = SCTP_STREAM_RESET_EVENT;
if (number_entries == 0) {
strreset->strreset_flags = flag | SCTP_STRRESET_ALL_STREAMS;
} else {
strreset->strreset_flags = flag | SCTP_STRRESET_STREAM_LIST;
}
strreset->strreset_flags = flag;
strreset->strreset_length = len;
strreset->strreset_assoc_id = sctp_get_associd(stcb);
if (number_entries) {
int i;
for (i = 0; i < number_entries; i++) {
strreset->strreset_list[i] = ntohs(list[i]);
strreset->strreset_stream_list[i] = ntohs(list[i]);
}
}
SCTP_BUF_LEN(m_notify) = len;
@ -3439,27 +3497,19 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
break;
case SCTP_NOTIFY_HB_RESP:
break;
case SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK:
sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_INBOUND_STR);
break;
case SCTP_NOTIFY_STR_RESET_ADD_OK:
sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_OUTBOUND_STR);
break;
case SCTP_NOTIFY_STR_RESET_ADD_FAIL:
sctp_notify_stream_reset_add(stcb, error, (SCTP_STRRESET_FAILED | SCTP_STRRESET_OUTBOUND_STR));
break;
case SCTP_NOTIFY_STR_RESET_SEND:
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_OUTBOUND_STR);
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING);
break;
case SCTP_NOTIFY_STR_RESET_RECV:
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_INBOUND_STR);
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING);
break;
case SCTP_NOTIFY_STR_RESET_FAILED_OUT:
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_OUTBOUND_STR | SCTP_STRRESET_FAILED));
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
(SCTP_STREAM_RESET_OUTGOING | SCTP_STREAM_RESET_INCOMING));
break;
case SCTP_NOTIFY_STR_RESET_FAILED_IN:
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_INBOUND_STR | SCTP_STRRESET_FAILED));
sctp_notify_stream_reset(stcb, error, ((uint16_t *) data),
(SCTP_STREAM_RESET_OUTGOING | SCTP_STREAM_RESET_INCOMING));
break;
case SCTP_NOTIFY_ASCONF_ADD_IP:
sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data,

View File

@ -87,6 +87,12 @@ int sctp_init_asoc(struct sctp_inpcb *, struct sctp_tcb *, uint32_t, uint32_t);
void sctp_fill_random_store(struct sctp_pcb *);
void
sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin,
uint16_t numberout, int flag);
void
sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag);
void
sctp_timer_start(int, struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);