Make stream our stream reset implementation
compliant to RFC6525. MFC after: 1 month
This commit is contained in:
parent
7fb26c47df
commit
c4e848b770
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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 *);
|
||||
|
Loading…
Reference in New Issue
Block a user