From owner-svn-src-head@FreeBSD.ORG Fri Feb 20 15:03:55 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B81571065675; Fri, 20 Feb 2009 15:03:55 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A61658FC15; Fri, 20 Feb 2009 15:03:55 +0000 (UTC) (envelope-from rrs@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n1KF3tQR032099; Fri, 20 Feb 2009 15:03:55 GMT (envelope-from rrs@svn.freebsd.org) Received: (from rrs@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n1KF3tsh032089; Fri, 20 Feb 2009 15:03:55 GMT (envelope-from rrs@svn.freebsd.org) Message-Id: <200902201503.n1KF3tsh032089@svn.freebsd.org> From: Randall Stewart Date: Fri, 20 Feb 2009 15:03:55 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r188854 - head/sys/netinet X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Feb 2009 15:03:56 -0000 Author: rrs Date: Fri Feb 20 15:03:54 2009 New Revision: 188854 URL: http://svn.freebsd.org/changeset/base/188854 Log: Add the add-stream capability. Still needs more testing.. MFC after: 1 month Modified: head/sys/netinet/sctp_constants.h head/sys/netinet/sctp_header.h head/sys/netinet/sctp_input.c head/sys/netinet/sctp_output.c head/sys/netinet/sctp_output.h head/sys/netinet/sctp_pcb.c head/sys/netinet/sctp_structs.h head/sys/netinet/sctp_uio.h head/sys/netinet/sctp_usrreq.c head/sys/netinet/sctputil.c Modified: head/sys/netinet/sctp_constants.h ============================================================================== --- head/sys/netinet/sctp_constants.h Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_constants.h Fri Feb 20 15:03:54 2009 (r188854) @@ -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. Modified: head/sys/netinet/sctp_header.h ============================================================================== --- head/sys/netinet/sctp_header.h Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_header.h Fri Feb 20 15:03:54 2009 (r188854) @@ -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 */ Modified: head/sys/netinet/sctp_input.c ============================================================================== --- head/sys/netinet/sctp_input.c Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_input.c Fri Feb 20 15:03:54 2009 (r188854) @@ -314,7 +314,7 @@ sctp_process_init(struct sctp_init_chunk 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 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 } } +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; Modified: head/sys/netinet/sctp_output.c ============================================================================== --- head/sys/netinet/sctp_output.c Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_output.c Fri Feb 20 15:03:54 2009 (r188854) @@ -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 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 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 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; Modified: head/sys/netinet/sctp_output.h ============================================================================== --- head/sys/netinet/sctp_output.h Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_output.h Fri Feb 20 15:03:54 2009 (r188854) @@ -192,10 +192,14 @@ sctp_add_stream_reset_result_tsn(struct 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 Modified: head/sys/netinet/sctp_pcb.c ============================================================================== --- head/sys/netinet/sctp_pcb.c Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_pcb.c Fri Feb 20 15:03:54 2009 (r188854) @@ -4885,7 +4885,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, 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; Modified: head/sys/netinet/sctp_structs.h ============================================================================== --- head/sys/netinet/sctp_structs.h Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_structs.h Fri Feb 20 15:03:54 2009 (r188854) @@ -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; Modified: head/sys/netinet/sctp_uio.h ============================================================================== --- head/sys/netinet/sctp_uio.h Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_uio.h Fri Feb 20 15:03:54 2009 (r188854) @@ -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 Modified: head/sys/netinet/sctp_usrreq.c ============================================================================== --- head/sys/netinet/sctp_usrreq.c Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctp_usrreq.c Fri Feb 20 15:03:54 2009 (r188854) @@ -3263,7 +3263,9 @@ sctp_setopt(struct socket *so, int optna 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 optna 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 optna goto get_out; } } + skip_stuff: if (error) { get_out: SCTP_TCB_UNLOCK(stcb); @@ -3330,7 +3387,7 @@ sctp_setopt(struct socket *so, int optna 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); Modified: head/sys/netinet/sctputil.c ============================================================================== --- head/sys/netinet/sctputil.c Fri Feb 20 14:53:49 2009 (r188853) +++ head/sys/netinet/sctputil.c Fri Feb 20 15:03:54 2009 (r188854) @@ -1119,7 +1119,7 @@ sctp_init_asoc(struct sctp_inpcb *m, str * 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 &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, s 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;