summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2009-02-20 15:03:54 +0000
committerrrs <rrs@FreeBSD.org>2009-02-20 15:03:54 +0000
commitfedf85598960cec3b904b5a11185a96887e1f922 (patch)
tree9c34a30433ed20d140768759bdac33b2130a9392 /sys/netinet
parentc271f8f194572e316996f807a7b9022039adb6f5 (diff)
downloadFreeBSD-src-fedf85598960cec3b904b5a11185a96887e1f922.zip
FreeBSD-src-fedf85598960cec3b904b5a11185a96887e1f922.tar.gz
Add the add-stream capability. Still needs more
testing.. MFC after: 1 month
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/sctp_constants.h9
-rw-r--r--sys/netinet/sctp_header.h7
-rw-r--r--sys/netinet/sctp_input.c76
-rw-r--r--sys/netinet/sctp_output.c74
-rw-r--r--sys/netinet/sctp_output.h10
-rw-r--r--sys/netinet/sctp_pcb.c2
-rw-r--r--sys/netinet/sctp_structs.h2
-rw-r--r--sys/netinet/sctp_uio.h7
-rw-r--r--sys/netinet/sctp_usrreq.c61
-rw-r--r--sys/netinet/sctputil.c69
10 files changed, 281 insertions, 36 deletions
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index ca9c010..d8f3627 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -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.
diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h
index ccfee63..c551e53 100644
--- a/sys/netinet/sctp_header.h
+++ b/sys/netinet/sctp_header.h
@@ -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 */
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 2d8a1f2..c187aac 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -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 @@ strres_nochunk:
}
}
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;
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 8593ee6..4ebd0b4 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -8620,13 +8620,12 @@ re_look:
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 @@ re_look:
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 @@ dont_do_it:
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;
}
@@ -15016,9 +15056,6 @@ skip_preblock:
(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 {
queue_only = 0;
@@ -15293,9 +15330,6 @@ skip_out_eof:
(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 {
queue_only = 0;
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index 898f554..8a8a064 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -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
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index b9b7218..d98e760 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -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;
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 35318ff..a03ae94 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -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;
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index f9b3d8f..b8d2ecd 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -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
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 81a64a4..c64026b 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -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);
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 615d8fa..1eac98a 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -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;
OpenPOWER on IntegriCloud