mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-30 08:19:09 +00:00
Add the add-stream capability. Still needs more
testing.. MFC after: 1 month
This commit is contained in:
parent
d9d641af77
commit
ea44232b3a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=188854
@ -418,11 +418,12 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_HOSTNAME_ADDRESS 0x000b
|
||||
#define SCTP_SUPPORTED_ADDRTYPE 0x000c
|
||||
|
||||
/* draft-ietf-stewart-strreset-xxx */
|
||||
/* draft-ietf-stewart-tsvwg-strreset-xxx */
|
||||
#define SCTP_STR_RESET_OUT_REQUEST 0x000d
|
||||
#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_MAX_RESET_PARAMS 2
|
||||
#define SCTP_STREAM_RESET_TSN_DELTA 0x1000
|
||||
@ -794,7 +795,11 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_NOTIFY_SPECIAL_SP_FAIL 27
|
||||
#define SCTP_NOTIFY_NO_PEER_AUTH 28
|
||||
#define SCTP_NOTIFY_SENDER_DRY 29
|
||||
#define SCTP_NOTIFY_MAX 29
|
||||
#define SCTP_NOTIFY_STR_RESET_ADD_OK 30
|
||||
#define SCTP_NOTIFY_STR_RESET_ADD_FAIL 31
|
||||
#define SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK 32
|
||||
#define SCTP_NOTIFY_MAX 32
|
||||
|
||||
|
||||
/* This is the value for messages that are NOT completely
|
||||
* copied down where we will start to split the message.
|
||||
|
@ -498,7 +498,12 @@ struct sctp_stream_reset_response_tsn {
|
||||
uint32_t receivers_next_tsn;
|
||||
} SCTP_PACKED;
|
||||
|
||||
|
||||
struct sctp_stream_reset_add_strm {
|
||||
struct sctp_paramhdr ph;
|
||||
uint32_t request_seq;
|
||||
uint16_t number_of_streams;
|
||||
uint16_t reserved;
|
||||
};
|
||||
|
||||
#define SCTP_STREAM_RESET_NOTHING 0x00000000 /* Nothing for me to do */
|
||||
#define SCTP_STREAM_RESET_PERFORMED 0x00000001 /* Did it */
|
||||
|
@ -314,7 +314,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
|
||||
asoc->pre_open_streams = newcnt;
|
||||
}
|
||||
SCTP_TCB_SEND_UNLOCK(stcb);
|
||||
asoc->streamoutcnt = asoc->pre_open_streams;
|
||||
asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams;
|
||||
/* init tsn's */
|
||||
asoc->highest_tsn_inside_map = asoc->asconf_seq_in = ntohl(init->initial_tsn) - 1;
|
||||
/* EY - nr_sack: initialize highest tsn in nr_mapping_array */
|
||||
@ -3440,6 +3440,17 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
|
||||
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);
|
||||
}
|
||||
} else if (type == SCTP_STR_RESET_ADD_STREAMS) {
|
||||
/* Ok we now may have more streams */
|
||||
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);
|
||||
} else {
|
||||
sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_ADD_FAIL, stcb,
|
||||
(uint32_t) stcb->asoc.streamoutcnt, NULL, SCTP_SO_NOT_LOCKED);
|
||||
}
|
||||
} else if (type == SCTP_STR_RESET_TSN_REQUEST) {
|
||||
/**
|
||||
* a) Adopt the new in tsn.
|
||||
@ -3709,6 +3720,63 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_handle_str_reset_add_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, i;
|
||||
uint32_t seq;
|
||||
|
||||
/* Get the number. */
|
||||
seq = ntohl(str_add->request_seq);
|
||||
num_stream = ntohs(str_add->number_of_streams);
|
||||
/* Now what would be the new total? */
|
||||
num_stream += stcb->asoc.streamincnt;
|
||||
if (num_stream > stcb->asoc.max_inbound_streams) {
|
||||
/* 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;
|
||||
} else {
|
||||
/* Ok, we can do that :-) */
|
||||
struct sctp_stream_in *oldstrm;
|
||||
|
||||
/* save off the old */
|
||||
oldstrm = stcb->asoc.strmin;
|
||||
SCTP_MALLOC(stcb->asoc.strmin, struct sctp_stream_in *,
|
||||
(num_stream * sizeof(struct sctp_stream_in)),
|
||||
SCTP_M_STRMI);
|
||||
if (stcb->asoc.strmin == NULL) {
|
||||
stcb->asoc.strmin = oldstrm;
|
||||
goto denied;
|
||||
}
|
||||
/* copy off the old data */
|
||||
memcpy(stcb->asoc.strmin, oldstrm,
|
||||
(stcb->asoc.streamincnt * sizeof(struct sctp_stream_in)));
|
||||
/* Init the new streams */
|
||||
for (i = stcb->asoc.streamincnt; i < num_stream; i++) {
|
||||
TAILQ_INIT(&stcb->asoc.strmin[i].inqueue);
|
||||
stcb->asoc.strmin[i].stream_no = i;
|
||||
stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
|
||||
stcb->asoc.strmin[i].delivery_started = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noinline))
|
||||
#endif
|
||||
@ -3803,6 +3871,12 @@ __attribute__((noinline))
|
||||
}
|
||||
}
|
||||
sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc);
|
||||
} else if (ptype == SCTP_STR_RESET_ADD_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_IN_REQUEST) {
|
||||
struct sctp_stream_reset_in_request *req_in;
|
||||
|
||||
|
@ -8620,13 +8620,12 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
sp->some_taken = 1;
|
||||
}
|
||||
} else {
|
||||
to_move = sctp_can_we_split_this(stcb, length, goal_mtu,
|
||||
frag_point, eeor_mode);
|
||||
to_move = sctp_can_we_split_this(stcb, length, goal_mtu, frag_point, eeor_mode);
|
||||
if (to_move) {
|
||||
/*-
|
||||
* We use a snapshot of length in case it
|
||||
* is expanding during the compare.
|
||||
*/
|
||||
* We use a snapshot of length in case it
|
||||
* is expanding during the compare.
|
||||
*/
|
||||
uint32_t llen;
|
||||
|
||||
llen = length;
|
||||
@ -8634,9 +8633,9 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
to_move = llen;
|
||||
if (send_lock_up == 0) {
|
||||
/*-
|
||||
* We are taking all of an incomplete msg
|
||||
* thus we need a send lock.
|
||||
*/
|
||||
* We are taking all of an incomplete msg
|
||||
* thus we need a send lock.
|
||||
*/
|
||||
SCTP_TCB_SEND_LOCK(stcb);
|
||||
send_lock_up = 1;
|
||||
if (sp->msg_is_complete) {
|
||||
@ -8836,8 +8835,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
goto out_of;
|
||||
}
|
||||
sctp_snd_sb_alloc(stcb, sizeof(struct sctp_data_chunk));
|
||||
chk->book_size = chk->send_size = (to_move +
|
||||
sizeof(struct sctp_data_chunk));
|
||||
chk->book_size = chk->send_size = (to_move + sizeof(struct sctp_data_chunk));
|
||||
chk->book_size_scale = 0;
|
||||
chk->sent = SCTP_DATAGRAM_UNSENT;
|
||||
|
||||
@ -13339,13 +13337,49 @@ sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk,
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_add_a_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_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_out_req,
|
||||
uint32_t resp_seq,
|
||||
uint8_t send_in_req,
|
||||
uint8_t send_tsn_req)
|
||||
uint8_t send_tsn_req,
|
||||
uint8_t add_stream,
|
||||
uint16_t adding
|
||||
)
|
||||
{
|
||||
|
||||
struct sctp_association *asoc;
|
||||
@ -13361,7 +13395,8 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
|
||||
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EBUSY);
|
||||
return (EBUSY);
|
||||
}
|
||||
if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0)) {
|
||||
if ((send_out_req == 0) && (send_in_req == 0) && (send_tsn_req == 0) &&
|
||||
(add_stream == 0)) {
|
||||
/* nothing to do */
|
||||
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
|
||||
return (EINVAL);
|
||||
@ -13412,6 +13447,11 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb,
|
||||
seq++;
|
||||
asoc->stream_reset_outstanding++;
|
||||
}
|
||||
if (add_stream) {
|
||||
sctp_add_a_stream(chk, seq, adding);
|
||||
seq++;
|
||||
asoc->stream_reset_outstanding++;
|
||||
}
|
||||
if (send_in_req) {
|
||||
sctp_add_stream_reset_in(chk, number_entries, list, seq);
|
||||
asoc->stream_reset_outstanding++;
|
||||
@ -14432,7 +14472,7 @@ sctp_lower_sosend(struct socket *so,
|
||||
if (tmp_str != NULL) {
|
||||
SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
|
||||
asoc->strmout = tmp_str;
|
||||
asoc->streamoutcnt = asoc->pre_open_streams;
|
||||
asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams;
|
||||
} else {
|
||||
asoc->pre_open_streams = asoc->streamoutcnt;
|
||||
}
|
||||
@ -15015,9 +15055,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
|
||||
(stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
|
||||
if (net->flight_size > net->cwnd) {
|
||||
queue_only = 1;
|
||||
SCTP_STAT_INCR(sctps_send_burst_avoid);
|
||||
} else if (net->flight_size > net->cwnd) {
|
||||
queue_only = 1;
|
||||
SCTP_STAT_INCR(sctps_send_cwnd_avoid);
|
||||
} else {
|
||||
@ -15292,9 +15329,6 @@ sctp_lower_sosend(struct socket *so,
|
||||
un_sent = ((stcb->asoc.total_output_queue_size - stcb->asoc.total_flight) +
|
||||
(stcb->asoc.stream_queue_cnt * sizeof(struct sctp_data_chunk)));
|
||||
if (net->flight_size > net->cwnd) {
|
||||
queue_only = 1;
|
||||
SCTP_STAT_INCR(sctps_send_burst_avoid);
|
||||
} else if (net->flight_size > net->cwnd) {
|
||||
queue_only = 1;
|
||||
SCTP_STAT_INCR(sctps_send_cwnd_avoid);
|
||||
} else {
|
||||
|
@ -192,10 +192,14 @@ 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,
|
||||
uint8_t send_out_req, uint32_t resp_seq,
|
||||
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 send_tsn_req,
|
||||
uint8_t add_str,
|
||||
uint16_t adding);
|
||||
|
||||
|
||||
void
|
||||
|
@ -4885,7 +4885,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
|
||||
asoc->strmout = NULL;
|
||||
}
|
||||
asoc->streamoutcnt = 0;
|
||||
asoc->strm_realoutsize = asoc->streamoutcnt = 0;
|
||||
if (asoc->strmin) {
|
||||
struct sctp_queued_to_read *ctl;
|
||||
|
||||
|
@ -935,7 +935,7 @@ struct sctp_association {
|
||||
/* could re-arrange to optimize space here. */
|
||||
uint16_t streamincnt;
|
||||
uint16_t streamoutcnt;
|
||||
|
||||
uint16_t strm_realoutsize;
|
||||
/* my maximum number of retrans of INIT and SEND */
|
||||
/* copied from SCTP but should be individually setable */
|
||||
uint16_t max_init_times;
|
||||
|
@ -377,7 +377,7 @@ struct sctp_stream_reset_event {
|
||||
#define SCTP_STRRESET_ALL_STREAMS 0x0004
|
||||
#define SCTP_STRRESET_STREAM_LIST 0x0008
|
||||
#define SCTP_STRRESET_FAILED 0x0010
|
||||
|
||||
#define SCTP_STRRESET_ADD_STREAM 0x0020
|
||||
|
||||
/* SCTP notification event */
|
||||
struct sctp_tlv {
|
||||
@ -596,6 +596,7 @@ struct sctp_blk_args {
|
||||
#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;
|
||||
@ -941,9 +942,7 @@ struct sctpstat {
|
||||
uint32_t sctps_cached_strmoq; /* Number of cached stream oq's used */
|
||||
uint32_t sctps_left_abandon; /* Number of unread message abandonded
|
||||
* by close */
|
||||
uint32_t sctps_send_burst_avoid; /* Send burst avoidance,
|
||||
* already max burst inflight
|
||||
* to net */
|
||||
uint32_t sctps_send_burst_avoid; /* Unused */
|
||||
uint32_t sctps_send_cwnd_avoid; /* Send cwnd full avoidance, already
|
||||
* max burst inflight to net */
|
||||
uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via
|
||||
|
@ -3263,7 +3263,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
case SCTP_RESET_STREAMS:
|
||||
{
|
||||
struct sctp_stream_reset *strrst;
|
||||
uint8_t send_in = 0, send_tsn = 0, send_out = 0;
|
||||
uint8_t send_in = 0, send_tsn = 0, send_out = 0,
|
||||
addstream = 0;
|
||||
uint16_t addstrmcnt = 0;
|
||||
int i;
|
||||
|
||||
SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_stream_reset, optsize);
|
||||
@ -3301,6 +3303,60 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
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;
|
||||
|
||||
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.
|
||||
*/
|
||||
memcpy(stcb->asoc.strmout, oldstream,
|
||||
(stcb->asoc.streamoutcnt * sizeof(struct sctp_stream_out)));
|
||||
/* now the new streams */
|
||||
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.strmout[i].next_spoke.tqe_next = 0;
|
||||
stcb->asoc.strmout[i].next_spoke.tqe_prev = 0;
|
||||
}
|
||||
stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt + addstrmcnt;
|
||||
SCTP_FREE(oldstream, SCTP_M_STRMO);
|
||||
}
|
||||
goto skip_stuff;
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
error = EINVAL;
|
||||
@ -3322,6 +3378,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
goto get_out;
|
||||
}
|
||||
}
|
||||
skip_stuff:
|
||||
if (error) {
|
||||
get_out:
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
@ -3330,7 +3387,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
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);
|
||||
send_in, send_tsn, addstream, addstrmcnt);
|
||||
|
||||
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
|
@ -1119,7 +1119,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
|
||||
* Now the stream parameters, here we allocate space for all streams
|
||||
* that we request by default.
|
||||
*/
|
||||
asoc->streamoutcnt = asoc->pre_open_streams =
|
||||
asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
|
||||
m->sctp_ep.pre_open_stream_count;
|
||||
SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
|
||||
asoc->streamoutcnt * sizeof(struct sctp_stream_out),
|
||||
@ -3351,6 +3351,63 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
|
||||
&stcb->sctp_socket->so_rcv, 1, so_locked);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag)
|
||||
{
|
||||
struct mbuf *m_notify;
|
||||
struct sctp_queued_to_read *control;
|
||||
struct sctp_stream_reset_event *strreset;
|
||||
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_stream_reset_event) + (number_entries * sizeof(uint16_t));
|
||||
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;
|
||||
|
||||
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, 0, 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_SO_NOT_LOCKED);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sctp_notify_stream_reset(struct sctp_tcb *stcb,
|
||||
int number_entries, uint16_t * list, int flag)
|
||||
@ -3528,6 +3585,16 @@ 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);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user