1f8829a4aSRandall Stewart /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4830d754dSRandall Stewart * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 5807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 6807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 7f8829a4aSRandall Stewart * 8f8829a4aSRandall Stewart * Redistribution and use in source and binary forms, with or without 9f8829a4aSRandall Stewart * modification, are permitted provided that the following conditions are met: 10f8829a4aSRandall Stewart * 11f8829a4aSRandall Stewart * a) Redistributions of source code must retain the above copyright notice, 12f8829a4aSRandall Stewart * this list of conditions and the following disclaimer. 13f8829a4aSRandall Stewart * 14f8829a4aSRandall Stewart * b) Redistributions in binary form must reproduce the above copyright 15f8829a4aSRandall Stewart * notice, this list of conditions and the following disclaimer in 16f8829a4aSRandall Stewart * the documentation and/or other materials provided with the distribution. 17f8829a4aSRandall Stewart * 18f8829a4aSRandall Stewart * c) Neither the name of Cisco Systems, Inc. nor the names of its 19f8829a4aSRandall Stewart * contributors may be used to endorse or promote products derived 20f8829a4aSRandall Stewart * from this software without specific prior written permission. 21f8829a4aSRandall Stewart * 22f8829a4aSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23f8829a4aSRandall Stewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 24f8829a4aSRandall Stewart * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25f8829a4aSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26f8829a4aSRandall Stewart * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27f8829a4aSRandall Stewart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28f8829a4aSRandall Stewart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29f8829a4aSRandall Stewart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30f8829a4aSRandall Stewart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31f8829a4aSRandall Stewart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32f8829a4aSRandall Stewart * THE POSSIBILITY OF SUCH DAMAGE. 33f8829a4aSRandall Stewart */ 34f8829a4aSRandall Stewart 35f8829a4aSRandall Stewart #include <sys/cdefs.h> 36f8829a4aSRandall Stewart __FBSDID("$FreeBSD$"); 37f8829a4aSRandall Stewart 38f8829a4aSRandall Stewart #include <netinet/sctp_os.h> 39f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h> 40f8829a4aSRandall Stewart #include <netinet/sctputil.h> 41f8829a4aSRandall Stewart #include <netinet/sctp_var.h> 4242551e99SRandall Stewart #include <netinet/sctp_sysctl.h> 43f8829a4aSRandall Stewart #ifdef INET6 443a51a264SMichael Tuexen #include <netinet6/sctp6_var.h> 45f8829a4aSRandall Stewart #endif 46f8829a4aSRandall Stewart #include <netinet/sctp_header.h> 47f8829a4aSRandall Stewart #include <netinet/sctp_output.h> 48f8829a4aSRandall Stewart #include <netinet/sctp_uio.h> 49f8829a4aSRandall Stewart #include <netinet/sctp_timer.h> 5046bf534cSMichael Tuexen #include <netinet/sctp_indata.h> 51f8829a4aSRandall Stewart #include <netinet/sctp_auth.h> 52f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h> 53f7517433SRandall Stewart #include <netinet/sctp_bsd_addr.h> 5410e0318aSMichael Tuexen #if defined(INET6) || defined(INET) 5510e0318aSMichael Tuexen #include <netinet/tcp_var.h> 5610e0318aSMichael Tuexen #endif 573a51a264SMichael Tuexen #include <netinet/udp.h> 583a51a264SMichael Tuexen #include <netinet/udp_var.h> 593a51a264SMichael Tuexen #include <sys/proc.h> 60fd7af143SMichael Tuexen #ifdef INET6 61fd7af143SMichael Tuexen #include <netinet/icmp6.h> 62fd7af143SMichael Tuexen #endif 63f8829a4aSRandall Stewart 64f8829a4aSRandall Stewart 65b9e7085aSRandall Stewart #ifndef KTR_SCTP 66b9e7085aSRandall Stewart #define KTR_SCTP KTR_SUBSYS 6780fefe0aSRandall Stewart #endif 68f8829a4aSRandall Stewart 69ed654363SMichael Tuexen extern const struct sctp_cc_functions sctp_cc_functions[]; 70ed654363SMichael Tuexen extern const struct sctp_ss_functions sctp_ss_functions[]; 710e9a9c10SMichael Tuexen 72f8829a4aSRandall Stewart void 73dcb68fbaSMichael Tuexen sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) 74f8829a4aSRandall Stewart { 75c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 76c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 77f8829a4aSRandall Stewart 7880fefe0aSRandall Stewart sctp_clog.x.sb.stcb = stcb; 794e88d37aSMichael Tuexen sctp_clog.x.sb.so_sbcc = sb->sb_cc; 80f8829a4aSRandall Stewart if (stcb) 814e88d37aSMichael Tuexen sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc; 82f8829a4aSRandall Stewart else 8380fefe0aSRandall Stewart sctp_clog.x.sb.stcb_sbcc = 0; 8480fefe0aSRandall Stewart sctp_clog.x.sb.incr = incr; 85c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 8680fefe0aSRandall Stewart SCTP_LOG_EVENT_SB, 8780fefe0aSRandall Stewart from, 8880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 8980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 9080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 9180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 92c692df45SMichael Tuexen #endif 93f8829a4aSRandall Stewart } 94f8829a4aSRandall Stewart 95f8829a4aSRandall Stewart void 96f8829a4aSRandall Stewart sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) 97f8829a4aSRandall Stewart { 98c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 99c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 100f8829a4aSRandall Stewart 10180fefe0aSRandall Stewart sctp_clog.x.close.inp = (void *)inp; 10280fefe0aSRandall Stewart sctp_clog.x.close.sctp_flags = inp->sctp_flags; 103f8829a4aSRandall Stewart if (stcb) { 10480fefe0aSRandall Stewart sctp_clog.x.close.stcb = (void *)stcb; 10580fefe0aSRandall Stewart sctp_clog.x.close.state = (uint16_t)stcb->asoc.state; 106f8829a4aSRandall Stewart } else { 10780fefe0aSRandall Stewart sctp_clog.x.close.stcb = 0; 10880fefe0aSRandall Stewart sctp_clog.x.close.state = 0; 109f8829a4aSRandall Stewart } 11080fefe0aSRandall Stewart sctp_clog.x.close.loc = loc; 111c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 11280fefe0aSRandall Stewart SCTP_LOG_EVENT_CLOSE, 11380fefe0aSRandall Stewart 0, 11480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 11580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 11680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 11780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 118c692df45SMichael Tuexen #endif 119f8829a4aSRandall Stewart } 120f8829a4aSRandall Stewart 121f8829a4aSRandall Stewart void 122f8829a4aSRandall Stewart rto_logging(struct sctp_nets *net, int from) 123f8829a4aSRandall Stewart { 124c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 125c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 126f8829a4aSRandall Stewart 127bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 12880fefe0aSRandall Stewart sctp_clog.x.rto.net = (void *)net; 129be1d9176SMichael Tuexen sctp_clog.x.rto.rtt = net->rtt / 1000; 130c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 13180fefe0aSRandall Stewart SCTP_LOG_EVENT_RTT, 13280fefe0aSRandall Stewart from, 13380fefe0aSRandall Stewart sctp_clog.x.misc.log1, 13480fefe0aSRandall Stewart sctp_clog.x.misc.log2, 13580fefe0aSRandall Stewart sctp_clog.x.misc.log3, 13680fefe0aSRandall Stewart sctp_clog.x.misc.log4); 137c692df45SMichael Tuexen #endif 138f8829a4aSRandall Stewart } 139f8829a4aSRandall Stewart 140f8829a4aSRandall Stewart void 1416a91f103SRandall Stewart sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from) 142f8829a4aSRandall Stewart { 143c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 144c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 145f8829a4aSRandall Stewart 14680fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = stcb; 14780fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = tsn; 14880fefe0aSRandall Stewart sctp_clog.x.strlog.n_sseq = sseq; 14980fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 15080fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 15180fefe0aSRandall Stewart sctp_clog.x.strlog.strm = stream; 152c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 15380fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 15480fefe0aSRandall Stewart from, 15580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 15680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 15780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 15880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 159c692df45SMichael Tuexen #endif 160f8829a4aSRandall Stewart } 161f8829a4aSRandall Stewart 162f8829a4aSRandall Stewart void 163f8829a4aSRandall Stewart sctp_log_nagle_event(struct sctp_tcb *stcb, int action) 164f8829a4aSRandall Stewart { 165c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 166c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 167f8829a4aSRandall Stewart 16880fefe0aSRandall Stewart sctp_clog.x.nagle.stcb = (void *)stcb; 16980fefe0aSRandall Stewart sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight; 17080fefe0aSRandall Stewart sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size; 17180fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue; 17280fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count; 173c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 17480fefe0aSRandall Stewart SCTP_LOG_EVENT_NAGLE, 17580fefe0aSRandall Stewart action, 17680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 17780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 17880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 17980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 180c692df45SMichael Tuexen #endif 181f8829a4aSRandall Stewart } 182f8829a4aSRandall Stewart 183f8829a4aSRandall Stewart void 184f8829a4aSRandall Stewart sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from) 185f8829a4aSRandall Stewart { 186c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 187c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 188f8829a4aSRandall Stewart 18980fefe0aSRandall Stewart sctp_clog.x.sack.cumack = cumack; 19080fefe0aSRandall Stewart sctp_clog.x.sack.oldcumack = old_cumack; 19180fefe0aSRandall Stewart sctp_clog.x.sack.tsn = tsn; 19280fefe0aSRandall Stewart sctp_clog.x.sack.numGaps = gaps; 19380fefe0aSRandall Stewart sctp_clog.x.sack.numDups = dups; 194c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 19580fefe0aSRandall Stewart SCTP_LOG_EVENT_SACK, 19680fefe0aSRandall Stewart from, 19780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 19880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 19980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 20080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 201c692df45SMichael Tuexen #endif 202f8829a4aSRandall Stewart } 203f8829a4aSRandall Stewart 204f8829a4aSRandall Stewart void 205f8829a4aSRandall Stewart sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) 206f8829a4aSRandall Stewart { 207c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 208c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 209f8829a4aSRandall Stewart 210bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 21180fefe0aSRandall Stewart sctp_clog.x.map.base = map; 21280fefe0aSRandall Stewart sctp_clog.x.map.cum = cum; 21380fefe0aSRandall Stewart sctp_clog.x.map.high = high; 214c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 21580fefe0aSRandall Stewart SCTP_LOG_EVENT_MAP, 21680fefe0aSRandall Stewart from, 21780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 21880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 21980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 22080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 221c692df45SMichael Tuexen #endif 222f8829a4aSRandall Stewart } 223f8829a4aSRandall Stewart 224f8829a4aSRandall Stewart void 225dcb68fbaSMichael Tuexen sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from) 226f8829a4aSRandall Stewart { 227c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 228c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 229f8829a4aSRandall Stewart 230bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 23180fefe0aSRandall Stewart sctp_clog.x.fr.largest_tsn = biggest_tsn; 23280fefe0aSRandall Stewart sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn; 23380fefe0aSRandall Stewart sctp_clog.x.fr.tsn = tsn; 234c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 23580fefe0aSRandall Stewart SCTP_LOG_EVENT_FR, 23680fefe0aSRandall Stewart from, 23780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 23880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 23980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 24080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 241c692df45SMichael Tuexen #endif 242f8829a4aSRandall Stewart } 243f8829a4aSRandall Stewart 2444be807c4SMichael Tuexen #ifdef SCTP_MBUF_LOGGING 245f8829a4aSRandall Stewart void 246f8829a4aSRandall Stewart sctp_log_mb(struct mbuf *m, int from) 247f8829a4aSRandall Stewart { 248c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 249c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 250f8829a4aSRandall Stewart 25180fefe0aSRandall Stewart sctp_clog.x.mb.mp = m; 25280fefe0aSRandall Stewart sctp_clog.x.mb.mbuf_flags = (uint8_t)(SCTP_BUF_GET_FLAGS(m)); 25380fefe0aSRandall Stewart sctp_clog.x.mb.size = (uint16_t)(SCTP_BUF_LEN(m)); 25480fefe0aSRandall Stewart sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0); 255139bc87fSRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 25680fefe0aSRandall Stewart sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m); 25780fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m)); 258f8829a4aSRandall Stewart } else { 25980fefe0aSRandall Stewart sctp_clog.x.mb.ext = 0; 26080fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = 0; 261f8829a4aSRandall Stewart } 262c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 26380fefe0aSRandall Stewart SCTP_LOG_EVENT_MBUF, 26480fefe0aSRandall Stewart from, 26580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 26680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 26780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 26880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 269c692df45SMichael Tuexen #endif 270f8829a4aSRandall Stewart } 271f8829a4aSRandall Stewart 272f8829a4aSRandall Stewart void 2734be807c4SMichael Tuexen sctp_log_mbc(struct mbuf *m, int from) 2744be807c4SMichael Tuexen { 2754be807c4SMichael Tuexen struct mbuf *mat; 2764be807c4SMichael Tuexen 2774be807c4SMichael Tuexen for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { 2784be807c4SMichael Tuexen sctp_log_mb(mat, from); 2794be807c4SMichael Tuexen } 2804be807c4SMichael Tuexen } 2814be807c4SMichael Tuexen #endif 2824be807c4SMichael Tuexen 2834be807c4SMichael Tuexen void 284dcb68fbaSMichael Tuexen sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from) 285f8829a4aSRandall Stewart { 286c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 287c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 288f8829a4aSRandall Stewart 289f8829a4aSRandall Stewart if (control == NULL) { 290ad81507eSRandall Stewart SCTP_PRINTF("Gak log of NULL?\n"); 291f8829a4aSRandall Stewart return; 292f8829a4aSRandall Stewart } 29380fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = control->stcb; 29480fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = control->sinfo_tsn; 29549656eefSMichael Tuexen sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid; 29680fefe0aSRandall Stewart sctp_clog.x.strlog.strm = control->sinfo_stream; 297f8829a4aSRandall Stewart if (poschk != NULL) { 29880fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn; 29949656eefSMichael Tuexen sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid; 300f8829a4aSRandall Stewart } else { 30180fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 30280fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 303f8829a4aSRandall Stewart } 304c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 30580fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 30680fefe0aSRandall Stewart from, 30780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 30880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 30980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 31080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 311c692df45SMichael Tuexen #endif 312f8829a4aSRandall Stewart } 313f8829a4aSRandall Stewart 314f8829a4aSRandall Stewart void 315f8829a4aSRandall Stewart sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from) 316f8829a4aSRandall Stewart { 317c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 318c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 319f8829a4aSRandall Stewart 32080fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 321f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 32280fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 323f8829a4aSRandall Stewart else 32480fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 325f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 32680fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 327f8829a4aSRandall Stewart else 32880fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 329f8829a4aSRandall Stewart 330f8829a4aSRandall Stewart if (net) { 33180fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = net->cwnd; 33280fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 33380fefe0aSRandall Stewart sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack; 33480fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack; 33580fefe0aSRandall Stewart sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack; 336f8829a4aSRandall Stewart } 337f8829a4aSRandall Stewart if (SCTP_CWNDLOG_PRESEND == from) { 33880fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd; 339f8829a4aSRandall Stewart } 34080fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = augment; 341c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 34280fefe0aSRandall Stewart SCTP_LOG_EVENT_CWND, 34380fefe0aSRandall Stewart from, 34480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 34580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 34680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 34780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 348c692df45SMichael Tuexen #endif 349f8829a4aSRandall Stewart } 350f8829a4aSRandall Stewart 351f8829a4aSRandall Stewart void 352f8829a4aSRandall Stewart sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) 353f8829a4aSRandall Stewart { 354c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 355c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 356f8829a4aSRandall Stewart 357bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 35803b0b021SRandall Stewart if (inp) { 35980fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)inp->sctp_socket; 36003b0b021SRandall Stewart 36103b0b021SRandall Stewart } else { 36280fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)NULL; 36303b0b021SRandall Stewart } 36480fefe0aSRandall Stewart sctp_clog.x.lock.inp = (void *)inp; 365f8829a4aSRandall Stewart if (stcb) { 36680fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx); 367f8829a4aSRandall Stewart } else { 36880fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN; 369f8829a4aSRandall Stewart } 370f8829a4aSRandall Stewart if (inp) { 37180fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx); 37280fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx); 373f8829a4aSRandall Stewart } else { 37480fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN; 37580fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN; 376f8829a4aSRandall Stewart } 377b3f1ea41SRandall Stewart sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); 37852129fcdSRandall Stewart if (inp && (inp->sctp_socket)) { 37980fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 38080fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 38180fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx)); 382f8829a4aSRandall Stewart } else { 38380fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN; 38480fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; 38580fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN; 386f8829a4aSRandall Stewart } 387c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 38880fefe0aSRandall Stewart SCTP_LOG_LOCK_EVENT, 38980fefe0aSRandall Stewart from, 39080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 39180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 39280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 39380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 394c692df45SMichael Tuexen #endif 395f8829a4aSRandall Stewart } 396f8829a4aSRandall Stewart 397f8829a4aSRandall Stewart void 398f8829a4aSRandall Stewart sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from) 399f8829a4aSRandall Stewart { 400c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 401c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 402f8829a4aSRandall Stewart 403bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 40480fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 40580fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = error; 40680fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 40780fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = burst; 408f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 40980fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 410f8829a4aSRandall Stewart else 41180fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 412f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 41380fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 414f8829a4aSRandall Stewart else 41580fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 416c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 41780fefe0aSRandall Stewart SCTP_LOG_EVENT_MAXBURST, 41880fefe0aSRandall Stewart from, 41980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 42080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 42180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 42280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 423c692df45SMichael Tuexen #endif 424f8829a4aSRandall Stewart } 425f8829a4aSRandall Stewart 426f8829a4aSRandall Stewart void 427f8829a4aSRandall Stewart sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead) 428f8829a4aSRandall Stewart { 429c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 430c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 431f8829a4aSRandall Stewart 43280fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 43380fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = snd_size; 43480fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 43580fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = 0; 436c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 43780fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 43880fefe0aSRandall Stewart from, 43980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 44080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 44180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 44280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 443c692df45SMichael Tuexen #endif 444f8829a4aSRandall Stewart } 445f8829a4aSRandall Stewart 446f8829a4aSRandall Stewart void 447f8829a4aSRandall Stewart sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval) 448f8829a4aSRandall Stewart { 449c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 450c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 451f8829a4aSRandall Stewart 45280fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 45380fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = flight_size; 45480fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 45580fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = a_rwndval; 456c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 45780fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 45880fefe0aSRandall Stewart from, 45980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 46080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 46180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 46280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 463c692df45SMichael Tuexen #endif 464f8829a4aSRandall Stewart } 465f8829a4aSRandall Stewart 4664be807c4SMichael Tuexen #ifdef SCTP_MBCNT_LOGGING 4674be807c4SMichael Tuexen static void 468f8829a4aSRandall Stewart sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt) 469f8829a4aSRandall Stewart { 470c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 471c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 472f8829a4aSRandall Stewart 47380fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_size = total_oq; 47480fefe0aSRandall Stewart sctp_clog.x.mbcnt.size_change = book; 47580fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q; 47680fefe0aSRandall Stewart sctp_clog.x.mbcnt.mbcnt_change = mbcnt; 477c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 47880fefe0aSRandall Stewart SCTP_LOG_EVENT_MBCNT, 47980fefe0aSRandall Stewart from, 48080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 48180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 48280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 48380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 484c692df45SMichael Tuexen #endif 485f8829a4aSRandall Stewart } 4864be807c4SMichael Tuexen #endif 4874be807c4SMichael Tuexen 488f8829a4aSRandall Stewart void 489f8829a4aSRandall Stewart sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) 490f8829a4aSRandall Stewart { 491c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 492c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 49380fefe0aSRandall Stewart SCTP_LOG_MISC_EVENT, 49480fefe0aSRandall Stewart from, 49580fefe0aSRandall Stewart a, b, c, d); 496c692df45SMichael Tuexen #endif 497f8829a4aSRandall Stewart } 498f8829a4aSRandall Stewart 499f8829a4aSRandall Stewart void 5007215cc1bSMichael Tuexen sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) 501f8829a4aSRandall Stewart { 502c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 503c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 504f8829a4aSRandall Stewart 50580fefe0aSRandall Stewart sctp_clog.x.wake.stcb = (void *)stcb; 50680fefe0aSRandall Stewart sctp_clog.x.wake.wake_cnt = wake_cnt; 50780fefe0aSRandall Stewart sctp_clog.x.wake.flight = stcb->asoc.total_flight_count; 50880fefe0aSRandall Stewart sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt; 50980fefe0aSRandall Stewart sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt; 510f8829a4aSRandall Stewart 511f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt < 0xff) 51280fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = (uint8_t)stcb->asoc.stream_queue_cnt; 513f8829a4aSRandall Stewart else 51480fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = 0xff; 515f8829a4aSRandall Stewart 516f8829a4aSRandall Stewart if (stcb->asoc.chunks_on_out_queue < 0xff) 51780fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = (uint8_t)stcb->asoc.chunks_on_out_queue; 518f8829a4aSRandall Stewart else 51980fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = 0xff; 520f8829a4aSRandall Stewart 52180fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags = 0; 522f8829a4aSRandall Stewart /* set in the defered mode stuff */ 523f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) 52480fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 1; 525f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) 52680fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 2; 527f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) 52880fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 4; 529f8829a4aSRandall Stewart /* what about the sb */ 530f8829a4aSRandall Stewart if (stcb->sctp_socket) { 531f8829a4aSRandall Stewart struct socket *so = stcb->sctp_socket; 532f8829a4aSRandall Stewart 53380fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = (uint8_t)((so->so_snd.sb_flags & 0x00ff)); 534f8829a4aSRandall Stewart } else { 53580fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = 0xff; 536f8829a4aSRandall Stewart } 537c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 53880fefe0aSRandall Stewart SCTP_LOG_EVENT_WAKE, 53980fefe0aSRandall Stewart from, 54080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 54180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 54280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 54380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 544c692df45SMichael Tuexen #endif 545f8829a4aSRandall Stewart } 546f8829a4aSRandall Stewart 547f8829a4aSRandall Stewart void 5489a8e3088SMichael Tuexen sctp_log_block(uint8_t from, struct sctp_association *asoc, size_t sendlen) 549f8829a4aSRandall Stewart { 550c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 551c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 552f8829a4aSRandall Stewart 55380fefe0aSRandall Stewart sctp_clog.x.blk.onsb = asoc->total_output_queue_size; 55480fefe0aSRandall Stewart sctp_clog.x.blk.send_sent_qcnt = (uint16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt); 55580fefe0aSRandall Stewart sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd; 55680fefe0aSRandall Stewart sctp_clog.x.blk.stream_qcnt = (uint16_t)asoc->stream_queue_cnt; 55780fefe0aSRandall Stewart sctp_clog.x.blk.chunks_on_oque = (uint16_t)asoc->chunks_on_out_queue; 55880fefe0aSRandall Stewart sctp_clog.x.blk.flight_size = (uint16_t)(asoc->total_flight / 1024); 5599a8e3088SMichael Tuexen sctp_clog.x.blk.sndlen = (uint32_t)sendlen; 560c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 56180fefe0aSRandall Stewart SCTP_LOG_EVENT_BLOCK, 56280fefe0aSRandall Stewart from, 56380fefe0aSRandall Stewart sctp_clog.x.misc.log1, 56480fefe0aSRandall Stewart sctp_clog.x.misc.log2, 56580fefe0aSRandall Stewart sctp_clog.x.misc.log3, 56680fefe0aSRandall Stewart sctp_clog.x.misc.log4); 567c692df45SMichael Tuexen #endif 568f8829a4aSRandall Stewart } 569f8829a4aSRandall Stewart 570f8829a4aSRandall Stewart int 5717215cc1bSMichael Tuexen sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED) 572f8829a4aSRandall Stewart { 57380fefe0aSRandall Stewart /* May need to fix this if ktrdump does not work */ 574f8829a4aSRandall Stewart return (0); 575f8829a4aSRandall Stewart } 576f8829a4aSRandall Stewart 577f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 578f8829a4aSRandall Stewart uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2]; 579f8829a4aSRandall Stewart static int sctp_audit_indx = 0; 580f8829a4aSRandall Stewart 581f8829a4aSRandall Stewart static 582f8829a4aSRandall Stewart void 583f8829a4aSRandall Stewart sctp_print_audit_report(void) 584f8829a4aSRandall Stewart { 585f8829a4aSRandall Stewart int i; 586f8829a4aSRandall Stewart int cnt; 587f8829a4aSRandall Stewart 588f8829a4aSRandall Stewart cnt = 0; 589f8829a4aSRandall Stewart for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) { 590f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 591f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 592f8829a4aSRandall Stewart cnt = 0; 593ad81507eSRandall Stewart SCTP_PRINTF("\n"); 594f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 595f8829a4aSRandall Stewart cnt = 0; 596ad81507eSRandall Stewart SCTP_PRINTF("\n"); 597f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 598f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 599ad81507eSRandall Stewart SCTP_PRINTF("\n"); 600f8829a4aSRandall Stewart cnt = 0; 601f8829a4aSRandall Stewart } 602ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0], 603f8829a4aSRandall Stewart (uint32_t)sctp_audit_data[i][1]); 604f8829a4aSRandall Stewart cnt++; 605f8829a4aSRandall Stewart if ((cnt % 14) == 0) 606ad81507eSRandall Stewart SCTP_PRINTF("\n"); 607f8829a4aSRandall Stewart } 608f8829a4aSRandall Stewart for (i = 0; i < sctp_audit_indx; i++) { 609f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 610f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 611f8829a4aSRandall Stewart cnt = 0; 612ad81507eSRandall Stewart SCTP_PRINTF("\n"); 613f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 614f8829a4aSRandall Stewart cnt = 0; 615ad81507eSRandall Stewart SCTP_PRINTF("\n"); 616f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 617f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 618ad81507eSRandall Stewart SCTP_PRINTF("\n"); 619f8829a4aSRandall Stewart cnt = 0; 620f8829a4aSRandall Stewart } 621ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0], 622f8829a4aSRandall Stewart (uint32_t)sctp_audit_data[i][1]); 623f8829a4aSRandall Stewart cnt++; 624f8829a4aSRandall Stewart if ((cnt % 14) == 0) 625ad81507eSRandall Stewart SCTP_PRINTF("\n"); 626f8829a4aSRandall Stewart } 627ad81507eSRandall Stewart SCTP_PRINTF("\n"); 628f8829a4aSRandall Stewart } 629f8829a4aSRandall Stewart 630f8829a4aSRandall Stewart void 631f8829a4aSRandall Stewart sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 632f8829a4aSRandall Stewart struct sctp_nets *net) 633f8829a4aSRandall Stewart { 634f8829a4aSRandall Stewart int resend_cnt, tot_out, rep, tot_book_cnt; 635f8829a4aSRandall Stewart struct sctp_nets *lnet; 636f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 637f8829a4aSRandall Stewart 638f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAA; 639f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from; 640f8829a4aSRandall Stewart sctp_audit_indx++; 641f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 642f8829a4aSRandall Stewart sctp_audit_indx = 0; 643f8829a4aSRandall Stewart } 644f8829a4aSRandall Stewart if (inp == NULL) { 645f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 646f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x01; 647f8829a4aSRandall Stewart sctp_audit_indx++; 648f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 649f8829a4aSRandall Stewart sctp_audit_indx = 0; 650f8829a4aSRandall Stewart } 651f8829a4aSRandall Stewart return; 652f8829a4aSRandall Stewart } 653f8829a4aSRandall Stewart if (stcb == NULL) { 654f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 655f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x02; 656f8829a4aSRandall Stewart sctp_audit_indx++; 657f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 658f8829a4aSRandall Stewart sctp_audit_indx = 0; 659f8829a4aSRandall Stewart } 660f8829a4aSRandall Stewart return; 661f8829a4aSRandall Stewart } 662f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA1; 663f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 664f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 665f8829a4aSRandall Stewart sctp_audit_indx++; 666f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 667f8829a4aSRandall Stewart sctp_audit_indx = 0; 668f8829a4aSRandall Stewart } 669f8829a4aSRandall Stewart rep = 0; 670f8829a4aSRandall Stewart tot_book_cnt = 0; 671f8829a4aSRandall Stewart resend_cnt = tot_out = 0; 672f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 673f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 674f8829a4aSRandall Stewart resend_cnt++; 675f8829a4aSRandall Stewart } else if (chk->sent < SCTP_DATAGRAM_RESEND) { 676f8829a4aSRandall Stewart tot_out += chk->book_size; 677f8829a4aSRandall Stewart tot_book_cnt++; 678f8829a4aSRandall Stewart } 679f8829a4aSRandall Stewart } 680f8829a4aSRandall Stewart if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) { 681f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 682f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA1; 683f8829a4aSRandall Stewart sctp_audit_indx++; 684f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 685f8829a4aSRandall Stewart sctp_audit_indx = 0; 686f8829a4aSRandall Stewart } 687ad81507eSRandall Stewart SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n", 688f8829a4aSRandall Stewart resend_cnt, stcb->asoc.sent_queue_retran_cnt); 689f8829a4aSRandall Stewart rep = 1; 690f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = resend_cnt; 691f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA2; 692f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 693f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 694f8829a4aSRandall Stewart sctp_audit_indx++; 695f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 696f8829a4aSRandall Stewart sctp_audit_indx = 0; 697f8829a4aSRandall Stewart } 698f8829a4aSRandall Stewart } 699f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 700f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 701f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA2; 702f8829a4aSRandall Stewart sctp_audit_indx++; 703f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 704f8829a4aSRandall Stewart sctp_audit_indx = 0; 705f8829a4aSRandall Stewart } 706f8829a4aSRandall Stewart rep = 1; 707ad81507eSRandall Stewart SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out, 708f8829a4aSRandall Stewart (int)stcb->asoc.total_flight); 709f8829a4aSRandall Stewart stcb->asoc.total_flight = tot_out; 710f8829a4aSRandall Stewart } 711f8829a4aSRandall Stewart if (tot_book_cnt != stcb->asoc.total_flight_count) { 712f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 713f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA5; 714f8829a4aSRandall Stewart sctp_audit_indx++; 715f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 716f8829a4aSRandall Stewart sctp_audit_indx = 0; 717f8829a4aSRandall Stewart } 718f8829a4aSRandall Stewart rep = 1; 719f31e6c7fSMichael Tuexen SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt); 720f8829a4aSRandall Stewart 721f8829a4aSRandall Stewart stcb->asoc.total_flight_count = tot_book_cnt; 722f8829a4aSRandall Stewart } 723f8829a4aSRandall Stewart tot_out = 0; 724f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 725f8829a4aSRandall Stewart tot_out += lnet->flight_size; 726f8829a4aSRandall Stewart } 727f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 728f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 729f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA3; 730f8829a4aSRandall Stewart sctp_audit_indx++; 731f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 732f8829a4aSRandall Stewart sctp_audit_indx = 0; 733f8829a4aSRandall Stewart } 734f8829a4aSRandall Stewart rep = 1; 735ad81507eSRandall Stewart SCTP_PRINTF("real flight:%d net total was %d\n", 736f8829a4aSRandall Stewart stcb->asoc.total_flight, tot_out); 737f8829a4aSRandall Stewart /* now corrective action */ 738f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 739f8829a4aSRandall Stewart 740f8829a4aSRandall Stewart tot_out = 0; 741f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 742f8829a4aSRandall Stewart if ((chk->whoTo == lnet) && 743f8829a4aSRandall Stewart (chk->sent < SCTP_DATAGRAM_RESEND)) { 744f8829a4aSRandall Stewart tot_out += chk->book_size; 745f8829a4aSRandall Stewart } 746f8829a4aSRandall Stewart } 747f8829a4aSRandall Stewart if (lnet->flight_size != tot_out) { 748f31e6c7fSMichael Tuexen SCTP_PRINTF("net:%p flight was %d corrected to %d\n", 749dd294dceSMichael Tuexen (void *)lnet, lnet->flight_size, 750ad81507eSRandall Stewart tot_out); 751f8829a4aSRandall Stewart lnet->flight_size = tot_out; 752f8829a4aSRandall Stewart } 753f8829a4aSRandall Stewart } 754f8829a4aSRandall Stewart } 755f8829a4aSRandall Stewart if (rep) { 756f8829a4aSRandall Stewart sctp_print_audit_report(); 757f8829a4aSRandall Stewart } 758f8829a4aSRandall Stewart } 759f8829a4aSRandall Stewart 760f8829a4aSRandall Stewart void 761f8829a4aSRandall Stewart sctp_audit_log(uint8_t ev, uint8_t fd) 762f8829a4aSRandall Stewart { 763f8829a4aSRandall Stewart 764f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = ev; 765f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = fd; 766f8829a4aSRandall Stewart sctp_audit_indx++; 767f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 768f8829a4aSRandall Stewart sctp_audit_indx = 0; 769f8829a4aSRandall Stewart } 770f8829a4aSRandall Stewart } 771f8829a4aSRandall Stewart 772f8829a4aSRandall Stewart #endif 773f8829a4aSRandall Stewart 774f8829a4aSRandall Stewart /* 77512af6654SMichael Tuexen * sctp_stop_timers_for_shutdown() should be called 77612af6654SMichael Tuexen * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT 77712af6654SMichael Tuexen * state to make sure that all timers are stopped. 77812af6654SMichael Tuexen */ 77912af6654SMichael Tuexen void 78012af6654SMichael Tuexen sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) 78112af6654SMichael Tuexen { 78212af6654SMichael Tuexen struct sctp_association *asoc; 78312af6654SMichael Tuexen struct sctp_nets *net; 78412af6654SMichael Tuexen 78512af6654SMichael Tuexen asoc = &stcb->asoc; 78612af6654SMichael Tuexen 78712af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); 78812af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); 78912af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer); 79012af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); 79112af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); 79212af6654SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 79312af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); 794ca85e948SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); 79512af6654SMichael Tuexen } 79612af6654SMichael Tuexen } 79712af6654SMichael Tuexen 79812af6654SMichael Tuexen /* 799589c42c2SMichael Tuexen * A list of sizes based on typical mtu's, used only if next hop size not 800589c42c2SMichael Tuexen * returned. These values MUST be multiples of 4 and MUST be ordered. 801f8829a4aSRandall Stewart */ 802437fc91aSMichael Tuexen static uint32_t sctp_mtu_sizes[] = { 803f8829a4aSRandall Stewart 68, 804f8829a4aSRandall Stewart 296, 805f8829a4aSRandall Stewart 508, 806f8829a4aSRandall Stewart 512, 807f8829a4aSRandall Stewart 544, 808f8829a4aSRandall Stewart 576, 809589c42c2SMichael Tuexen 1004, 810f8829a4aSRandall Stewart 1492, 811f8829a4aSRandall Stewart 1500, 812f8829a4aSRandall Stewart 1536, 813589c42c2SMichael Tuexen 2000, 814f8829a4aSRandall Stewart 2048, 815f8829a4aSRandall Stewart 4352, 816f8829a4aSRandall Stewart 4464, 817f8829a4aSRandall Stewart 8166, 818589c42c2SMichael Tuexen 17912, 819f8829a4aSRandall Stewart 32000, 820589c42c2SMichael Tuexen 65532 821f8829a4aSRandall Stewart }; 822f8829a4aSRandall Stewart 823f8829a4aSRandall Stewart /* 824589c42c2SMichael Tuexen * Return the largest MTU in sctp_mtu_sizes smaller than val. 825589c42c2SMichael Tuexen * If val is smaller than the minimum, just return the largest 826589c42c2SMichael Tuexen * multiple of 4 smaller or equal to val. 827589c42c2SMichael Tuexen * Ensure that the result is a multiple of 4. 828f8829a4aSRandall Stewart */ 829437fc91aSMichael Tuexen uint32_t 830*b0471b4bSMichael Tuexen sctp_get_prev_mtu(uint32_t val) 831*b0471b4bSMichael Tuexen { 832437fc91aSMichael Tuexen uint32_t i; 833437fc91aSMichael Tuexen 834eef8d4a9SMichael Tuexen val &= 0xfffffffc; 835437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[0]) { 836437fc91aSMichael Tuexen return (val); 837437fc91aSMichael Tuexen } 838437fc91aSMichael Tuexen for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 839437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[i]) { 840f8829a4aSRandall Stewart break; 841f8829a4aSRandall Stewart } 842f8829a4aSRandall Stewart } 843589c42c2SMichael Tuexen KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0, 844589c42c2SMichael Tuexen ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1)); 845437fc91aSMichael Tuexen return (sctp_mtu_sizes[i - 1]); 846437fc91aSMichael Tuexen } 847437fc91aSMichael Tuexen 848437fc91aSMichael Tuexen /* 849589c42c2SMichael Tuexen * Return the smallest MTU in sctp_mtu_sizes larger than val. 850589c42c2SMichael Tuexen * If val is larger than the maximum, just return the largest multiple of 4 smaller 851589c42c2SMichael Tuexen * or equal to val. 852589c42c2SMichael Tuexen * Ensure that the result is a multiple of 4. 853437fc91aSMichael Tuexen */ 854437fc91aSMichael Tuexen uint32_t 855*b0471b4bSMichael Tuexen sctp_get_next_mtu(uint32_t val) 856*b0471b4bSMichael Tuexen { 857437fc91aSMichael Tuexen /* select another MTU that is just bigger than this one */ 858437fc91aSMichael Tuexen uint32_t i; 859437fc91aSMichael Tuexen 860eef8d4a9SMichael Tuexen val &= 0xfffffffc; 861437fc91aSMichael Tuexen for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 862437fc91aSMichael Tuexen if (val < sctp_mtu_sizes[i]) { 863589c42c2SMichael Tuexen KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0, 864589c42c2SMichael Tuexen ("sctp_mtu_sizes[%u] not a multiple of 4", i)); 865437fc91aSMichael Tuexen return (sctp_mtu_sizes[i]); 866437fc91aSMichael Tuexen } 867437fc91aSMichael Tuexen } 868437fc91aSMichael Tuexen return (val); 869f8829a4aSRandall Stewart } 870f8829a4aSRandall Stewart 871f8829a4aSRandall Stewart void 872f8829a4aSRandall Stewart sctp_fill_random_store(struct sctp_pcb *m) 873f8829a4aSRandall Stewart { 874f8829a4aSRandall Stewart /* 875f8829a4aSRandall Stewart * Here we use the MD5/SHA-1 to hash with our good randomNumbers and 876f8829a4aSRandall Stewart * our counter. The result becomes our good random numbers and we 877f8829a4aSRandall Stewart * then setup to give these out. Note that we do no locking to 878f8829a4aSRandall Stewart * protect this. This is ok, since if competing folks call this we 87917205eccSRandall Stewart * will get more gobbled gook in the random store which is what we 880f8829a4aSRandall Stewart * want. There is a danger that two guys will use the same random 881f8829a4aSRandall Stewart * numbers, but thats ok too since that is random as well :-> 882f8829a4aSRandall Stewart */ 883f8829a4aSRandall Stewart m->store_at = 0; 884ad81507eSRandall Stewart (void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers, 885f8829a4aSRandall Stewart sizeof(m->random_numbers), (uint8_t *)&m->random_counter, 886f8829a4aSRandall Stewart sizeof(m->random_counter), (uint8_t *)m->random_store); 887f8829a4aSRandall Stewart m->random_counter++; 888f8829a4aSRandall Stewart } 889f8829a4aSRandall Stewart 890f8829a4aSRandall Stewart uint32_t 891*b0471b4bSMichael Tuexen sctp_select_initial_TSN(struct sctp_pcb *inp) 892*b0471b4bSMichael Tuexen { 893f8829a4aSRandall Stewart /* 894f8829a4aSRandall Stewart * A true implementation should use random selection process to get 895f8829a4aSRandall Stewart * the initial stream sequence number, using RFC1750 as a good 896f8829a4aSRandall Stewart * guideline 897f8829a4aSRandall Stewart */ 898139bc87fSRandall Stewart uint32_t x, *xp; 899f8829a4aSRandall Stewart uint8_t *p; 900851b7298SRandall Stewart int store_at, new_store; 901f8829a4aSRandall Stewart 902851b7298SRandall Stewart if (inp->initial_sequence_debug != 0) { 903f8829a4aSRandall Stewart uint32_t ret; 904f8829a4aSRandall Stewart 905851b7298SRandall Stewart ret = inp->initial_sequence_debug; 906851b7298SRandall Stewart inp->initial_sequence_debug++; 907f8829a4aSRandall Stewart return (ret); 908f8829a4aSRandall Stewart } 909851b7298SRandall Stewart retry: 910851b7298SRandall Stewart store_at = inp->store_at; 911851b7298SRandall Stewart new_store = store_at + sizeof(uint32_t); 912851b7298SRandall Stewart if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) { 913851b7298SRandall Stewart new_store = 0; 914f8829a4aSRandall Stewart } 915851b7298SRandall Stewart if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) { 916851b7298SRandall Stewart goto retry; 917851b7298SRandall Stewart } 918851b7298SRandall Stewart if (new_store == 0) { 919851b7298SRandall Stewart /* Refill the random store */ 920851b7298SRandall Stewart sctp_fill_random_store(inp); 921851b7298SRandall Stewart } 922851b7298SRandall Stewart p = &inp->random_store[store_at]; 923139bc87fSRandall Stewart xp = (uint32_t *)p; 924f8829a4aSRandall Stewart x = *xp; 925f8829a4aSRandall Stewart return (x); 926f8829a4aSRandall Stewart } 927f8829a4aSRandall Stewart 928f8829a4aSRandall Stewart uint32_t 929*b0471b4bSMichael Tuexen sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check) 930*b0471b4bSMichael Tuexen { 9317215cc1bSMichael Tuexen uint32_t x; 932f8829a4aSRandall Stewart struct timeval now; 933f8829a4aSRandall Stewart 9347215cc1bSMichael Tuexen if (check) { 9356e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 9367215cc1bSMichael Tuexen } 9377215cc1bSMichael Tuexen for (;;) { 938851b7298SRandall Stewart x = sctp_select_initial_TSN(&inp->sctp_ep); 939f8829a4aSRandall Stewart if (x == 0) { 940f8829a4aSRandall Stewart /* we never use 0 */ 941f8829a4aSRandall Stewart continue; 942f8829a4aSRandall Stewart } 9437215cc1bSMichael Tuexen if (!check || sctp_is_vtag_good(x, lport, rport, &now)) { 9447215cc1bSMichael Tuexen break; 945f8829a4aSRandall Stewart } 946f8829a4aSRandall Stewart } 947f8829a4aSRandall Stewart return (x); 948f8829a4aSRandall Stewart } 949f8829a4aSRandall Stewart 950e92c2a8dSMichael Tuexen int32_t 951*b0471b4bSMichael Tuexen sctp_map_assoc_state(int kernel_state) 952*b0471b4bSMichael Tuexen { 953e92c2a8dSMichael Tuexen int32_t user_state; 954e92c2a8dSMichael Tuexen 955e92c2a8dSMichael Tuexen if (kernel_state & SCTP_STATE_WAS_ABORTED) { 956e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 957e92c2a8dSMichael Tuexen } else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) { 958e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_PENDING; 959e92c2a8dSMichael Tuexen } else { 960e92c2a8dSMichael Tuexen switch (kernel_state & SCTP_STATE_MASK) { 961e92c2a8dSMichael Tuexen case SCTP_STATE_EMPTY: 962e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 963e92c2a8dSMichael Tuexen break; 964e92c2a8dSMichael Tuexen case SCTP_STATE_INUSE: 965e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 966e92c2a8dSMichael Tuexen break; 967e92c2a8dSMichael Tuexen case SCTP_STATE_COOKIE_WAIT: 968e92c2a8dSMichael Tuexen user_state = SCTP_COOKIE_WAIT; 969e92c2a8dSMichael Tuexen break; 970e92c2a8dSMichael Tuexen case SCTP_STATE_COOKIE_ECHOED: 971e92c2a8dSMichael Tuexen user_state = SCTP_COOKIE_ECHOED; 972e92c2a8dSMichael Tuexen break; 973e92c2a8dSMichael Tuexen case SCTP_STATE_OPEN: 974e92c2a8dSMichael Tuexen user_state = SCTP_ESTABLISHED; 975e92c2a8dSMichael Tuexen break; 976e92c2a8dSMichael Tuexen case SCTP_STATE_SHUTDOWN_SENT: 977e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_SENT; 978e92c2a8dSMichael Tuexen break; 979e92c2a8dSMichael Tuexen case SCTP_STATE_SHUTDOWN_RECEIVED: 980e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_RECEIVED; 981e92c2a8dSMichael Tuexen break; 982e92c2a8dSMichael Tuexen case SCTP_STATE_SHUTDOWN_ACK_SENT: 983e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_ACK_SENT; 984e92c2a8dSMichael Tuexen break; 985e92c2a8dSMichael Tuexen default: 986e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 987e92c2a8dSMichael Tuexen break; 988e92c2a8dSMichael Tuexen } 989e92c2a8dSMichael Tuexen } 990e92c2a8dSMichael Tuexen return (user_state); 991e92c2a8dSMichael Tuexen } 992e92c2a8dSMichael Tuexen 993f8829a4aSRandall Stewart int 994a1cb341bSMichael Tuexen sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 995c979034bSMichael Tuexen uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms) 996f8829a4aSRandall Stewart { 9970696e120SRandall Stewart struct sctp_association *asoc; 9980696e120SRandall Stewart 999f8829a4aSRandall Stewart /* 1000f8829a4aSRandall Stewart * Anything set to zero is taken care of by the allocation routine's 1001f8829a4aSRandall Stewart * bzero 1002f8829a4aSRandall Stewart */ 1003f8829a4aSRandall Stewart 1004f8829a4aSRandall Stewart /* 1005f8829a4aSRandall Stewart * Up front select what scoping to apply on addresses I tell my peer 1006f8829a4aSRandall Stewart * Not sure what to do with these right now, we will need to come up 1007f8829a4aSRandall Stewart * with a way to set them. We may need to pass them through from the 1008f8829a4aSRandall Stewart * caller in the sctp_aloc_assoc() function. 1009f8829a4aSRandall Stewart */ 1010f8829a4aSRandall Stewart int i; 1011f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 1012f0396ad1SMichael Tuexen int j; 1013f0396ad1SMichael Tuexen #endif 1014f0396ad1SMichael Tuexen 10150696e120SRandall Stewart asoc = &stcb->asoc; 1016f8829a4aSRandall Stewart /* init all variables to a known value. */ 1017c4739e2fSRandall Stewart SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE); 1018a1cb341bSMichael Tuexen asoc->max_burst = inp->sctp_ep.max_burst; 1019a1cb341bSMichael Tuexen asoc->fr_max_burst = inp->sctp_ep.fr_max_burst; 1020a1cb341bSMichael Tuexen asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 1021a1cb341bSMichael Tuexen asoc->cookie_life = inp->sctp_ep.def_cookie_life; 1022a1cb341bSMichael Tuexen asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off; 1023f342355aSMichael Tuexen asoc->ecn_supported = inp->ecn_supported; 1024dd973b0eSMichael Tuexen asoc->prsctp_supported = inp->prsctp_supported; 102544249214SRandall Stewart asoc->idata_supported = inp->idata_supported; 1026c79bec9cSMichael Tuexen asoc->auth_supported = inp->auth_supported; 1027c79bec9cSMichael Tuexen asoc->asconf_supported = inp->asconf_supported; 1028317e00efSMichael Tuexen asoc->reconfig_supported = inp->reconfig_supported; 1029caea9879SMichael Tuexen asoc->nrsack_supported = inp->nrsack_supported; 1030cb9b8e6fSMichael Tuexen asoc->pktdrop_supported = inp->pktdrop_supported; 103144249214SRandall Stewart asoc->idata_supported = inp->idata_supported; 1032ca85e948SMichael Tuexen asoc->sctp_cmt_pf = (uint8_t)0; 1033a1cb341bSMichael Tuexen asoc->sctp_frag_point = inp->sctp_frag_point; 1034a1cb341bSMichael Tuexen asoc->sctp_features = inp->sctp_features; 1035a1cb341bSMichael Tuexen asoc->default_dscp = inp->sctp_ep.default_dscp; 103659b6d5beSMichael Tuexen asoc->max_cwnd = inp->max_cwnd; 103742551e99SRandall Stewart #ifdef INET6 1038a1cb341bSMichael Tuexen if (inp->sctp_ep.default_flowlabel) { 1039a1cb341bSMichael Tuexen asoc->default_flowlabel = inp->sctp_ep.default_flowlabel; 104058bdb691SMichael Tuexen } else { 1041a1cb341bSMichael Tuexen if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) { 1042a1cb341bSMichael Tuexen asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep); 104358bdb691SMichael Tuexen asoc->default_flowlabel &= 0x000fffff; 104458bdb691SMichael Tuexen asoc->default_flowlabel |= 0x80000000; 104558bdb691SMichael Tuexen } else { 1046f8829a4aSRandall Stewart asoc->default_flowlabel = 0; 104758bdb691SMichael Tuexen } 104858bdb691SMichael Tuexen } 1049f8829a4aSRandall Stewart #endif 10509f22f500SRandall Stewart asoc->sb_send_resv = 0; 1051f8829a4aSRandall Stewart if (override_tag) { 1052f8829a4aSRandall Stewart asoc->my_vtag = override_tag; 1053f8829a4aSRandall Stewart } else { 1054a1cb341bSMichael Tuexen asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1); 1055f8829a4aSRandall Stewart } 1056de0e935bSRandall Stewart /* Get the nonce tags */ 1057a1cb341bSMichael Tuexen asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 1058a1cb341bSMichael Tuexen asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 105942551e99SRandall Stewart asoc->vrf_id = vrf_id; 1060de0e935bSRandall Stewart 106118e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 106218e198d3SRandall Stewart asoc->tsn_in_at = 0; 106318e198d3SRandall Stewart asoc->tsn_out_at = 0; 106418e198d3SRandall Stewart asoc->tsn_in_wrapped = 0; 106518e198d3SRandall Stewart asoc->tsn_out_wrapped = 0; 106618e198d3SRandall Stewart asoc->cumack_log_at = 0; 1067b201f536SRandall Stewart asoc->cumack_log_atsnt = 0; 106818e198d3SRandall Stewart #endif 106918e198d3SRandall Stewart #ifdef SCTP_FS_SPEC_LOG 107018e198d3SRandall Stewart asoc->fs_index = 0; 107118e198d3SRandall Stewart #endif 1072f8829a4aSRandall Stewart asoc->refcnt = 0; 1073f8829a4aSRandall Stewart asoc->assoc_up_sent = 0; 1074f8829a4aSRandall Stewart asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq = 1075a1cb341bSMichael Tuexen sctp_select_initial_TSN(&inp->sctp_ep); 1076c54a18d2SRandall Stewart asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; 1077f8829a4aSRandall Stewart /* we are optimisitic here */ 1078830d754dSRandall Stewart asoc->peer_supports_nat = 0; 1079f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 1080f8829a4aSRandall Stewart 1081f8829a4aSRandall Stewart /* for CMT */ 10828933fa13SRandall Stewart asoc->last_net_cmt_send_started = NULL; 1083f8829a4aSRandall Stewart 1084f8829a4aSRandall Stewart /* This will need to be adjusted */ 1085f8829a4aSRandall Stewart asoc->last_acked_seq = asoc->init_seq_number - 1; 1086f8829a4aSRandall Stewart asoc->advanced_peer_ack_point = asoc->last_acked_seq; 1087f8829a4aSRandall Stewart asoc->asconf_seq_in = asoc->last_acked_seq; 1088f8829a4aSRandall Stewart 1089f8829a4aSRandall Stewart /* here we are different, we hold the next one we expect */ 1090f8829a4aSRandall Stewart asoc->str_reset_seq_in = asoc->last_acked_seq + 1; 1091f8829a4aSRandall Stewart 1092a1cb341bSMichael Tuexen asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max; 1093a1cb341bSMichael Tuexen asoc->initial_rto = inp->sctp_ep.initial_rto; 1094f8829a4aSRandall Stewart 109528a6addeSMichael Tuexen asoc->default_mtu = inp->sctp_ep.default_mtu; 1096a1cb341bSMichael Tuexen asoc->max_init_times = inp->sctp_ep.max_init_times; 1097a1cb341bSMichael Tuexen asoc->max_send_times = inp->sctp_ep.max_send_times; 1098a1cb341bSMichael Tuexen asoc->def_net_failure = inp->sctp_ep.def_net_failure; 1099a1cb341bSMichael Tuexen asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold; 1100f8829a4aSRandall Stewart asoc->free_chunk_cnt = 0; 1101f8829a4aSRandall Stewart 1102f8829a4aSRandall Stewart asoc->iam_blocking = 0; 1103a1cb341bSMichael Tuexen asoc->context = inp->sctp_context; 1104a1cb341bSMichael Tuexen asoc->local_strreset_support = inp->local_strreset_support; 1105a1cb341bSMichael Tuexen asoc->def_send = inp->def_send; 1106a1cb341bSMichael Tuexen asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 1107a1cb341bSMichael Tuexen asoc->sack_freq = inp->sctp_ep.sctp_sack_freq; 1108f8829a4aSRandall Stewart asoc->pr_sctp_cnt = 0; 1109f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 1110f8829a4aSRandall Stewart 1111a1cb341bSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1112a1cb341bSMichael Tuexen asoc->scope.ipv6_addr_legal = 1; 1113a1cb341bSMichael Tuexen if (SCTP_IPV6_V6ONLY(inp) == 0) { 1114a1cb341bSMichael Tuexen asoc->scope.ipv4_addr_legal = 1; 1115f8829a4aSRandall Stewart } else { 1116a1cb341bSMichael Tuexen asoc->scope.ipv4_addr_legal = 0; 1117f8829a4aSRandall Stewart } 1118f8829a4aSRandall Stewart } else { 1119a1cb341bSMichael Tuexen asoc->scope.ipv6_addr_legal = 0; 1120a1cb341bSMichael Tuexen asoc->scope.ipv4_addr_legal = 1; 1121f8829a4aSRandall Stewart } 1122f8829a4aSRandall Stewart 1123a1cb341bSMichael Tuexen asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND); 1124a1cb341bSMichael Tuexen asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket); 1125f8829a4aSRandall Stewart 1126a1cb341bSMichael Tuexen asoc->smallest_mtu = inp->sctp_frag_point; 1127a1cb341bSMichael Tuexen asoc->minrto = inp->sctp_ep.sctp_minrto; 1128a1cb341bSMichael Tuexen asoc->maxrto = inp->sctp_ep.sctp_maxrto; 1129f8829a4aSRandall Stewart 1130f8829a4aSRandall Stewart asoc->stream_locked_on = 0; 1131f8829a4aSRandall Stewart asoc->ecn_echo_cnt_onq = 0; 1132f8829a4aSRandall Stewart asoc->stream_locked = 0; 1133f8829a4aSRandall Stewart 113442551e99SRandall Stewart asoc->send_sack = 1; 113542551e99SRandall Stewart 113642551e99SRandall Stewart LIST_INIT(&asoc->sctp_restricted_addrs); 113742551e99SRandall Stewart 1138f8829a4aSRandall Stewart TAILQ_INIT(&asoc->nets); 1139f8829a4aSRandall Stewart TAILQ_INIT(&asoc->pending_reply_queue); 11402afb3e84SRandall Stewart TAILQ_INIT(&asoc->asconf_ack_sent); 1141f8829a4aSRandall Stewart /* Setup to fill the hb random cache at first HB */ 1142f8829a4aSRandall Stewart asoc->hb_random_idx = 4; 1143f8829a4aSRandall Stewart 1144a1cb341bSMichael Tuexen asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time; 1145f8829a4aSRandall Stewart 1146a1cb341bSMichael Tuexen stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module; 1147a1cb341bSMichael Tuexen stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module]; 1148b54d3a6cSRandall Stewart 1149a1cb341bSMichael Tuexen stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module; 1150a1cb341bSMichael Tuexen stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module]; 1151f7a77f6fSMichael Tuexen 1152b54d3a6cSRandall Stewart /* 1153f8829a4aSRandall Stewart * Now the stream parameters, here we allocate space for all streams 1154f8829a4aSRandall Stewart * that we request by default. 1155f8829a4aSRandall Stewart */ 1156ea44232bSRandall Stewart asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams = 1157c979034bSMichael Tuexen o_strms; 1158f8829a4aSRandall Stewart SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *, 1159f8829a4aSRandall Stewart asoc->streamoutcnt * sizeof(struct sctp_stream_out), 1160207304d4SRandall Stewart SCTP_M_STRMO); 1161f8829a4aSRandall Stewart if (asoc->strmout == NULL) { 1162f8829a4aSRandall Stewart /* big trouble no memory */ 1163c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1164f8829a4aSRandall Stewart return (ENOMEM); 1165f8829a4aSRandall Stewart } 1166f8829a4aSRandall Stewart for (i = 0; i < asoc->streamoutcnt; i++) { 1167f8829a4aSRandall Stewart /* 1168f8829a4aSRandall Stewart * inbound side must be set to 0xffff, also NOTE when we get 1169f8829a4aSRandall Stewart * the INIT-ACK back (for INIT sender) we MUST reduce the 1170f8829a4aSRandall Stewart * count (streamoutcnt) but first check if we sent to any of 1171f8829a4aSRandall Stewart * the upper streams that were dropped (if some were). Those 1172f8829a4aSRandall Stewart * that were dropped must be notified to the upper layer as 1173f8829a4aSRandall Stewart * failed to send. 1174f8829a4aSRandall Stewart */ 117563d5b568SMichael Tuexen asoc->strmout[i].next_mid_ordered = 0; 117663d5b568SMichael Tuexen asoc->strmout[i].next_mid_unordered = 0; 1177f8829a4aSRandall Stewart TAILQ_INIT(&asoc->strmout[i].outqueue); 1178325c8c46SMichael Tuexen asoc->strmout[i].chunks_on_queues = 0; 1179f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 1180f0396ad1SMichael Tuexen for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { 1181f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_sent[j] = 0; 1182f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_unsent[j] = 0; 1183f0396ad1SMichael Tuexen } 1184f0396ad1SMichael Tuexen #else 1185f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_sent[0] = 0; 1186f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_unsent[0] = 0; 1187f0396ad1SMichael Tuexen #endif 118849656eefSMichael Tuexen asoc->strmout[i].sid = i; 1189f8829a4aSRandall Stewart asoc->strmout[i].last_msg_incomplete = 0; 11907cca1775SRandall Stewart asoc->strmout[i].state = SCTP_STREAM_OPENING; 1191d1ea5fa9SMichael Tuexen asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL); 1192f8829a4aSRandall Stewart } 1193f7a77f6fSMichael Tuexen asoc->ss_functions.sctp_ss_init(stcb, asoc, 0); 1194f7a77f6fSMichael Tuexen 1195f8829a4aSRandall Stewart /* Now the mapping array */ 1196f8829a4aSRandall Stewart asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; 1197f8829a4aSRandall Stewart SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size, 1198207304d4SRandall Stewart SCTP_M_MAP); 1199f8829a4aSRandall Stewart if (asoc->mapping_array == NULL) { 1200207304d4SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1201c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1202f8829a4aSRandall Stewart return (ENOMEM); 1203f8829a4aSRandall Stewart } 1204f8829a4aSRandall Stewart memset(asoc->mapping_array, 0, asoc->mapping_array_size); 1205b5c16493SMichael Tuexen SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size, 1206830d754dSRandall Stewart SCTP_M_MAP); 1207bf1be571SRandall Stewart if (asoc->nr_mapping_array == NULL) { 1208bf1be571SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1209bf1be571SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1210bf1be571SRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1211bf1be571SRandall Stewart return (ENOMEM); 1212bf1be571SRandall Stewart } 1213b5c16493SMichael Tuexen memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); 1214830d754dSRandall Stewart 1215f8829a4aSRandall Stewart /* Now the init of the other outqueues */ 1216f8829a4aSRandall Stewart TAILQ_INIT(&asoc->free_chunks); 1217f8829a4aSRandall Stewart TAILQ_INIT(&asoc->control_send_queue); 1218c54a18d2SRandall Stewart TAILQ_INIT(&asoc->asconf_send_queue); 1219f8829a4aSRandall Stewart TAILQ_INIT(&asoc->send_queue); 1220f8829a4aSRandall Stewart TAILQ_INIT(&asoc->sent_queue); 1221f8829a4aSRandall Stewart TAILQ_INIT(&asoc->resetHead); 1222a1cb341bSMichael Tuexen asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome; 1223f8829a4aSRandall Stewart TAILQ_INIT(&asoc->asconf_queue); 1224f8829a4aSRandall Stewart /* authentication fields */ 1225f8829a4aSRandall Stewart asoc->authinfo.random = NULL; 1226830d754dSRandall Stewart asoc->authinfo.active_keyid = 0; 1227f8829a4aSRandall Stewart asoc->authinfo.assoc_key = NULL; 1228f8829a4aSRandall Stewart asoc->authinfo.assoc_keyid = 0; 1229f8829a4aSRandall Stewart asoc->authinfo.recv_key = NULL; 1230f8829a4aSRandall Stewart asoc->authinfo.recv_keyid = 0; 1231f8829a4aSRandall Stewart LIST_INIT(&asoc->shared_keys); 1232f42a358aSRandall Stewart asoc->marked_retrans = 0; 1233a1cb341bSMichael Tuexen asoc->port = inp->sctp_ep.port; 1234f42a358aSRandall Stewart asoc->timoinit = 0; 1235f42a358aSRandall Stewart asoc->timodata = 0; 1236f42a358aSRandall Stewart asoc->timosack = 0; 1237f42a358aSRandall Stewart asoc->timoshutdown = 0; 1238f42a358aSRandall Stewart asoc->timoheartbeat = 0; 1239f42a358aSRandall Stewart asoc->timocookie = 0; 1240f42a358aSRandall Stewart asoc->timoshutdownack = 0; 12416e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&asoc->start_time); 12426e55db54SRandall Stewart asoc->discontinuity_time = asoc->start_time; 1243f0396ad1SMichael Tuexen for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) { 1244f0396ad1SMichael Tuexen asoc->abandoned_unsent[i] = 0; 1245f0396ad1SMichael Tuexen asoc->abandoned_sent[i] = 0; 1246f0396ad1SMichael Tuexen } 1247eacc51c5SRandall Stewart /* 1248eacc51c5SRandall Stewart * sa_ignore MEMLEAK {memory is put in the assoc mapping array and 124977acdc25SRandall Stewart * freed later when the association is freed. 1250eacc51c5SRandall Stewart */ 1251f8829a4aSRandall Stewart return (0); 1252f8829a4aSRandall Stewart } 1253f8829a4aSRandall Stewart 12540e13104dSRandall Stewart void 12550e13104dSRandall Stewart sctp_print_mapping_array(struct sctp_association *asoc) 12560e13104dSRandall Stewart { 1257aed5947cSMichael Tuexen unsigned int i, limit; 12580e13104dSRandall Stewart 1259cd3fd531SMichael Tuexen SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n", 12600e13104dSRandall Stewart asoc->mapping_array_size, 12610e13104dSRandall Stewart asoc->mapping_array_base_tsn, 12620e13104dSRandall Stewart asoc->cumulative_tsn, 1263aed5947cSMichael Tuexen asoc->highest_tsn_inside_map, 1264aed5947cSMichael Tuexen asoc->highest_tsn_inside_nr_map); 1265aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 126660990c0cSMichael Tuexen if (asoc->mapping_array[limit - 1] != 0) { 126777acdc25SRandall Stewart break; 126877acdc25SRandall Stewart } 126977acdc25SRandall Stewart } 1270cd3fd531SMichael Tuexen SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 127177acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1272cd3fd531SMichael Tuexen SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 127377acdc25SRandall Stewart } 1274aed5947cSMichael Tuexen if (limit % 16) 1275cd3fd531SMichael Tuexen SCTP_PRINTF("\n"); 1276aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 1277aed5947cSMichael Tuexen if (asoc->nr_mapping_array[limit - 1]) { 127877acdc25SRandall Stewart break; 127977acdc25SRandall Stewart } 128077acdc25SRandall Stewart } 1281cd3fd531SMichael Tuexen SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 128277acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1283cd3fd531SMichael Tuexen SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 12840e13104dSRandall Stewart } 1285aed5947cSMichael Tuexen if (limit % 16) 1286cd3fd531SMichael Tuexen SCTP_PRINTF("\n"); 12870e13104dSRandall Stewart } 12880e13104dSRandall Stewart 1289f8829a4aSRandall Stewart int 12900696e120SRandall Stewart sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed) 1291f8829a4aSRandall Stewart { 1292f8829a4aSRandall Stewart /* mapping array needs to grow */ 1293b5c16493SMichael Tuexen uint8_t *new_array1, *new_array2; 12940696e120SRandall Stewart uint32_t new_size; 1295f8829a4aSRandall Stewart 12960696e120SRandall Stewart new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR); 1297b5c16493SMichael Tuexen SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP); 1298b5c16493SMichael Tuexen SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP); 1299b5c16493SMichael Tuexen if ((new_array1 == NULL) || (new_array2 == NULL)) { 1300f8829a4aSRandall Stewart /* can't get more, forget it */ 1301b5c16493SMichael Tuexen SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size); 1302b5c16493SMichael Tuexen if (new_array1) { 1303b5c16493SMichael Tuexen SCTP_FREE(new_array1, SCTP_M_MAP); 1304b5c16493SMichael Tuexen } 1305b5c16493SMichael Tuexen if (new_array2) { 1306b5c16493SMichael Tuexen SCTP_FREE(new_array2, SCTP_M_MAP); 1307b5c16493SMichael Tuexen } 1308f8829a4aSRandall Stewart return (-1); 1309f8829a4aSRandall Stewart } 1310b5c16493SMichael Tuexen memset(new_array1, 0, new_size); 1311b5c16493SMichael Tuexen memset(new_array2, 0, new_size); 1312b5c16493SMichael Tuexen memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size); 1313b5c16493SMichael Tuexen memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size); 1314207304d4SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1315830d754dSRandall Stewart SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); 1316b5c16493SMichael Tuexen asoc->mapping_array = new_array1; 1317b5c16493SMichael Tuexen asoc->nr_mapping_array = new_array2; 1318b5c16493SMichael Tuexen asoc->mapping_array_size = new_size; 1319830d754dSRandall Stewart return (0); 1320830d754dSRandall Stewart } 1321830d754dSRandall Stewart 13228933fa13SRandall Stewart 132342551e99SRandall Stewart static void 132442551e99SRandall Stewart sctp_iterator_work(struct sctp_iterator *it) 132542551e99SRandall Stewart { 132642551e99SRandall Stewart int iteration_count = 0; 132742551e99SRandall Stewart int inp_skip = 0; 1328ec4c19fcSRandall Stewart int first_in = 1; 1329ec4c19fcSRandall Stewart struct sctp_inpcb *tinp; 133042551e99SRandall Stewart 1331ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 133242551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1333dcb436c9SMichael Tuexen sctp_it_ctl.cur_it = it; 1334ad81507eSRandall Stewart if (it->inp) { 1335ec4c19fcSRandall Stewart SCTP_INP_RLOCK(it->inp); 133642551e99SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1337ad81507eSRandall Stewart } 133842551e99SRandall Stewart if (it->inp == NULL) { 133942551e99SRandall Stewart /* iterator is complete */ 134042551e99SRandall Stewart done_with_iterator: 1341dcb436c9SMichael Tuexen sctp_it_ctl.cur_it = NULL; 134242551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1343ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 134442551e99SRandall Stewart if (it->function_atend != NULL) { 134542551e99SRandall Stewart (*it->function_atend) (it->pointer, it->val); 134642551e99SRandall Stewart } 1347207304d4SRandall Stewart SCTP_FREE(it, SCTP_M_ITER); 134842551e99SRandall Stewart return; 134942551e99SRandall Stewart } 135042551e99SRandall Stewart select_a_new_ep: 1351ec4c19fcSRandall Stewart if (first_in) { 1352ec4c19fcSRandall Stewart first_in = 0; 1353ec4c19fcSRandall Stewart } else { 1354f7517433SRandall Stewart SCTP_INP_RLOCK(it->inp); 1355ec4c19fcSRandall Stewart } 135642551e99SRandall Stewart while (((it->pcb_flags) && 135742551e99SRandall Stewart ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || 135842551e99SRandall Stewart ((it->pcb_features) && 135942551e99SRandall Stewart ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { 136042551e99SRandall Stewart /* endpoint flags or features don't match, so keep looking */ 136142551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1362f7517433SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 136342551e99SRandall Stewart goto done_with_iterator; 136442551e99SRandall Stewart } 1365ec4c19fcSRandall Stewart tinp = it->inp; 136642551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1367ec4c19fcSRandall Stewart SCTP_INP_RUNLOCK(tinp); 136842551e99SRandall Stewart if (it->inp == NULL) { 136942551e99SRandall Stewart goto done_with_iterator; 137042551e99SRandall Stewart } 137142551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1372f7517433SRandall Stewart } 137342551e99SRandall Stewart /* now go through each assoc which is in the desired state */ 137442551e99SRandall Stewart if (it->done_current_ep == 0) { 137542551e99SRandall Stewart if (it->function_inp != NULL) 137642551e99SRandall Stewart inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val); 137742551e99SRandall Stewart it->done_current_ep = 1; 137842551e99SRandall Stewart } 137942551e99SRandall Stewart if (it->stcb == NULL) { 138042551e99SRandall Stewart /* run the per instance function */ 138142551e99SRandall Stewart it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); 138242551e99SRandall Stewart } 138342551e99SRandall Stewart if ((inp_skip) || it->stcb == NULL) { 138442551e99SRandall Stewart if (it->function_inp_end != NULL) { 138542551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 138642551e99SRandall Stewart it->pointer, 138742551e99SRandall Stewart it->val); 138842551e99SRandall Stewart } 138942551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 139042551e99SRandall Stewart goto no_stcb; 139142551e99SRandall Stewart } 139242551e99SRandall Stewart while (it->stcb) { 139342551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 139442551e99SRandall Stewart if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { 139542551e99SRandall Stewart /* not in the right state... keep looking */ 139642551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 139742551e99SRandall Stewart goto next_assoc; 139842551e99SRandall Stewart } 139942551e99SRandall Stewart /* see if we have limited out the iterator loop */ 140042551e99SRandall Stewart iteration_count++; 140142551e99SRandall Stewart if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { 140242551e99SRandall Stewart /* Pause to let others grab the lock */ 140342551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, 1); 140442551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1405c4739e2fSRandall Stewart SCTP_INP_INCR_REF(it->inp); 140642551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 140742551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1408ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 1409ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 141042551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1411f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags) { 1412f7517433SRandall Stewart /* We won't be staying here */ 1413f7517433SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1414f7517433SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 1415f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1416f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_IT) { 1417f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT; 1418f7517433SRandall Stewart goto done_with_iterator; 1419f7517433SRandall Stewart } 1420f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1421f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_INP) { 1422f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP; 1423f7517433SRandall Stewart goto no_stcb; 1424f7517433SRandall Stewart } 1425f7517433SRandall Stewart /* If we reach here huh? */ 1426cd3fd531SMichael Tuexen SCTP_PRINTF("Unknown it ctl flag %x\n", 1427f7517433SRandall Stewart sctp_it_ctl.iterator_flags); 1428f7517433SRandall Stewart sctp_it_ctl.iterator_flags = 0; 1429f7517433SRandall Stewart } 143042551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1431c4739e2fSRandall Stewart SCTP_INP_DECR_REF(it->inp); 143242551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 143342551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 143442551e99SRandall Stewart iteration_count = 0; 143542551e99SRandall Stewart } 143642551e99SRandall Stewart /* run function on this one */ 143742551e99SRandall Stewart (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val); 143842551e99SRandall Stewart 143942551e99SRandall Stewart /* 144042551e99SRandall Stewart * we lie here, it really needs to have its own type but 144142551e99SRandall Stewart * first I must verify that this won't effect things :-0 144242551e99SRandall Stewart */ 144342551e99SRandall Stewart if (it->no_chunk_output == 0) 1444ceaad40aSRandall Stewart sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 144542551e99SRandall Stewart 144642551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 144742551e99SRandall Stewart next_assoc: 144842551e99SRandall Stewart it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); 144942551e99SRandall Stewart if (it->stcb == NULL) { 145042551e99SRandall Stewart /* Run last function */ 145142551e99SRandall Stewart if (it->function_inp_end != NULL) { 145242551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 145342551e99SRandall Stewart it->pointer, 145442551e99SRandall Stewart it->val); 145542551e99SRandall Stewart } 145642551e99SRandall Stewart } 145742551e99SRandall Stewart } 145842551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 145942551e99SRandall Stewart no_stcb: 146042551e99SRandall Stewart /* done with all assocs on this endpoint, move on to next endpoint */ 146142551e99SRandall Stewart it->done_current_ep = 0; 146242551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 146342551e99SRandall Stewart it->inp = NULL; 146442551e99SRandall Stewart } else { 146542551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 146642551e99SRandall Stewart } 146742551e99SRandall Stewart if (it->inp == NULL) { 146842551e99SRandall Stewart goto done_with_iterator; 146942551e99SRandall Stewart } 147042551e99SRandall Stewart goto select_a_new_ep; 147142551e99SRandall Stewart } 147242551e99SRandall Stewart 147342551e99SRandall Stewart void 147442551e99SRandall Stewart sctp_iterator_worker(void) 147542551e99SRandall Stewart { 14764a9ef3f8SMichael Tuexen struct sctp_iterator *it, *nit; 147742551e99SRandall Stewart 147842551e99SRandall Stewart /* This function is called with the WQ lock in place */ 147942551e99SRandall Stewart 1480f7517433SRandall Stewart sctp_it_ctl.iterator_running = 1; 14814a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { 148242551e99SRandall Stewart /* now lets work on this one */ 1483f7517433SRandall Stewart TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); 148442551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_UNLOCK(); 1485f7517433SRandall Stewart CURVNET_SET(it->vn); 148642551e99SRandall Stewart sctp_iterator_work(it); 1487f7517433SRandall Stewart CURVNET_RESTORE(); 148842551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_LOCK(); 14893c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 149042551e99SRandall Stewart } 1491f7517433SRandall Stewart sctp_it_ctl.iterator_running = 0; 149242551e99SRandall Stewart return; 149342551e99SRandall Stewart } 149442551e99SRandall Stewart 1495f8829a4aSRandall Stewart 1496f8829a4aSRandall Stewart static void 1497f8829a4aSRandall Stewart sctp_handle_addr_wq(void) 1498f8829a4aSRandall Stewart { 1499f8829a4aSRandall Stewart /* deal with the ADDR wq from the rtsock calls */ 15004a9ef3f8SMichael Tuexen struct sctp_laddr *wi, *nwi; 150142551e99SRandall Stewart struct sctp_asconf_iterator *asc; 1502f8829a4aSRandall Stewart 150342551e99SRandall Stewart SCTP_MALLOC(asc, struct sctp_asconf_iterator *, 1504207304d4SRandall Stewart sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT); 150542551e99SRandall Stewart if (asc == NULL) { 150642551e99SRandall Stewart /* Try later, no memory */ 1507f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 1508f8829a4aSRandall Stewart (struct sctp_inpcb *)NULL, 1509f8829a4aSRandall Stewart (struct sctp_tcb *)NULL, 1510f8829a4aSRandall Stewart (struct sctp_nets *)NULL); 151142551e99SRandall Stewart return; 1512f8829a4aSRandall Stewart } 151342551e99SRandall Stewart LIST_INIT(&asc->list_of_work); 151442551e99SRandall Stewart asc->cnt = 0; 1515f7517433SRandall Stewart 15164a9ef3f8SMichael Tuexen LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { 151742551e99SRandall Stewart LIST_REMOVE(wi, sctp_nxt_addr); 151842551e99SRandall Stewart LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); 151942551e99SRandall Stewart asc->cnt++; 1520f8829a4aSRandall Stewart } 1521f7517433SRandall Stewart 152242551e99SRandall Stewart if (asc->cnt == 0) { 1523207304d4SRandall Stewart SCTP_FREE(asc, SCTP_M_ASC_IT); 152442551e99SRandall Stewart } else { 15252b1c7de4SMichael Tuexen int ret; 15262b1c7de4SMichael Tuexen 15272b1c7de4SMichael Tuexen ret = sctp_initiate_iterator(sctp_asconf_iterator_ep, 15281b649582SRandall Stewart sctp_asconf_iterator_stcb, 152942551e99SRandall Stewart NULL, /* No ep end for boundall */ 153042551e99SRandall Stewart SCTP_PCB_FLAGS_BOUNDALL, 153142551e99SRandall Stewart SCTP_PCB_ANY_FEATURES, 15321b649582SRandall Stewart SCTP_ASOC_ANY_STATE, 15331b649582SRandall Stewart (void *)asc, 0, 15341b649582SRandall Stewart sctp_asconf_iterator_end, NULL, 0); 15352b1c7de4SMichael Tuexen if (ret) { 15362b1c7de4SMichael Tuexen SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n"); 1537b7b84c0eSMichael Tuexen /* 1538b7b84c0eSMichael Tuexen * Freeing if we are stopping or put back on the 1539b7b84c0eSMichael Tuexen * addr_wq. 1540b7b84c0eSMichael Tuexen */ 15412b1c7de4SMichael Tuexen if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { 15422b1c7de4SMichael Tuexen sctp_asconf_iterator_end(asc, 0); 15432b1c7de4SMichael Tuexen } else { 15442b1c7de4SMichael Tuexen LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) { 15452b1c7de4SMichael Tuexen LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 15462b1c7de4SMichael Tuexen } 15472b1c7de4SMichael Tuexen SCTP_FREE(asc, SCTP_M_ASC_IT); 15482b1c7de4SMichael Tuexen } 15492b1c7de4SMichael Tuexen } 155042551e99SRandall Stewart } 1551f8829a4aSRandall Stewart } 1552f8829a4aSRandall Stewart 1553f8829a4aSRandall Stewart void 1554f8829a4aSRandall Stewart sctp_timeout_handler(void *t) 1555f8829a4aSRandall Stewart { 1556f8829a4aSRandall Stewart struct sctp_inpcb *inp; 1557f8829a4aSRandall Stewart struct sctp_tcb *stcb; 1558f8829a4aSRandall Stewart struct sctp_nets *net; 1559f8829a4aSRandall Stewart struct sctp_timer *tmr; 1560267dbe63SMichael Tuexen struct mbuf *op_err; 1561ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1562ceaad40aSRandall Stewart struct socket *so; 1563ceaad40aSRandall Stewart #endif 1564548f47a8SMichael Tuexen int did_output; 1565fa89f692SMichael Tuexen int type; 1566f8829a4aSRandall Stewart 1567f8829a4aSRandall Stewart tmr = (struct sctp_timer *)t; 1568f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)tmr->ep; 1569f8829a4aSRandall Stewart stcb = (struct sctp_tcb *)tmr->tcb; 1570f8829a4aSRandall Stewart net = (struct sctp_nets *)tmr->net; 15718518270eSMichael Tuexen CURVNET_SET((struct vnet *)tmr->vnet); 1572f8829a4aSRandall Stewart did_output = 1; 1573f8829a4aSRandall Stewart 1574f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1575f8829a4aSRandall Stewart sctp_audit_log(0xF0, (uint8_t)tmr->type); 1576f8829a4aSRandall Stewart sctp_auditing(3, inp, stcb, net); 1577f8829a4aSRandall Stewart #endif 1578f8829a4aSRandall Stewart 1579f8829a4aSRandall Stewart /* sanity checks... */ 1580f8829a4aSRandall Stewart if (tmr->self != (void *)tmr) { 1581f8829a4aSRandall Stewart /* 1582ad81507eSRandall Stewart * SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n", 1583dd294dceSMichael Tuexen * (void *)tmr); 1584f8829a4aSRandall Stewart */ 15858518270eSMichael Tuexen CURVNET_RESTORE(); 1586f8829a4aSRandall Stewart return; 1587f8829a4aSRandall Stewart } 1588a5d547adSRandall Stewart tmr->stopped_from = 0xa001; 1589f8829a4aSRandall Stewart if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) { 1590f8829a4aSRandall Stewart /* 1591ad81507eSRandall Stewart * SCTP_PRINTF("SCTP timer fired with invalid type: 0x%x\n", 1592f8829a4aSRandall Stewart * tmr->type); 1593f8829a4aSRandall Stewart */ 15948518270eSMichael Tuexen CURVNET_RESTORE(); 1595f8829a4aSRandall Stewart return; 1596f8829a4aSRandall Stewart } 1597a5d547adSRandall Stewart tmr->stopped_from = 0xa002; 1598f8829a4aSRandall Stewart if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) { 15998518270eSMichael Tuexen CURVNET_RESTORE(); 1600f8829a4aSRandall Stewart return; 1601f8829a4aSRandall Stewart } 1602f8829a4aSRandall Stewart /* if this is an iterator timeout, get the struct and clear inp */ 1603a5d547adSRandall Stewart tmr->stopped_from = 0xa003; 1604f8829a4aSRandall Stewart if (inp) { 1605f8829a4aSRandall Stewart SCTP_INP_INCR_REF(inp); 1606aa1808b7SMichael Tuexen if ((inp->sctp_socket == NULL) && 1607f8829a4aSRandall Stewart ((tmr->type != SCTP_TIMER_TYPE_INPKILL) && 1608810ec536SMichael Tuexen (tmr->type != SCTP_TIMER_TYPE_INIT) && 1609a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SEND) && 1610a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_RECV) && 1611a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) && 1612f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) && 1613f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) && 1614f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) && 16152c62ba73SMichael Tuexen (tmr->type != SCTP_TIMER_TYPE_ASOCKILL))) { 1616f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 16178518270eSMichael Tuexen CURVNET_RESTORE(); 1618f8829a4aSRandall Stewart return; 1619f8829a4aSRandall Stewart } 1620f8829a4aSRandall Stewart } 1621a5d547adSRandall Stewart tmr->stopped_from = 0xa004; 1622f8829a4aSRandall Stewart if (stcb) { 1623c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1624f8829a4aSRandall Stewart if (stcb->asoc.state == 0) { 1625c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1626f8829a4aSRandall Stewart if (inp) { 1627f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1628f8829a4aSRandall Stewart } 16298518270eSMichael Tuexen CURVNET_RESTORE(); 1630f8829a4aSRandall Stewart return; 1631f8829a4aSRandall Stewart } 1632f8829a4aSRandall Stewart } 1633fa89f692SMichael Tuexen type = tmr->type; 1634a5d547adSRandall Stewart tmr->stopped_from = 0xa005; 1635fa89f692SMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", type); 1636139bc87fSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 1637f8829a4aSRandall Stewart if (inp) { 1638f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1639f8829a4aSRandall Stewart } 1640207304d4SRandall Stewart if (stcb) { 1641207304d4SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1642207304d4SRandall Stewart } 16438518270eSMichael Tuexen CURVNET_RESTORE(); 1644f8829a4aSRandall Stewart return; 1645f8829a4aSRandall Stewart } 1646a5d547adSRandall Stewart tmr->stopped_from = 0xa006; 1647a5d547adSRandall Stewart 1648f8829a4aSRandall Stewart if (stcb) { 1649f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 165050cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1651fa89f692SMichael Tuexen if ((type != SCTP_TIMER_TYPE_ASOCKILL) && 1652b54d3a6cSRandall Stewart ((stcb->asoc.state == 0) || 1653b54d3a6cSRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { 1654b54d3a6cSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1655b54d3a6cSRandall Stewart if (inp) { 1656b54d3a6cSRandall Stewart SCTP_INP_DECR_REF(inp); 1657b54d3a6cSRandall Stewart } 16588518270eSMichael Tuexen CURVNET_RESTORE(); 1659b54d3a6cSRandall Stewart return; 1660b54d3a6cSRandall Stewart } 16612c62ba73SMichael Tuexen } else if (inp != NULL) { 16622c62ba73SMichael Tuexen if (type != SCTP_TIMER_TYPE_INPKILL) { 16632c62ba73SMichael Tuexen SCTP_INP_WLOCK(inp); 16642c62ba73SMichael Tuexen } 16652c62ba73SMichael Tuexen } else { 16662c62ba73SMichael Tuexen SCTP_WQ_ADDR_LOCK(); 1667f8829a4aSRandall Stewart } 1668cd0a4ff6SPedro F. Giffuni /* record in stopped what t-o occurred */ 1669fa89f692SMichael Tuexen tmr->stopped_from = type; 167044b7479bSRandall Stewart 1671f8829a4aSRandall Stewart /* mark as being serviced now */ 167244b7479bSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 167344b7479bSRandall Stewart /* 167444b7479bSRandall Stewart * Callout has been rescheduled. 167544b7479bSRandall Stewart */ 167644b7479bSRandall Stewart goto get_out; 167744b7479bSRandall Stewart } 167844b7479bSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 167944b7479bSRandall Stewart /* 168044b7479bSRandall Stewart * Not active, so no action. 168144b7479bSRandall Stewart */ 168244b7479bSRandall Stewart goto get_out; 168344b7479bSRandall Stewart } 1684139bc87fSRandall Stewart SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); 1685f8829a4aSRandall Stewart 1686f8829a4aSRandall Stewart /* call the handler for the appropriate timer type */ 1687fa89f692SMichael Tuexen switch (type) { 1688f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 1689f8829a4aSRandall Stewart sctp_handle_addr_wq(); 1690f8829a4aSRandall Stewart break; 1691f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 1692ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1693ad81507eSRandall Stewart break; 1694ad81507eSRandall Stewart } 1695f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timodata); 1696f42a358aSRandall Stewart stcb->asoc.timodata++; 1697f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 1698f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 1699f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 1700f8829a4aSRandall Stewart } 1701b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 170260990c0cSMichael Tuexen if (sctp_t3rxt_timer(inp, stcb, net)) { 1703f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1704f8829a4aSRandall Stewart 1705f8829a4aSRandall Stewart goto out_decr; 1706f8829a4aSRandall Stewart } 1707b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1708f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1709f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1710f8829a4aSRandall Stewart #endif 1711ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1712f8829a4aSRandall Stewart if ((stcb->asoc.num_send_timers_up == 0) && 17134a9ef3f8SMichael Tuexen (stcb->asoc.sent_queue_cnt > 0)) { 1714f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 1715f8829a4aSRandall Stewart 1716f8829a4aSRandall Stewart /* 1717f8829a4aSRandall Stewart * safeguard. If there on some on the sent queue 1718f8829a4aSRandall Stewart * somewhere but no timers running something is 1719f8829a4aSRandall Stewart * wrong... so we start a timer on the first chunk 1720f8829a4aSRandall Stewart * on the send queue on whatever net it is sent to. 1721f8829a4aSRandall Stewart */ 1722f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 1723f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, 1724f8829a4aSRandall Stewart chk->whoTo); 1725f8829a4aSRandall Stewart } 1726f8829a4aSRandall Stewart break; 1727f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 1728ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1729ad81507eSRandall Stewart break; 1730ad81507eSRandall Stewart } 1731f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinit); 1732f42a358aSRandall Stewart stcb->asoc.timoinit++; 1733f8829a4aSRandall Stewart if (sctp_t1init_timer(inp, stcb, net)) { 1734f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1735f8829a4aSRandall Stewart goto out_decr; 1736f8829a4aSRandall Stewart } 1737f8829a4aSRandall Stewart /* We do output but not here */ 1738f8829a4aSRandall Stewart did_output = 0; 1739f8829a4aSRandall Stewart break; 1740f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 1741ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1742ad81507eSRandall Stewart break; 1743ca85e948SMichael Tuexen } 1744f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosack); 1745f42a358aSRandall Stewart stcb->asoc.timosack++; 1746689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); 1747f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1748f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1749f8829a4aSRandall Stewart #endif 1750ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED); 1751f8829a4aSRandall Stewart break; 1752f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 1753ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1754ad81507eSRandall Stewart break; 1755ad81507eSRandall Stewart } 1756f8829a4aSRandall Stewart if (sctp_shutdown_timer(inp, stcb, net)) { 1757f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1758f8829a4aSRandall Stewart goto out_decr; 1759f8829a4aSRandall Stewart } 1760f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdown); 1761f42a358aSRandall Stewart stcb->asoc.timoshutdown++; 1762f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1763f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1764f8829a4aSRandall Stewart #endif 1765ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); 1766f8829a4aSRandall Stewart break; 1767f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 1768ca85e948SMichael Tuexen if ((stcb == NULL) || (inp == NULL) || (net == NULL)) { 1769ad81507eSRandall Stewart break; 1770ad81507eSRandall Stewart } 1771f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoheartbeat); 1772f42a358aSRandall Stewart stcb->asoc.timoheartbeat++; 1773ca85e948SMichael Tuexen if (sctp_heartbeat_timer(inp, stcb, net)) { 1774f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1775f8829a4aSRandall Stewart goto out_decr; 1776f8829a4aSRandall Stewart } 1777f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1778ca85e948SMichael Tuexen sctp_auditing(4, inp, stcb, net); 1779f8829a4aSRandall Stewart #endif 1780ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 1781629749b6SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 1782ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); 1783f8829a4aSRandall Stewart } 1784f8829a4aSRandall Stewart break; 1785f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 1786ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1787ad81507eSRandall Stewart break; 1788ad81507eSRandall Stewart } 1789f8829a4aSRandall Stewart if (sctp_cookie_timer(inp, stcb, net)) { 1790f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1791f8829a4aSRandall Stewart goto out_decr; 1792f8829a4aSRandall Stewart } 1793f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timocookie); 1794f42a358aSRandall Stewart stcb->asoc.timocookie++; 1795f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1796f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1797f8829a4aSRandall Stewart #endif 1798f8829a4aSRandall Stewart /* 1799f8829a4aSRandall Stewart * We consider T3 and Cookie timer pretty much the same with 1800f8829a4aSRandall Stewart * respect to where from in chunk_output. 1801f8829a4aSRandall Stewart */ 1802ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1803f8829a4aSRandall Stewart break; 1804f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 1805f8829a4aSRandall Stewart { 1806f8829a4aSRandall Stewart struct timeval tv; 1807f8829a4aSRandall Stewart int i, secret; 1808f8829a4aSRandall Stewart 1809ad81507eSRandall Stewart if (inp == NULL) { 1810ad81507eSRandall Stewart break; 1811ad81507eSRandall Stewart } 1812f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosecret); 18136e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tv); 1814f8829a4aSRandall Stewart inp->sctp_ep.time_of_secret_change = tv.tv_sec; 1815f8829a4aSRandall Stewart inp->sctp_ep.last_secret_number = 1816f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number; 1817f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number++; 1818f8829a4aSRandall Stewart if (inp->sctp_ep.current_secret_number >= 1819f8829a4aSRandall Stewart SCTP_HOW_MANY_SECRETS) { 1820f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number = 0; 1821f8829a4aSRandall Stewart } 1822f8829a4aSRandall Stewart secret = (int)inp->sctp_ep.current_secret_number; 1823f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) { 1824f8829a4aSRandall Stewart inp->sctp_ep.secret_key[secret][i] = 1825f8829a4aSRandall Stewart sctp_select_initial_TSN(&inp->sctp_ep); 1826f8829a4aSRandall Stewart } 1827f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net); 1828f8829a4aSRandall Stewart } 1829f8829a4aSRandall Stewart did_output = 0; 1830f8829a4aSRandall Stewart break; 1831f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 1832ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1833ad81507eSRandall Stewart break; 1834ad81507eSRandall Stewart } 1835f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timopathmtu); 1836f8829a4aSRandall Stewart sctp_pathmtu_timer(inp, stcb, net); 1837f8829a4aSRandall Stewart did_output = 0; 1838f8829a4aSRandall Stewart break; 1839f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 1840ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1841ad81507eSRandall Stewart break; 1842ad81507eSRandall Stewart } 1843f8829a4aSRandall Stewart if (sctp_shutdownack_timer(inp, stcb, net)) { 1844f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1845f8829a4aSRandall Stewart goto out_decr; 1846f8829a4aSRandall Stewart } 1847f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownack); 1848f42a358aSRandall Stewart stcb->asoc.timoshutdownack++; 1849f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1850f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1851f8829a4aSRandall Stewart #endif 1852ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED); 1853f8829a4aSRandall Stewart break; 1854f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 1855ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1856ad81507eSRandall Stewart break; 1857ad81507eSRandall Stewart } 1858f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownguard); 1859267dbe63SMichael Tuexen op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), 1860267dbe63SMichael Tuexen "Shutdown guard timer expired"); 1861267dbe63SMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 1862f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1863f8829a4aSRandall Stewart goto out_decr; 1864f8829a4aSRandall Stewart 1865f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 1866ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1867ad81507eSRandall Stewart break; 1868ad81507eSRandall Stewart } 1869f8829a4aSRandall Stewart if (sctp_strreset_timer(inp, stcb, net)) { 1870f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1871f8829a4aSRandall Stewart goto out_decr; 1872f8829a4aSRandall Stewart } 1873f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timostrmrst); 1874ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); 1875f8829a4aSRandall Stewart break; 1876f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 1877ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1878ad81507eSRandall Stewart break; 1879ad81507eSRandall Stewart } 1880f8829a4aSRandall Stewart if (sctp_asconf_timer(inp, stcb, net)) { 1881f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1882f8829a4aSRandall Stewart goto out_decr; 1883f8829a4aSRandall Stewart } 1884f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoasconf); 1885f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1886f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1887f8829a4aSRandall Stewart #endif 1888ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); 1889f8829a4aSRandall Stewart break; 1890851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 1891851b7298SRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1892851b7298SRandall Stewart break; 1893851b7298SRandall Stewart } 189404ee05e8SRandall Stewart sctp_delete_prim_timer(inp, stcb, net); 1895851b7298SRandall Stewart SCTP_STAT_INCR(sctps_timodelprim); 1896851b7298SRandall Stewart break; 1897f8829a4aSRandall Stewart 1898f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 1899ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1900ad81507eSRandall Stewart break; 1901ad81507eSRandall Stewart } 1902f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoautoclose); 1903f8829a4aSRandall Stewart sctp_autoclose_timer(inp, stcb, net); 1904ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); 1905f8829a4aSRandall Stewart did_output = 0; 1906f8829a4aSRandall Stewart break; 1907f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 1908ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1909ad81507eSRandall Stewart break; 1910ad81507eSRandall Stewart } 1911f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoassockill); 1912f8829a4aSRandall Stewart /* Can we free it yet? */ 1913f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1914ba785902SMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, 1915ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_1); 1916ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1917ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 1918ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1919ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1920ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 1921ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 1922ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 1923ceaad40aSRandall Stewart #endif 1924ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 1925ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_2); 1926ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1927ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 1928ceaad40aSRandall Stewart #endif 1929f8829a4aSRandall Stewart /* 1930f8829a4aSRandall Stewart * free asoc, always unlocks (or destroy's) so prevent 1931f8829a4aSRandall Stewart * duplicate unlock or unlock of a free mtx :-0 1932f8829a4aSRandall Stewart */ 1933f8829a4aSRandall Stewart stcb = NULL; 1934f8829a4aSRandall Stewart goto out_no_decr; 1935f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 1936f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinpkill); 1937ad81507eSRandall Stewart if (inp == NULL) { 1938ad81507eSRandall Stewart break; 1939ad81507eSRandall Stewart } 1940f8829a4aSRandall Stewart /* 1941f8829a4aSRandall Stewart * special case, take away our increment since WE are the 1942f8829a4aSRandall Stewart * killer 1943f8829a4aSRandall Stewart */ 1944f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1945ba785902SMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, 1946ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_3); 1947b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 19480c7dc840SRandall Stewart SCTP_CALLED_FROM_INPKILL_TIMER); 1949d61374e1SRandall Stewart inp = NULL; 1950f8829a4aSRandall Stewart goto out_no_decr; 1951f8829a4aSRandall Stewart default: 1952ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n", 1953fa89f692SMichael Tuexen type); 1954f8829a4aSRandall Stewart break; 195560990c0cSMichael Tuexen } 1956f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1957fa89f692SMichael Tuexen sctp_audit_log(0xF1, (uint8_t)type); 1958f8829a4aSRandall Stewart if (inp) 1959f8829a4aSRandall Stewart sctp_auditing(5, inp, stcb, net); 1960f8829a4aSRandall Stewart #endif 1961f8829a4aSRandall Stewart if ((did_output) && stcb) { 1962f8829a4aSRandall Stewart /* 1963f8829a4aSRandall Stewart * Now we need to clean up the control chunk chain if an 1964f8829a4aSRandall Stewart * ECNE is on it. It must be marked as UNSENT again so next 1965f8829a4aSRandall Stewart * call will continue to send it until such time that we get 1966f8829a4aSRandall Stewart * a CWR, to remove it. It is, however, less likely that we 1967f8829a4aSRandall Stewart * will find a ecn echo on the chain though. 1968f8829a4aSRandall Stewart */ 1969f8829a4aSRandall Stewart sctp_fix_ecn_echo(&stcb->asoc); 1970f8829a4aSRandall Stewart } 197144b7479bSRandall Stewart get_out: 1972f8829a4aSRandall Stewart if (stcb) { 1973f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 19742c62ba73SMichael Tuexen } else if (inp != NULL) { 19752c62ba73SMichael Tuexen SCTP_INP_WUNLOCK(inp); 19762c62ba73SMichael Tuexen } else { 19772c62ba73SMichael Tuexen SCTP_WQ_ADDR_UNLOCK(); 1978f8829a4aSRandall Stewart } 19792c62ba73SMichael Tuexen 1980f8829a4aSRandall Stewart out_decr: 1981f8829a4aSRandall Stewart if (inp) { 1982f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1983f8829a4aSRandall Stewart } 1984f8829a4aSRandall Stewart out_no_decr: 1985fa89f692SMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type = %d)\n", type); 19868518270eSMichael Tuexen CURVNET_RESTORE(); 1987f8829a4aSRandall Stewart } 1988f8829a4aSRandall Stewart 1989ad81507eSRandall Stewart void 1990f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1991f8829a4aSRandall Stewart struct sctp_nets *net) 1992f8829a4aSRandall Stewart { 1993ca85e948SMichael Tuexen uint32_t to_ticks; 1994f8829a4aSRandall Stewart struct sctp_timer *tmr; 1995f8829a4aSRandall Stewart 1996139bc87fSRandall Stewart if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) 1997ad81507eSRandall Stewart return; 1998f8829a4aSRandall Stewart 1999f8829a4aSRandall Stewart tmr = NULL; 2000f8829a4aSRandall Stewart if (stcb) { 2001f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2002f8829a4aSRandall Stewart } 2003f8829a4aSRandall Stewart switch (t_type) { 2004f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 2005f8829a4aSRandall Stewart /* Only 1 tick away :-) */ 2006b3f1ea41SRandall Stewart tmr = &SCTP_BASE_INFO(addr_wq_timer); 200742551e99SRandall Stewart to_ticks = SCTP_ADDRESS_TICK_DELAY; 2008f8829a4aSRandall Stewart break; 2009f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2010f8829a4aSRandall Stewart /* Here we use the RTO timer */ 2011f8829a4aSRandall Stewart { 2012f8829a4aSRandall Stewart int rto_val; 2013f8829a4aSRandall Stewart 2014f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2015ad81507eSRandall Stewart return; 2016f8829a4aSRandall Stewart } 2017f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2018f8829a4aSRandall Stewart if (net->RTO == 0) { 2019f8829a4aSRandall Stewart rto_val = stcb->asoc.initial_rto; 2020f8829a4aSRandall Stewart } else { 2021f8829a4aSRandall Stewart rto_val = net->RTO; 2022f8829a4aSRandall Stewart } 2023f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(rto_val); 2024f8829a4aSRandall Stewart } 2025f8829a4aSRandall Stewart break; 2026f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2027f8829a4aSRandall Stewart /* 2028f8829a4aSRandall Stewart * Here we use the INIT timer default usually about 1 2029f8829a4aSRandall Stewart * minute. 2030f8829a4aSRandall Stewart */ 2031f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2032ad81507eSRandall Stewart return; 2033f8829a4aSRandall Stewart } 2034f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2035f8829a4aSRandall Stewart if (net->RTO == 0) { 2036f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2037f8829a4aSRandall Stewart } else { 2038f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2039f8829a4aSRandall Stewart } 2040f8829a4aSRandall Stewart break; 2041f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2042f8829a4aSRandall Stewart /* 2043f8829a4aSRandall Stewart * Here we use the Delayed-Ack timer value from the inp 2044f8829a4aSRandall Stewart * ususually about 200ms. 2045f8829a4aSRandall Stewart */ 2046f8829a4aSRandall Stewart if (stcb == NULL) { 2047ad81507eSRandall Stewart return; 2048f8829a4aSRandall Stewart } 2049f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2050f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack); 2051f8829a4aSRandall Stewart break; 2052f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2053f8829a4aSRandall Stewart /* Here we use the RTO of the destination. */ 2054f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2055ad81507eSRandall Stewart return; 2056f8829a4aSRandall Stewart } 2057f8829a4aSRandall Stewart if (net->RTO == 0) { 2058f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2059f8829a4aSRandall Stewart } else { 2060f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2061f8829a4aSRandall Stewart } 2062f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2063f8829a4aSRandall Stewart break; 2064f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2065f8829a4aSRandall Stewart /* 2066f8829a4aSRandall Stewart * the net is used here so that we can add in the RTO. Even 2067f8829a4aSRandall Stewart * though we use a different timer. We also add the HB timer 2068f8829a4aSRandall Stewart * PLUS a random jitter. 2069f8829a4aSRandall Stewart */ 2070f3ba71beSMichael Tuexen if ((stcb == NULL) || (net == NULL)) { 2071ad81507eSRandall Stewart return; 2072ad81507eSRandall Stewart } else { 2073f8829a4aSRandall Stewart uint32_t rndval; 2074ca85e948SMichael Tuexen uint32_t jitter; 2075f8829a4aSRandall Stewart 2076ca85e948SMichael Tuexen if ((net->dest_state & SCTP_ADDR_NOHB) && 2077ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 2078ad81507eSRandall Stewart return; 2079f8829a4aSRandall Stewart } 2080f8829a4aSRandall Stewart if (net->RTO == 0) { 2081ca85e948SMichael Tuexen to_ticks = stcb->asoc.initial_rto; 2082f8829a4aSRandall Stewart } else { 2083ca85e948SMichael Tuexen to_ticks = net->RTO; 2084f8829a4aSRandall Stewart } 2085ca85e948SMichael Tuexen rndval = sctp_select_initial_TSN(&inp->sctp_ep); 2086ca85e948SMichael Tuexen jitter = rndval % to_ticks; 2087ca85e948SMichael Tuexen if (jitter >= (to_ticks >> 1)) { 2088ca85e948SMichael Tuexen to_ticks = to_ticks + (jitter - (to_ticks >> 1)); 2089f8829a4aSRandall Stewart } else { 2090ca85e948SMichael Tuexen to_ticks = to_ticks - jitter; 2091f8829a4aSRandall Stewart } 2092ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 2093ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_PF)) { 2094ca85e948SMichael Tuexen to_ticks += net->heart_beat_delay; 2095f8829a4aSRandall Stewart } 2096f8829a4aSRandall Stewart /* 2097f8829a4aSRandall Stewart * Now we must convert the to_ticks that are now in 2098f8829a4aSRandall Stewart * ms to ticks. 2099f8829a4aSRandall Stewart */ 2100f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(to_ticks); 2101ca85e948SMichael Tuexen tmr = &net->hb_timer; 2102f8829a4aSRandall Stewart } 2103f8829a4aSRandall Stewart break; 2104f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2105f8829a4aSRandall Stewart /* 2106f8829a4aSRandall Stewart * Here we can use the RTO timer from the network since one 2107f8829a4aSRandall Stewart * RTT was compelete. If a retran happened then we will be 2108f8829a4aSRandall Stewart * using the RTO initial value. 2109f8829a4aSRandall Stewart */ 2110f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2111ad81507eSRandall Stewart return; 2112f8829a4aSRandall Stewart } 2113f8829a4aSRandall Stewart if (net->RTO == 0) { 2114f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2115f8829a4aSRandall Stewart } else { 2116f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2117f8829a4aSRandall Stewart } 2118f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2119f8829a4aSRandall Stewart break; 2120f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2121f8829a4aSRandall Stewart /* 2122f8829a4aSRandall Stewart * nothing needed but the endpoint here ususually about 60 2123f8829a4aSRandall Stewart * minutes. 2124f8829a4aSRandall Stewart */ 2125f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2126f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE]; 2127f8829a4aSRandall Stewart break; 2128f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 2129f8829a4aSRandall Stewart if (stcb == NULL) { 2130ad81507eSRandall Stewart return; 2131f8829a4aSRandall Stewart } 2132f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2133f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT); 2134f8829a4aSRandall Stewart break; 2135f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 2136f8829a4aSRandall Stewart /* 2137f8829a4aSRandall Stewart * The inp is setup to die. We re-use the signature_chage 2138f8829a4aSRandall Stewart * timer since that has stopped and we are in the GONE 2139f8829a4aSRandall Stewart * state. 2140f8829a4aSRandall Stewart */ 2141f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2142f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT); 2143f8829a4aSRandall Stewart break; 2144f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2145f8829a4aSRandall Stewart /* 2146f8829a4aSRandall Stewart * Here we use the value found in the EP for PMTU ususually 2147f8829a4aSRandall Stewart * about 10 minutes. 2148f8829a4aSRandall Stewart */ 2149f3ba71beSMichael Tuexen if ((stcb == NULL) || (net == NULL)) { 2150ad81507eSRandall Stewart return; 2151f8829a4aSRandall Stewart } 215280c79bbeSMichael Tuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 215380c79bbeSMichael Tuexen return; 215480c79bbeSMichael Tuexen } 2155f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU]; 2156f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2157f8829a4aSRandall Stewart break; 2158f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2159f8829a4aSRandall Stewart /* Here we use the RTO of the destination */ 2160f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2161ad81507eSRandall Stewart return; 2162f8829a4aSRandall Stewart } 2163f8829a4aSRandall Stewart if (net->RTO == 0) { 2164f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2165f8829a4aSRandall Stewart } else { 2166f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2167f8829a4aSRandall Stewart } 2168f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2169f8829a4aSRandall Stewart break; 2170f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2171f8829a4aSRandall Stewart /* 2172f8829a4aSRandall Stewart * Here we use the endpoints shutdown guard timer usually 2173f8829a4aSRandall Stewart * about 3 minutes. 2174f8829a4aSRandall Stewart */ 2175f3ba71beSMichael Tuexen if (stcb == NULL) { 2176ad81507eSRandall Stewart return; 2177f8829a4aSRandall Stewart } 21782e2d6794SMichael Tuexen if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) { 21792e2d6794SMichael Tuexen to_ticks = 5 * MSEC_TO_TICKS(stcb->asoc.maxrto); 21802e2d6794SMichael Tuexen } else { 2181f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN]; 21822e2d6794SMichael Tuexen } 2183f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2184f8829a4aSRandall Stewart break; 2185f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2186f8829a4aSRandall Stewart /* 21871b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 21881b649582SRandall Stewart * the net's RTO. 2189f8829a4aSRandall Stewart */ 2190f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2191ad81507eSRandall Stewart return; 2192f8829a4aSRandall Stewart } 2193f8829a4aSRandall Stewart if (net->RTO == 0) { 2194f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2195f8829a4aSRandall Stewart } else { 2196f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2197f8829a4aSRandall Stewart } 2198f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2199f8829a4aSRandall Stewart break; 2200f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 2201f8829a4aSRandall Stewart /* 22021b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 22031b649582SRandall Stewart * the net's RTO. 2204f8829a4aSRandall Stewart */ 2205f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2206ad81507eSRandall Stewart return; 2207f8829a4aSRandall Stewart } 2208f8829a4aSRandall Stewart if (net->RTO == 0) { 2209f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2210f8829a4aSRandall Stewart } else { 2211f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2212f8829a4aSRandall Stewart } 2213f8829a4aSRandall Stewart tmr = &stcb->asoc.asconf_timer; 2214f8829a4aSRandall Stewart break; 2215851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2216851b7298SRandall Stewart if ((stcb == NULL) || (net != NULL)) { 2217851b7298SRandall Stewart return; 2218851b7298SRandall Stewart } 2219851b7298SRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2220851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2221851b7298SRandall Stewart break; 2222f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 2223f8829a4aSRandall Stewart if (stcb == NULL) { 2224ad81507eSRandall Stewart return; 2225f8829a4aSRandall Stewart } 2226f8829a4aSRandall Stewart if (stcb->asoc.sctp_autoclose_ticks == 0) { 2227f8829a4aSRandall Stewart /* 2228f8829a4aSRandall Stewart * Really an error since stcb is NOT set to 2229f8829a4aSRandall Stewart * autoclose 2230f8829a4aSRandall Stewart */ 2231ad81507eSRandall Stewart return; 2232f8829a4aSRandall Stewart } 2233f8829a4aSRandall Stewart to_ticks = stcb->asoc.sctp_autoclose_ticks; 2234f8829a4aSRandall Stewart tmr = &stcb->asoc.autoclose_timer; 2235f8829a4aSRandall Stewart break; 2236f8829a4aSRandall Stewart default: 2237ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n", 22386e9c45e0SMichael Tuexen __func__, t_type); 2239ad81507eSRandall Stewart return; 2240f8829a4aSRandall Stewart break; 224160990c0cSMichael Tuexen } 2242f8829a4aSRandall Stewart if ((to_ticks <= 0) || (tmr == NULL)) { 2243ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n", 22446e9c45e0SMichael Tuexen __func__, t_type, to_ticks, (void *)tmr); 2245ad81507eSRandall Stewart return; 2246f8829a4aSRandall Stewart } 2247139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 2248f8829a4aSRandall Stewart /* 2249f8829a4aSRandall Stewart * we do NOT allow you to have it already running. if it is 2250f8829a4aSRandall Stewart * we leave the current one up unchanged 2251f8829a4aSRandall Stewart */ 2252ad81507eSRandall Stewart return; 2253f8829a4aSRandall Stewart } 2254f8829a4aSRandall Stewart /* At this point we can proceed */ 2255f8829a4aSRandall Stewart if (t_type == SCTP_TIMER_TYPE_SEND) { 2256f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up++; 2257f8829a4aSRandall Stewart } 2258a5d547adSRandall Stewart tmr->stopped_from = 0; 2259f8829a4aSRandall Stewart tmr->type = t_type; 2260f8829a4aSRandall Stewart tmr->ep = (void *)inp; 2261f8829a4aSRandall Stewart tmr->tcb = (void *)stcb; 2262f8829a4aSRandall Stewart tmr->net = (void *)net; 2263f8829a4aSRandall Stewart tmr->self = (void *)tmr; 22648518270eSMichael Tuexen tmr->vnet = (void *)curvnet; 2265c4739e2fSRandall Stewart tmr->ticks = sctp_get_tick_count(); 2266ad81507eSRandall Stewart (void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr); 2267ad81507eSRandall Stewart return; 2268f8829a4aSRandall Stewart } 2269f8829a4aSRandall Stewart 22706e55db54SRandall Stewart void 2271f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2272a5d547adSRandall Stewart struct sctp_nets *net, uint32_t from) 2273f8829a4aSRandall Stewart { 2274f8829a4aSRandall Stewart struct sctp_timer *tmr; 2275f8829a4aSRandall Stewart 2276f8829a4aSRandall Stewart if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && 2277f8829a4aSRandall Stewart (inp == NULL)) 22786e55db54SRandall Stewart return; 2279f8829a4aSRandall Stewart 2280f8829a4aSRandall Stewart tmr = NULL; 2281f8829a4aSRandall Stewart if (stcb) { 2282f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2283f8829a4aSRandall Stewart } 2284f8829a4aSRandall Stewart switch (t_type) { 2285f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 2286b3f1ea41SRandall Stewart tmr = &SCTP_BASE_INFO(addr_wq_timer); 2287f8829a4aSRandall Stewart break; 2288f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2289f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22906e55db54SRandall Stewart return; 2291f8829a4aSRandall Stewart } 2292f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2293f8829a4aSRandall Stewart break; 2294f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2295f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22966e55db54SRandall Stewart return; 2297f8829a4aSRandall Stewart } 2298f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2299f8829a4aSRandall Stewart break; 2300f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2301f8829a4aSRandall Stewart if (stcb == NULL) { 23026e55db54SRandall Stewart return; 2303f8829a4aSRandall Stewart } 2304f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2305f8829a4aSRandall Stewart break; 2306f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2307f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 23086e55db54SRandall Stewart return; 2309f8829a4aSRandall Stewart } 2310f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2311f8829a4aSRandall Stewart break; 2312f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2313ca85e948SMichael Tuexen if ((stcb == NULL) || (net == NULL)) { 23146e55db54SRandall Stewart return; 2315f8829a4aSRandall Stewart } 2316ca85e948SMichael Tuexen tmr = &net->hb_timer; 2317f8829a4aSRandall Stewart break; 2318f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2319f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 23206e55db54SRandall Stewart return; 2321f8829a4aSRandall Stewart } 2322f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2323f8829a4aSRandall Stewart break; 2324f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2325f8829a4aSRandall Stewart /* nothing needed but the endpoint here */ 2326f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2327f8829a4aSRandall Stewart /* 2328f8829a4aSRandall Stewart * We re-use the newcookie timer for the INP kill timer. We 2329f8829a4aSRandall Stewart * must assure that we do not kill it by accident. 2330f8829a4aSRandall Stewart */ 2331f8829a4aSRandall Stewart break; 2332f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 2333f8829a4aSRandall Stewart /* 2334f8829a4aSRandall Stewart * Stop the asoc kill timer. 2335f8829a4aSRandall Stewart */ 2336f8829a4aSRandall Stewart if (stcb == NULL) { 23376e55db54SRandall Stewart return; 2338f8829a4aSRandall Stewart } 2339f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2340f8829a4aSRandall Stewart break; 2341f8829a4aSRandall Stewart 2342f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 2343f8829a4aSRandall Stewart /* 2344f8829a4aSRandall Stewart * The inp is setup to die. We re-use the signature_chage 2345f8829a4aSRandall Stewart * timer since that has stopped and we are in the GONE 2346f8829a4aSRandall Stewart * state. 2347f8829a4aSRandall Stewart */ 2348f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2349f8829a4aSRandall Stewart break; 2350f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2351f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 23526e55db54SRandall Stewart return; 2353f8829a4aSRandall Stewart } 2354f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2355f8829a4aSRandall Stewart break; 2356f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2357f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 23586e55db54SRandall Stewart return; 2359f8829a4aSRandall Stewart } 2360f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2361f8829a4aSRandall Stewart break; 2362f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2363f8829a4aSRandall Stewart if (stcb == NULL) { 23646e55db54SRandall Stewart return; 2365f8829a4aSRandall Stewart } 2366f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2367f8829a4aSRandall Stewart break; 2368f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2369f8829a4aSRandall Stewart if (stcb == NULL) { 23706e55db54SRandall Stewart return; 2371f8829a4aSRandall Stewart } 2372f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2373f8829a4aSRandall Stewart break; 2374f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 2375f8829a4aSRandall Stewart if (stcb == NULL) { 23766e55db54SRandall Stewart return; 2377f8829a4aSRandall Stewart } 2378f8829a4aSRandall Stewart tmr = &stcb->asoc.asconf_timer; 2379f8829a4aSRandall Stewart break; 2380851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2381851b7298SRandall Stewart if (stcb == NULL) { 2382851b7298SRandall Stewart return; 2383851b7298SRandall Stewart } 2384851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2385851b7298SRandall Stewart break; 2386f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 2387f8829a4aSRandall Stewart if (stcb == NULL) { 23886e55db54SRandall Stewart return; 2389f8829a4aSRandall Stewart } 2390f8829a4aSRandall Stewart tmr = &stcb->asoc.autoclose_timer; 2391f8829a4aSRandall Stewart break; 2392f8829a4aSRandall Stewart default: 2393ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n", 23946e9c45e0SMichael Tuexen __func__, t_type); 2395f8829a4aSRandall Stewart break; 239660990c0cSMichael Tuexen } 2397f8829a4aSRandall Stewart if (tmr == NULL) { 23986e55db54SRandall Stewart return; 2399f8829a4aSRandall Stewart } 2400f8829a4aSRandall Stewart if ((tmr->type != t_type) && tmr->type) { 2401f8829a4aSRandall Stewart /* 2402f8829a4aSRandall Stewart * Ok we have a timer that is under joint use. Cookie timer 2403f8829a4aSRandall Stewart * per chance with the SEND timer. We therefore are NOT 2404f8829a4aSRandall Stewart * running the timer that the caller wants stopped. So just 2405f8829a4aSRandall Stewart * return. 2406f8829a4aSRandall Stewart */ 24076e55db54SRandall Stewart return; 2408f8829a4aSRandall Stewart } 2409ad81507eSRandall Stewart if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) { 2410f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 2411f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 2412f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 2413f8829a4aSRandall Stewart } 2414f8829a4aSRandall Stewart } 2415f8829a4aSRandall Stewart tmr->self = NULL; 2416a5d547adSRandall Stewart tmr->stopped_from = from; 24176e55db54SRandall Stewart (void)SCTP_OS_TIMER_STOP(&tmr->timer); 24186e55db54SRandall Stewart return; 2419f8829a4aSRandall Stewart } 2420f8829a4aSRandall Stewart 2421f8829a4aSRandall Stewart uint32_t 2422*b0471b4bSMichael Tuexen sctp_calculate_len(struct mbuf *m) 2423*b0471b4bSMichael Tuexen { 2424f8829a4aSRandall Stewart uint32_t tlen = 0; 2425f8829a4aSRandall Stewart struct mbuf *at; 2426f8829a4aSRandall Stewart 2427f8829a4aSRandall Stewart at = m; 2428f8829a4aSRandall Stewart while (at) { 2429139bc87fSRandall Stewart tlen += SCTP_BUF_LEN(at); 2430139bc87fSRandall Stewart at = SCTP_BUF_NEXT(at); 2431f8829a4aSRandall Stewart } 2432f8829a4aSRandall Stewart return (tlen); 2433f8829a4aSRandall Stewart } 2434f8829a4aSRandall Stewart 2435f8829a4aSRandall Stewart void 2436f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp, 243744b7479bSRandall Stewart struct sctp_association *asoc, uint32_t mtu) 2438f8829a4aSRandall Stewart { 2439f8829a4aSRandall Stewart /* 2440f8829a4aSRandall Stewart * Reset the P-MTU size on this association, this involves changing 2441f8829a4aSRandall Stewart * the asoc MTU, going through ANY chunk+overhead larger than mtu to 2442f8829a4aSRandall Stewart * allow the DF flag to be cleared. 2443f8829a4aSRandall Stewart */ 2444f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 2445f8829a4aSRandall Stewart unsigned int eff_mtu, ovh; 2446f8829a4aSRandall Stewart 2447f8829a4aSRandall Stewart asoc->smallest_mtu = mtu; 2448f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2449f8829a4aSRandall Stewart ovh = SCTP_MIN_OVERHEAD; 2450f8829a4aSRandall Stewart } else { 2451f8829a4aSRandall Stewart ovh = SCTP_MIN_V4_OVERHEAD; 2452f8829a4aSRandall Stewart } 2453f8829a4aSRandall Stewart eff_mtu = mtu - ovh; 2454f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 2455f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2456f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2457f8829a4aSRandall Stewart } 2458f8829a4aSRandall Stewart } 2459f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 2460f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2461f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2462f8829a4aSRandall Stewart } 2463f8829a4aSRandall Stewart } 2464f8829a4aSRandall Stewart } 2465f8829a4aSRandall Stewart 2466f8829a4aSRandall Stewart 2467f8829a4aSRandall Stewart /* 2468f8829a4aSRandall Stewart * given an association and starting time of the current RTT period return 2469f42a358aSRandall Stewart * RTO in number of msecs net should point to the current network 2470f8829a4aSRandall Stewart */ 2471899288aeSRandall Stewart 2472f8829a4aSRandall Stewart uint32_t 2473f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb, 2474f8829a4aSRandall Stewart struct sctp_association *asoc, 2475f8829a4aSRandall Stewart struct sctp_nets *net, 24768c8e10b7SMichael Tuexen struct timeval *old, 2477*b0471b4bSMichael Tuexen int rtt_from_sack) 2478*b0471b4bSMichael Tuexen { 247918e198d3SRandall Stewart /*- 2480f8829a4aSRandall Stewart * given an association and the starting time of the current RTT 2481f42a358aSRandall Stewart * period (in value1/value2) return RTO in number of msecs. 2482f8829a4aSRandall Stewart */ 2483be1d9176SMichael Tuexen int32_t rtt; /* RTT in ms */ 2484be1d9176SMichael Tuexen uint32_t new_rto; 2485f8829a4aSRandall Stewart int first_measure = 0; 24868c8e10b7SMichael Tuexen struct timeval now; 2487f8829a4aSRandall Stewart 2488f8829a4aSRandall Stewart /************************/ 2489f8829a4aSRandall Stewart /* 1. calculate new RTT */ 2490f8829a4aSRandall Stewart /************************/ 2491f8829a4aSRandall Stewart /* get the current time */ 2492299108c5SRandall Stewart if (stcb->asoc.use_precise_time) { 2493299108c5SRandall Stewart (void)SCTP_GETPTIME_TIMEVAL(&now); 2494299108c5SRandall Stewart } else { 24956e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 2496299108c5SRandall Stewart } 2497be1d9176SMichael Tuexen timevalsub(&now, old); 2498be1d9176SMichael Tuexen /* store the current RTT in us */ 249981eb4e63SMichael Tuexen net->rtt = (uint64_t)1000000 *(uint64_t)now.tv_sec + 2500be1d9176SMichael Tuexen (uint64_t)now.tv_usec; 2501*b0471b4bSMichael Tuexen 2502b60b0fe6SMichael Tuexen /* compute rtt in ms */ 2503b60b0fe6SMichael Tuexen rtt = (int32_t)(net->rtt / 1000); 2504f79aab18SRandall Stewart if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) { 2505b7b84c0eSMichael Tuexen /* 2506b7b84c0eSMichael Tuexen * Tell the CC module that a new update has just occurred 2507b7b84c0eSMichael Tuexen * from a sack 2508b7b84c0eSMichael Tuexen */ 2509f79aab18SRandall Stewart (*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now); 2510f79aab18SRandall Stewart } 2511f79aab18SRandall Stewart /* 2512f79aab18SRandall Stewart * Do we need to determine the lan? We do this only on sacks i.e. 2513f79aab18SRandall Stewart * RTT being determined from data not non-data (HB/INIT->INITACK). 2514f79aab18SRandall Stewart */ 2515f79aab18SRandall Stewart if ((rtt_from_sack == SCTP_RTT_FROM_DATA) && 2516be1d9176SMichael Tuexen (net->lan_type == SCTP_LAN_UNKNOWN)) { 2517be1d9176SMichael Tuexen if (net->rtt > SCTP_LOCAL_LAN_RTT) { 2518899288aeSRandall Stewart net->lan_type = SCTP_LAN_INTERNET; 2519899288aeSRandall Stewart } else { 2520899288aeSRandall Stewart net->lan_type = SCTP_LAN_LOCAL; 2521899288aeSRandall Stewart } 2522899288aeSRandall Stewart } 2523f8829a4aSRandall Stewart /***************************/ 2524f8829a4aSRandall Stewart /* 2. update RTTVAR & SRTT */ 2525f8829a4aSRandall Stewart /***************************/ 2526be1d9176SMichael Tuexen /*- 2527be1d9176SMichael Tuexen * Compute the scaled average lastsa and the 2528be1d9176SMichael Tuexen * scaled variance lastsv as described in van Jacobson 2529be1d9176SMichael Tuexen * Paper "Congestion Avoidance and Control", Annex A. 2530be1d9176SMichael Tuexen * 2531be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt 2532be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar 2533be1d9176SMichael Tuexen */ 25349a972525SRandall Stewart if (net->RTO_measured) { 2535be1d9176SMichael Tuexen rtt -= (net->lastsa >> SCTP_RTT_SHIFT); 2536be1d9176SMichael Tuexen net->lastsa += rtt; 2537be1d9176SMichael Tuexen if (rtt < 0) { 2538be1d9176SMichael Tuexen rtt = -rtt; 2539be1d9176SMichael Tuexen } 2540be1d9176SMichael Tuexen rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); 2541be1d9176SMichael Tuexen net->lastsv += rtt; 2542b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2543f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_RTTVAR); 254480fefe0aSRandall Stewart } 2545f8829a4aSRandall Stewart } else { 2546f8829a4aSRandall Stewart /* First RTO measurment */ 25479a972525SRandall Stewart net->RTO_measured = 1; 2548f8829a4aSRandall Stewart first_measure = 1; 2549be1d9176SMichael Tuexen net->lastsa = rtt << SCTP_RTT_SHIFT; 2550be1d9176SMichael Tuexen net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT; 2551b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2552f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_INITIAL_RTT); 255380fefe0aSRandall Stewart } 2554f8829a4aSRandall Stewart } 2555be1d9176SMichael Tuexen if (net->lastsv == 0) { 2556be1d9176SMichael Tuexen net->lastsv = SCTP_CLOCK_GRANULARITY; 2557be1d9176SMichael Tuexen } 2558108df27cSRandall Stewart new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 2559f8829a4aSRandall Stewart if ((new_rto > SCTP_SAT_NETWORK_MIN) && 2560f8829a4aSRandall Stewart (stcb->asoc.sat_network_lockout == 0)) { 2561f8829a4aSRandall Stewart stcb->asoc.sat_network = 1; 2562f8829a4aSRandall Stewart } else if ((!first_measure) && stcb->asoc.sat_network) { 2563f8829a4aSRandall Stewart stcb->asoc.sat_network = 0; 2564f8829a4aSRandall Stewart stcb->asoc.sat_network_lockout = 1; 2565f8829a4aSRandall Stewart } 2566f8829a4aSRandall Stewart /* bound it, per C6/C7 in Section 5.3.1 */ 2567f8829a4aSRandall Stewart if (new_rto < stcb->asoc.minrto) { 2568f8829a4aSRandall Stewart new_rto = stcb->asoc.minrto; 2569f8829a4aSRandall Stewart } 2570f8829a4aSRandall Stewart if (new_rto > stcb->asoc.maxrto) { 2571f8829a4aSRandall Stewart new_rto = stcb->asoc.maxrto; 2572f8829a4aSRandall Stewart } 25735e54f665SRandall Stewart /* we are now returning the RTO */ 25745e54f665SRandall Stewart return (new_rto); 2575f8829a4aSRandall Stewart } 2576f8829a4aSRandall Stewart 2577f8829a4aSRandall Stewart /* 2578f8829a4aSRandall Stewart * return a pointer to a contiguous piece of data from the given mbuf chain 2579f8829a4aSRandall Stewart * starting at 'off' for 'len' bytes. If the desired piece spans more than 2580f8829a4aSRandall Stewart * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size 2581f8829a4aSRandall Stewart * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain. 2582f8829a4aSRandall Stewart */ 258372fb6fdbSRandall Stewart caddr_t 2584f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t *in_ptr) 2585f8829a4aSRandall Stewart { 2586f8829a4aSRandall Stewart uint32_t count; 2587f8829a4aSRandall Stewart uint8_t *ptr; 2588f8829a4aSRandall Stewart 2589f8829a4aSRandall Stewart ptr = in_ptr; 2590f8829a4aSRandall Stewart if ((off < 0) || (len <= 0)) 2591f8829a4aSRandall Stewart return (NULL); 2592f8829a4aSRandall Stewart 2593f8829a4aSRandall Stewart /* find the desired start location */ 2594f8829a4aSRandall Stewart while ((m != NULL) && (off > 0)) { 2595139bc87fSRandall Stewart if (off < SCTP_BUF_LEN(m)) 2596f8829a4aSRandall Stewart break; 2597139bc87fSRandall Stewart off -= SCTP_BUF_LEN(m); 2598139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2599f8829a4aSRandall Stewart } 2600f8829a4aSRandall Stewart if (m == NULL) 2601f8829a4aSRandall Stewart return (NULL); 2602f8829a4aSRandall Stewart 2603f8829a4aSRandall Stewart /* is the current mbuf large enough (eg. contiguous)? */ 2604139bc87fSRandall Stewart if ((SCTP_BUF_LEN(m) - off) >= len) { 2605f8829a4aSRandall Stewart return (mtod(m, caddr_t)+off); 2606f8829a4aSRandall Stewart } else { 2607f8829a4aSRandall Stewart /* else, it spans more than one mbuf, so save a temp copy... */ 2608f8829a4aSRandall Stewart while ((m != NULL) && (len > 0)) { 2609139bc87fSRandall Stewart count = min(SCTP_BUF_LEN(m) - off, len); 26105ba7f91fSMichael Tuexen memcpy(ptr, mtod(m, caddr_t)+off, count); 2611f8829a4aSRandall Stewart len -= count; 2612f8829a4aSRandall Stewart ptr += count; 2613f8829a4aSRandall Stewart off = 0; 2614139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2615f8829a4aSRandall Stewart } 2616f8829a4aSRandall Stewart if ((m == NULL) && (len > 0)) 2617f8829a4aSRandall Stewart return (NULL); 2618f8829a4aSRandall Stewart else 2619f8829a4aSRandall Stewart return ((caddr_t)in_ptr); 2620f8829a4aSRandall Stewart } 2621f8829a4aSRandall Stewart } 2622f8829a4aSRandall Stewart 2623f8829a4aSRandall Stewart 262444b7479bSRandall Stewart 2625f8829a4aSRandall Stewart struct sctp_paramhdr * 2626f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m, 2627f8829a4aSRandall Stewart int offset, 2628f8829a4aSRandall Stewart struct sctp_paramhdr *pull, 2629f8829a4aSRandall Stewart int pull_limit) 2630f8829a4aSRandall Stewart { 2631f8829a4aSRandall Stewart /* This just provides a typed signature to Peter's Pull routine */ 2632f8829a4aSRandall Stewart return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit, 2633f8829a4aSRandall Stewart (uint8_t *)pull)); 2634f8829a4aSRandall Stewart } 2635f8829a4aSRandall Stewart 2636f8829a4aSRandall Stewart 2637ce11b842SMichael Tuexen struct mbuf * 2638f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen) 2639f8829a4aSRandall Stewart { 2640ce11b842SMichael Tuexen struct mbuf *m_last; 2641ce11b842SMichael Tuexen caddr_t dp; 2642f8829a4aSRandall Stewart 2643f8829a4aSRandall Stewart if (padlen > 3) { 2644ce11b842SMichael Tuexen return (NULL); 2645f8829a4aSRandall Stewart } 264641eee555SRandall Stewart if (padlen <= M_TRAILINGSPACE(m)) { 2647f8829a4aSRandall Stewart /* 2648f8829a4aSRandall Stewart * The easy way. We hope the majority of the time we hit 2649f8829a4aSRandall Stewart * here :) 2650f8829a4aSRandall Stewart */ 2651ce11b842SMichael Tuexen m_last = m; 2652f8829a4aSRandall Stewart } else { 2653ce11b842SMichael Tuexen /* Hard way we must grow the mbuf chain */ 2654ce11b842SMichael Tuexen m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA); 2655ce11b842SMichael Tuexen if (m_last == NULL) { 2656ce11b842SMichael Tuexen return (NULL); 2657f8829a4aSRandall Stewart } 2658ce11b842SMichael Tuexen SCTP_BUF_LEN(m_last) = 0; 2659ce11b842SMichael Tuexen SCTP_BUF_NEXT(m_last) = NULL; 2660ce11b842SMichael Tuexen SCTP_BUF_NEXT(m) = m_last; 2661f8829a4aSRandall Stewart } 2662ce11b842SMichael Tuexen dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last); 2663ce11b842SMichael Tuexen SCTP_BUF_LEN(m_last) += padlen; 2664ce11b842SMichael Tuexen memset(dp, 0, padlen); 2665ce11b842SMichael Tuexen return (m_last); 2666f8829a4aSRandall Stewart } 2667f8829a4aSRandall Stewart 2668ce11b842SMichael Tuexen struct mbuf * 2669f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) 2670f8829a4aSRandall Stewart { 2671f8829a4aSRandall Stewart /* find the last mbuf in chain and pad it */ 2672f8829a4aSRandall Stewart struct mbuf *m_at; 2673f8829a4aSRandall Stewart 2674ce11b842SMichael Tuexen if (last_mbuf != NULL) { 2675f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(last_mbuf, padval)); 2676f8829a4aSRandall Stewart } else { 267717267b32SMichael Tuexen for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) { 2678139bc87fSRandall Stewart if (SCTP_BUF_NEXT(m_at) == NULL) { 2679f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(m_at, padval)); 2680f8829a4aSRandall Stewart } 2681f8829a4aSRandall Stewart } 2682f8829a4aSRandall Stewart } 2683ce11b842SMichael Tuexen return (NULL); 2684f8829a4aSRandall Stewart } 2685f8829a4aSRandall Stewart 2686f8829a4aSRandall Stewart static void 2687c5b5675dSMichael Tuexen sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, 2688410a3b1eSMichael Tuexen uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked 2689ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2690ceaad40aSRandall Stewart SCTP_UNUSED 2691ceaad40aSRandall Stewart #endif 2692ceaad40aSRandall Stewart ) 2693f8829a4aSRandall Stewart { 2694f8829a4aSRandall Stewart struct mbuf *m_notify; 2695f8829a4aSRandall Stewart struct sctp_assoc_change *sac; 2696f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 26979a8e3088SMichael Tuexen unsigned int notif_len; 26989a8e3088SMichael Tuexen uint16_t abort_len; 2699e06b67c7SMichael Tuexen unsigned int i; 2700ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2701ceaad40aSRandall Stewart struct socket *so; 2702ceaad40aSRandall Stewart #endif 2703ceaad40aSRandall Stewart 270459713bbfSMichael Tuexen if (stcb == NULL) { 270559713bbfSMichael Tuexen return; 270659713bbfSMichael Tuexen } 270758411b08SMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { 27089a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_assoc_change); 2709a2b42326SMichael Tuexen if (abort != NULL) { 2710c9eb4473SMichael Tuexen abort_len = ntohs(abort->ch.chunk_length); 27119669e724SMichael Tuexen /* 27129669e724SMichael Tuexen * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be 271345d41de5SMichael Tuexen * contiguous. 27149669e724SMichael Tuexen */ 27159669e724SMichael Tuexen if (abort_len > SCTP_CHUNK_BUFFER_SIZE) { 27169669e724SMichael Tuexen abort_len = SCTP_CHUNK_BUFFER_SIZE; 27179669e724SMichael Tuexen } 2718a2b42326SMichael Tuexen } else { 2719a2b42326SMichael Tuexen abort_len = 0; 2720c5b5675dSMichael Tuexen } 2721a2b42326SMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 2722a2b42326SMichael Tuexen notif_len += SCTP_ASSOC_SUPPORTS_MAX; 2723a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 2724a2b42326SMichael Tuexen notif_len += abort_len; 2725a2b42326SMichael Tuexen } 2726eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 2727a2b42326SMichael Tuexen if (m_notify == NULL) { 2728a2b42326SMichael Tuexen /* Retry with smaller value. */ 27299a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_assoc_change); 2730eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 2731a2b42326SMichael Tuexen if (m_notify == NULL) { 273258411b08SMichael Tuexen goto set_error; 2733a2b42326SMichael Tuexen } 2734a2b42326SMichael Tuexen } 2735a2b42326SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 2736f8829a4aSRandall Stewart sac = mtod(m_notify, struct sctp_assoc_change *); 2737e432298aSXin LI memset(sac, 0, notif_len); 2738f8829a4aSRandall Stewart sac->sac_type = SCTP_ASSOC_CHANGE; 2739f8829a4aSRandall Stewart sac->sac_flags = 0; 2740f8829a4aSRandall Stewart sac->sac_length = sizeof(struct sctp_assoc_change); 2741c5b5675dSMichael Tuexen sac->sac_state = state; 2742f8829a4aSRandall Stewart sac->sac_error = error; 2743f8829a4aSRandall Stewart /* XXX verify these stream counts */ 2744f8829a4aSRandall Stewart sac->sac_outbound_streams = stcb->asoc.streamoutcnt; 2745f8829a4aSRandall Stewart sac->sac_inbound_streams = stcb->asoc.streamincnt; 2746f8829a4aSRandall Stewart sac->sac_assoc_id = sctp_get_associd(stcb); 2747a2b42326SMichael Tuexen if (notif_len > sizeof(struct sctp_assoc_change)) { 2748c5b5675dSMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 2749e06b67c7SMichael Tuexen i = 0; 2750c79bec9cSMichael Tuexen if (stcb->asoc.prsctp_supported == 1) { 2751e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR; 2752e06b67c7SMichael Tuexen } 2753c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 1) { 2754e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH; 2755e06b67c7SMichael Tuexen } 2756c79bec9cSMichael Tuexen if (stcb->asoc.asconf_supported == 1) { 2757e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; 2758e06b67c7SMichael Tuexen } 275944249214SRandall Stewart if (stcb->asoc.idata_supported == 1) { 276044249214SRandall Stewart sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING; 276144249214SRandall Stewart } 2762e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; 2763c79bec9cSMichael Tuexen if (stcb->asoc.reconfig_supported == 1) { 2764e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; 2765e06b67c7SMichael Tuexen } 2766e06b67c7SMichael Tuexen sac->sac_length += i; 2767a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 2768a2b42326SMichael Tuexen memcpy(sac->sac_info, abort, abort_len); 2769a2b42326SMichael Tuexen sac->sac_length += abort_len; 2770a2b42326SMichael Tuexen } 2771c5b5675dSMichael Tuexen } 2772e06b67c7SMichael Tuexen SCTP_BUF_LEN(m_notify) = sac->sac_length; 2773f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 27747215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2775f8829a4aSRandall Stewart m_notify); 277658411b08SMichael Tuexen if (control != NULL) { 2777139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 277828cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 2779f8829a4aSRandall Stewart /* not that we need this */ 2780f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2781f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2782f8829a4aSRandall Stewart control, 2783cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, 2784cfde3ff7SRandall Stewart so_locked); 278558411b08SMichael Tuexen } else { 278658411b08SMichael Tuexen sctp_m_freem(m_notify); 278758411b08SMichael Tuexen } 278858411b08SMichael Tuexen } 278958411b08SMichael Tuexen /* 279058411b08SMichael Tuexen * For 1-to-1 style sockets, we send up and error when an ABORT 279158411b08SMichael Tuexen * comes in. 279258411b08SMichael Tuexen */ 279358411b08SMichael Tuexen set_error: 279458411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 279558411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 279658411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 2797e045904fSMichael Tuexen SOCK_LOCK(stcb->sctp_socket); 2798410a3b1eSMichael Tuexen if (from_peer) { 279958411b08SMichael Tuexen if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) { 280058411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); 280158411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNREFUSED; 280258411b08SMichael Tuexen } else { 280358411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 280458411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNRESET; 280558411b08SMichael Tuexen } 2806410a3b1eSMichael Tuexen } else { 2807553bb068SMichael Tuexen if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) || 2808553bb068SMichael Tuexen (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED)) { 2809553bb068SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT); 2810553bb068SMichael Tuexen stcb->sctp_socket->so_error = ETIMEDOUT; 2811553bb068SMichael Tuexen } else { 2812410a3b1eSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED); 2813410a3b1eSMichael Tuexen stcb->sctp_socket->so_error = ECONNABORTED; 2814410a3b1eSMichael Tuexen } 281558411b08SMichael Tuexen } 28163acfe1e1SGleb Smirnoff SOCK_UNLOCK(stcb->sctp_socket); 2817553bb068SMichael Tuexen } 281858411b08SMichael Tuexen /* Wake ANY sleepers */ 2819ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2820ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 2821ceaad40aSRandall Stewart if (!so_locked) { 2822ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 2823ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 2824ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 2825ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 2826ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 2827ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 2828ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2829ceaad40aSRandall Stewart return; 2830ceaad40aSRandall Stewart } 2831ceaad40aSRandall Stewart } 2832ceaad40aSRandall Stewart #endif 283358411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 283458411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 283558411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 28363acfe1e1SGleb Smirnoff socantrcvmore(stcb->sctp_socket); 283758411b08SMichael Tuexen } 283858411b08SMichael Tuexen sorwakeup(stcb->sctp_socket); 283958411b08SMichael Tuexen sowwakeup(stcb->sctp_socket); 2840ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2841ceaad40aSRandall Stewart if (!so_locked) { 2842ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2843ceaad40aSRandall Stewart } 2844ceaad40aSRandall Stewart #endif 2845f8829a4aSRandall Stewart } 2846f8829a4aSRandall Stewart 2847f8829a4aSRandall Stewart static void 2848f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, 28493cb3567dSMichael Tuexen struct sockaddr *sa, uint32_t error, int so_locked 28503cb3567dSMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 28513cb3567dSMichael Tuexen SCTP_UNUSED 28523cb3567dSMichael Tuexen #endif 28533cb3567dSMichael Tuexen ) 2854f8829a4aSRandall Stewart { 2855f8829a4aSRandall Stewart struct mbuf *m_notify; 2856f8829a4aSRandall Stewart struct sctp_paddr_change *spc; 2857f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2858f8829a4aSRandall Stewart 285960990c0cSMichael Tuexen if ((stcb == NULL) || 286060990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { 2861f8829a4aSRandall Stewart /* event not enabled */ 2862f8829a4aSRandall Stewart return; 2863830d754dSRandall Stewart } 2864eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA); 2865f8829a4aSRandall Stewart if (m_notify == NULL) 2866f8829a4aSRandall Stewart return; 2867139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2868f8829a4aSRandall Stewart spc = mtod(m_notify, struct sctp_paddr_change *); 286956711f94SMichael Tuexen memset(spc, 0, sizeof(struct sctp_paddr_change)); 2870f8829a4aSRandall Stewart spc->spc_type = SCTP_PEER_ADDR_CHANGE; 2871f8829a4aSRandall Stewart spc->spc_flags = 0; 2872f8829a4aSRandall Stewart spc->spc_length = sizeof(struct sctp_paddr_change); 28735e2c2d87SRandall Stewart switch (sa->sa_family) { 2874ea5eba11SMichael Tuexen #ifdef INET 28755e2c2d87SRandall Stewart case AF_INET: 2876d59107f7SMichael Tuexen #ifdef INET6 2877d59107f7SMichael Tuexen if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 2878d59107f7SMichael Tuexen in6_sin_2_v4mapsin6((struct sockaddr_in *)sa, 2879d59107f7SMichael Tuexen (struct sockaddr_in6 *)&spc->spc_aaddr); 2880d59107f7SMichael Tuexen } else { 2881f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 2882d59107f7SMichael Tuexen } 2883d59107f7SMichael Tuexen #else 2884d59107f7SMichael Tuexen memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 2885d59107f7SMichael Tuexen #endif 28865e2c2d87SRandall Stewart break; 2887ea5eba11SMichael Tuexen #endif 28885e2c2d87SRandall Stewart #ifdef INET6 28895e2c2d87SRandall Stewart case AF_INET6: 28905e2c2d87SRandall Stewart { 2891f42a358aSRandall Stewart struct sockaddr_in6 *sin6; 2892f42a358aSRandall Stewart 2893f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6)); 2894f42a358aSRandall Stewart 2895f42a358aSRandall Stewart sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; 2896f42a358aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 289742551e99SRandall Stewart if (sin6->sin6_scope_id == 0) { 289842551e99SRandall Stewart /* recover scope_id for user */ 2899f42a358aSRandall Stewart (void)sa6_recoverscope(sin6); 290042551e99SRandall Stewart } else { 290142551e99SRandall Stewart /* clear embedded scope_id for user */ 290242551e99SRandall Stewart in6_clearscope(&sin6->sin6_addr); 290342551e99SRandall Stewart } 2904f42a358aSRandall Stewart } 29055e2c2d87SRandall Stewart break; 29065e2c2d87SRandall Stewart } 29075e2c2d87SRandall Stewart #endif 29085e2c2d87SRandall Stewart default: 29095e2c2d87SRandall Stewart /* TSNH */ 29105e2c2d87SRandall Stewart break; 2911f8829a4aSRandall Stewart } 2912f8829a4aSRandall Stewart spc->spc_state = state; 2913f8829a4aSRandall Stewart spc->spc_error = error; 2914f8829a4aSRandall Stewart spc->spc_assoc_id = sctp_get_associd(stcb); 2915f8829a4aSRandall Stewart 2916139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change); 2917139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 2918f8829a4aSRandall Stewart 2919f8829a4aSRandall Stewart /* append to socket */ 2920f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 29217215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2922f8829a4aSRandall Stewart m_notify); 2923f8829a4aSRandall Stewart if (control == NULL) { 2924f8829a4aSRandall Stewart /* no memory */ 2925f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2926f8829a4aSRandall Stewart return; 2927f8829a4aSRandall Stewart } 2928139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 2929139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2930f8829a4aSRandall Stewart /* not that we need this */ 2931f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2932f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2933f8829a4aSRandall Stewart control, 2934cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 2935cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 29363cb3567dSMichael Tuexen so_locked); 2937f8829a4aSRandall Stewart } 2938f8829a4aSRandall Stewart 2939f8829a4aSRandall Stewart 2940f8829a4aSRandall Stewart static void 29411edc9dbaSMichael Tuexen sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, 2942ceaad40aSRandall Stewart struct sctp_tmit_chunk *chk, int so_locked 2943ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2944ceaad40aSRandall Stewart SCTP_UNUSED 2945ceaad40aSRandall Stewart #endif 2946ceaad40aSRandall Stewart ) 2947f8829a4aSRandall Stewart { 2948830d754dSRandall Stewart struct mbuf *m_notify; 2949f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 29509935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 2951f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2952ab337314SMichael Tuexen struct sctp_chunkhdr *chkhdr; 2953ab337314SMichael Tuexen int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len; 2954f8829a4aSRandall Stewart 295560990c0cSMichael Tuexen if ((stcb == NULL) || 29569935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 29579935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 2958f8829a4aSRandall Stewart /* event not enabled */ 2959f8829a4aSRandall Stewart return; 2960830d754dSRandall Stewart } 29619935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 2962ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed_event); 29639935403aSMichael Tuexen } else { 2964ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed); 29659935403aSMichael Tuexen } 2966ab337314SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); 2967f8829a4aSRandall Stewart if (m_notify == NULL) 2968f8829a4aSRandall Stewart /* no space left */ 2969f8829a4aSRandall Stewart return; 2970ab337314SMichael Tuexen SCTP_BUF_LEN(m_notify) = notifhdr_len; 2971ab337314SMichael Tuexen if (stcb->asoc.idata_supported) { 2972ab337314SMichael Tuexen chkhdr_len = sizeof(struct sctp_idata_chunk); 2973ab337314SMichael Tuexen } else { 2974ab337314SMichael Tuexen chkhdr_len = sizeof(struct sctp_data_chunk); 2975ab337314SMichael Tuexen } 2976ab337314SMichael Tuexen /* Use some defaults in case we can't access the chunk header */ 2977ab337314SMichael Tuexen if (chk->send_size >= chkhdr_len) { 2978ab337314SMichael Tuexen payload_len = chk->send_size - chkhdr_len; 2979ab337314SMichael Tuexen } else { 2980ab337314SMichael Tuexen payload_len = 0; 2981ab337314SMichael Tuexen } 2982ab337314SMichael Tuexen padding_len = 0; 2983ab337314SMichael Tuexen if (chk->data != NULL) { 2984ab337314SMichael Tuexen chkhdr = mtod(chk->data, struct sctp_chunkhdr *); 2985ab337314SMichael Tuexen if (chkhdr != NULL) { 2986ab337314SMichael Tuexen chk_len = ntohs(chkhdr->chunk_length); 2987ab337314SMichael Tuexen if ((chk_len >= chkhdr_len) && 2988ab337314SMichael Tuexen (chk->send_size >= chk_len) && 2989ab337314SMichael Tuexen (chk->send_size - chk_len < 4)) { 2990ab337314SMichael Tuexen padding_len = chk->send_size - chk_len; 2991ab337314SMichael Tuexen payload_len = chk->send_size - chkhdr_len - padding_len; 2992ab337314SMichael Tuexen } 2993ab337314SMichael Tuexen } 2994ab337314SMichael Tuexen } 29959935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 29969935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 2997ab337314SMichael Tuexen memset(ssfe, 0, notifhdr_len); 29989935403aSMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 29991edc9dbaSMichael Tuexen if (sent) { 30009935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_SENT; 30011edc9dbaSMichael Tuexen } else { 30021edc9dbaSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 30031edc9dbaSMichael Tuexen } 3004ab337314SMichael Tuexen ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len); 30059935403aSMichael Tuexen ssfe->ssfe_error = error; 30069935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 300749656eefSMichael Tuexen ssfe->ssfe_info.snd_sid = chk->rec.data.sid; 30089935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags; 300949656eefSMichael Tuexen ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid; 30109935403aSMichael Tuexen ssfe->ssfe_info.snd_context = chk->rec.data.context; 30119935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 30129935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 30139935403aSMichael Tuexen } else { 3014f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 3015ab337314SMichael Tuexen memset(ssf, 0, notifhdr_len); 3016f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 30171edc9dbaSMichael Tuexen if (sent) { 3018f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_SENT; 30191edc9dbaSMichael Tuexen } else { 30201edc9dbaSMichael Tuexen ssf->ssf_flags = SCTP_DATA_UNSENT; 30211edc9dbaSMichael Tuexen } 3022ab337314SMichael Tuexen ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len); 3023f8829a4aSRandall Stewart ssf->ssf_error = error; 3024f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 302549656eefSMichael Tuexen ssf->ssf_info.sinfo_stream = chk->rec.data.sid; 302649656eefSMichael Tuexen ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid; 3027f8829a4aSRandall Stewart ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; 302849656eefSMichael Tuexen ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid; 3029f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = chk->rec.data.context; 3030f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 3031f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 30329935403aSMichael Tuexen } 3033ab337314SMichael Tuexen if (chk->data != NULL) { 3034ab337314SMichael Tuexen /* Trim off the sctp chunk header (it should be there) */ 3035ab337314SMichael Tuexen if (chk->send_size == chkhdr_len + payload_len + padding_len) { 3036ab337314SMichael Tuexen m_adj(chk->data, chkhdr_len); 3037ab337314SMichael Tuexen m_adj(chk->data, -padding_len); 3038830d754dSRandall Stewart sctp_mbuf_crush(chk->data); 3039ab337314SMichael Tuexen chk->send_size -= (chkhdr_len + padding_len); 3040830d754dSRandall Stewart } 3041830d754dSRandall Stewart } 3042810ec536SMichael Tuexen SCTP_BUF_NEXT(m_notify) = chk->data; 3043f8829a4aSRandall Stewart /* Steal off the mbuf */ 3044f8829a4aSRandall Stewart chk->data = NULL; 3045f8829a4aSRandall Stewart /* 3046f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 3047f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 3048f8829a4aSRandall Stewart * non-reader 3049f8829a4aSRandall Stewart */ 3050139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3051f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3052f8829a4aSRandall Stewart return; 3053f8829a4aSRandall Stewart } 3054f8829a4aSRandall Stewart /* append to socket */ 3055f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 30567215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3057f8829a4aSRandall Stewart m_notify); 3058f8829a4aSRandall Stewart if (control == NULL) { 3059f8829a4aSRandall Stewart /* no memory */ 3060f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3061f8829a4aSRandall Stewart return; 3062f8829a4aSRandall Stewart } 306328cd0699SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3064139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 306528cd0699SMichael Tuexen /* not that we need this */ 306628cd0699SMichael Tuexen control->tail_mbuf = m_notify; 3067f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3068f8829a4aSRandall Stewart control, 3069cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 3070cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 3071cfde3ff7SRandall Stewart so_locked); 3072f8829a4aSRandall Stewart } 3073f8829a4aSRandall Stewart 3074f8829a4aSRandall Stewart 3075f8829a4aSRandall Stewart static void 3076f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, 3077ceaad40aSRandall Stewart struct sctp_stream_queue_pending *sp, int so_locked 3078ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3079ceaad40aSRandall Stewart SCTP_UNUSED 3080ceaad40aSRandall Stewart #endif 3081ceaad40aSRandall Stewart ) 3082f8829a4aSRandall Stewart { 3083f8829a4aSRandall Stewart struct mbuf *m_notify; 3084f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 30859935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 3086f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3087ab337314SMichael Tuexen int notifhdr_len; 3088f8829a4aSRandall Stewart 308960990c0cSMichael Tuexen if ((stcb == NULL) || 30909935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 30919935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 3092f8829a4aSRandall Stewart /* event not enabled */ 3093f8829a4aSRandall Stewart return; 3094830d754dSRandall Stewart } 30959935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 3096ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed_event); 30979935403aSMichael Tuexen } else { 3098ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed); 30999935403aSMichael Tuexen } 3100ab337314SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); 31019935403aSMichael Tuexen if (m_notify == NULL) { 3102f8829a4aSRandall Stewart /* no space left */ 3103f8829a4aSRandall Stewart return; 31049935403aSMichael Tuexen } 3105ab337314SMichael Tuexen SCTP_BUF_LEN(m_notify) = notifhdr_len; 31069935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 31079935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 3108ab337314SMichael Tuexen memset(ssfe, 0, notifhdr_len); 3109ad83c8a5SMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 31109935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 3111ab337314SMichael Tuexen ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length); 31129935403aSMichael Tuexen ssfe->ssfe_error = error; 31139935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 311449656eefSMichael Tuexen ssfe->ssfe_info.snd_sid = sp->sid; 31159935403aSMichael Tuexen if (sp->some_taken) { 31169935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG; 31179935403aSMichael Tuexen } else { 31189935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG; 31199935403aSMichael Tuexen } 31209935403aSMichael Tuexen ssfe->ssfe_info.snd_ppid = sp->ppid; 31219935403aSMichael Tuexen ssfe->ssfe_info.snd_context = sp->context; 31229935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 31239935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 31249935403aSMichael Tuexen } else { 3125f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 3126ab337314SMichael Tuexen memset(ssf, 0, notifhdr_len); 3127f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 3128f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_UNSENT; 3129ab337314SMichael Tuexen ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length); 3130f8829a4aSRandall Stewart ssf->ssf_error = error; 3131f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 313249656eefSMichael Tuexen ssf->ssf_info.sinfo_stream = sp->sid; 3133f3b05218SMichael Tuexen ssf->ssf_info.sinfo_ssn = 0; 3134fc14de76SRandall Stewart if (sp->some_taken) { 3135fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG; 3136fc14de76SRandall Stewart } else { 3137fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG; 3138fc14de76SRandall Stewart } 3139f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = sp->ppid; 3140f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = sp->context; 3141f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 3142f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 31439935403aSMichael Tuexen } 31449935403aSMichael Tuexen SCTP_BUF_NEXT(m_notify) = sp->data; 3145f8829a4aSRandall Stewart 3146f8829a4aSRandall Stewart /* Steal off the mbuf */ 3147f8829a4aSRandall Stewart sp->data = NULL; 3148f8829a4aSRandall Stewart /* 3149f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 3150f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 3151f8829a4aSRandall Stewart * non-reader 3152f8829a4aSRandall Stewart */ 3153139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3154f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3155f8829a4aSRandall Stewart return; 3156f8829a4aSRandall Stewart } 3157f8829a4aSRandall Stewart /* append to socket */ 3158f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 31597215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3160f8829a4aSRandall Stewart m_notify); 3161f8829a4aSRandall Stewart if (control == NULL) { 3162f8829a4aSRandall Stewart /* no memory */ 3163f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3164f8829a4aSRandall Stewart return; 3165f8829a4aSRandall Stewart } 316628cd0699SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3167139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 316828cd0699SMichael Tuexen /* not that we need this */ 316928cd0699SMichael Tuexen control->tail_mbuf = m_notify; 3170f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3171f8829a4aSRandall Stewart control, 3172cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3173f8829a4aSRandall Stewart } 3174f8829a4aSRandall Stewart 3175f8829a4aSRandall Stewart 3176f8829a4aSRandall Stewart 3177f8829a4aSRandall Stewart static void 31787215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb) 3179f8829a4aSRandall Stewart { 3180f8829a4aSRandall Stewart struct mbuf *m_notify; 3181f8829a4aSRandall Stewart struct sctp_adaptation_event *sai; 3182f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3183f8829a4aSRandall Stewart 318460990c0cSMichael Tuexen if ((stcb == NULL) || 318560990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { 3186f8829a4aSRandall Stewart /* event not enabled */ 3187f8829a4aSRandall Stewart return; 3188830d754dSRandall Stewart } 3189eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA); 3190f8829a4aSRandall Stewart if (m_notify == NULL) 3191f8829a4aSRandall Stewart /* no space left */ 3192f8829a4aSRandall Stewart return; 3193139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3194f8829a4aSRandall Stewart sai = mtod(m_notify, struct sctp_adaptation_event *); 3195e432298aSXin LI memset(sai, 0, sizeof(struct sctp_adaptation_event)); 3196f8829a4aSRandall Stewart sai->sai_type = SCTP_ADAPTATION_INDICATION; 3197f8829a4aSRandall Stewart sai->sai_flags = 0; 3198f8829a4aSRandall Stewart sai->sai_length = sizeof(struct sctp_adaptation_event); 31992afb3e84SRandall Stewart sai->sai_adaptation_ind = stcb->asoc.peers_adaptation; 3200f8829a4aSRandall Stewart sai->sai_assoc_id = sctp_get_associd(stcb); 3201f8829a4aSRandall Stewart 3202139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event); 3203139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3204f8829a4aSRandall Stewart 3205f8829a4aSRandall Stewart /* append to socket */ 3206f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 32077215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3208f8829a4aSRandall Stewart m_notify); 3209f8829a4aSRandall Stewart if (control == NULL) { 3210f8829a4aSRandall Stewart /* no memory */ 3211f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3212f8829a4aSRandall Stewart return; 3213f8829a4aSRandall Stewart } 3214139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3215139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3216f8829a4aSRandall Stewart /* not that we need this */ 3217f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3218f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3219f8829a4aSRandall Stewart control, 3220cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3221f8829a4aSRandall Stewart } 3222f8829a4aSRandall Stewart 322303b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */ 3224810ec536SMichael Tuexen static void 32252dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, 3226810ec536SMichael Tuexen uint32_t val, int so_locked 3227810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3228810ec536SMichael Tuexen SCTP_UNUSED 3229810ec536SMichael Tuexen #endif 3230810ec536SMichael Tuexen ) 3231f8829a4aSRandall Stewart { 3232f8829a4aSRandall Stewart struct mbuf *m_notify; 3233f8829a4aSRandall Stewart struct sctp_pdapi_event *pdapi; 3234f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 323503b0b021SRandall Stewart struct sockbuf *sb; 3236f8829a4aSRandall Stewart 323760990c0cSMichael Tuexen if ((stcb == NULL) || 323860990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { 3239f8829a4aSRandall Stewart /* event not enabled */ 3240f8829a4aSRandall Stewart return; 3241830d754dSRandall Stewart } 3242cd1386abSMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 3243cd1386abSMichael Tuexen return; 3244cd1386abSMichael Tuexen } 3245eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA); 3246f8829a4aSRandall Stewart if (m_notify == NULL) 3247f8829a4aSRandall Stewart /* no space left */ 3248f8829a4aSRandall Stewart return; 3249139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3250f8829a4aSRandall Stewart pdapi = mtod(m_notify, struct sctp_pdapi_event *); 3251e432298aSXin LI memset(pdapi, 0, sizeof(struct sctp_pdapi_event)); 3252f8829a4aSRandall Stewart pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; 3253f8829a4aSRandall Stewart pdapi->pdapi_flags = 0; 3254f8829a4aSRandall Stewart pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); 3255f8829a4aSRandall Stewart pdapi->pdapi_indication = error; 32569a6142d8SRandall Stewart pdapi->pdapi_stream = (val >> 16); 32579a6142d8SRandall Stewart pdapi->pdapi_seq = (val & 0x0000ffff); 3258f8829a4aSRandall Stewart pdapi->pdapi_assoc_id = sctp_get_associd(stcb); 3259f8829a4aSRandall Stewart 3260139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); 3261139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3262f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 32637215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3264f8829a4aSRandall Stewart m_notify); 3265f8829a4aSRandall Stewart if (control == NULL) { 3266f8829a4aSRandall Stewart /* no memory */ 3267f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3268f8829a4aSRandall Stewart return; 3269f8829a4aSRandall Stewart } 3270139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 327128cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3272f8829a4aSRandall Stewart /* not that we need this */ 3273f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 327403b0b021SRandall Stewart sb = &stcb->sctp_socket->so_rcv; 3275b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 3276139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify)); 327780fefe0aSRandall Stewart } 327803b0b021SRandall Stewart sctp_sballoc(stcb, sb, m_notify); 3279b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 328003b0b021SRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 328180fefe0aSRandall Stewart } 328203b0b021SRandall Stewart control->end_added = 1; 328303b0b021SRandall Stewart if (stcb->asoc.control_pdapi) 328403b0b021SRandall Stewart TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); 328503b0b021SRandall Stewart else { 328603b0b021SRandall Stewart /* we really should not see this case */ 328703b0b021SRandall Stewart TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); 328803b0b021SRandall Stewart } 328903b0b021SRandall Stewart if (stcb->sctp_ep && stcb->sctp_socket) { 329003b0b021SRandall Stewart /* This should always be the case */ 3291810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3292810ec536SMichael Tuexen struct socket *so; 3293810ec536SMichael Tuexen 3294810ec536SMichael Tuexen so = SCTP_INP_SO(stcb->sctp_ep); 3295810ec536SMichael Tuexen if (!so_locked) { 3296810ec536SMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, 1); 3297810ec536SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 3298810ec536SMichael Tuexen SCTP_SOCKET_LOCK(so, 1); 3299810ec536SMichael Tuexen SCTP_TCB_LOCK(stcb); 3300810ec536SMichael Tuexen atomic_subtract_int(&stcb->asoc.refcnt, 1); 3301810ec536SMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3302810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3303810ec536SMichael Tuexen return; 3304810ec536SMichael Tuexen } 3305810ec536SMichael Tuexen } 3306810ec536SMichael Tuexen #endif 330703b0b021SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 3308810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3309810ec536SMichael Tuexen if (!so_locked) { 3310810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3311810ec536SMichael Tuexen } 3312810ec536SMichael Tuexen #endif 3313f8829a4aSRandall Stewart } 3314f8829a4aSRandall Stewart } 3315f8829a4aSRandall Stewart 3316f8829a4aSRandall Stewart static void 3317f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb) 3318f8829a4aSRandall Stewart { 3319f8829a4aSRandall Stewart struct mbuf *m_notify; 3320f8829a4aSRandall Stewart struct sctp_shutdown_event *sse; 3321f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3322f8829a4aSRandall Stewart 3323f8829a4aSRandall Stewart /* 3324f8829a4aSRandall Stewart * For TCP model AND UDP connected sockets we will send an error up 3325f8829a4aSRandall Stewart * when an SHUTDOWN completes 3326f8829a4aSRandall Stewart */ 3327f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3328f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3329f8829a4aSRandall Stewart /* mark socket closed for read/write and wakeup! */ 3330ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3331ceaad40aSRandall Stewart struct socket *so; 3332ceaad40aSRandall Stewart 3333ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3334ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3335ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3336ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3337ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3338ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3339ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3340ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3341ceaad40aSRandall Stewart return; 3342ceaad40aSRandall Stewart } 3343ceaad40aSRandall Stewart #endif 3344f8829a4aSRandall Stewart socantsendmore(stcb->sctp_socket); 3345ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3346ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3347ceaad40aSRandall Stewart #endif 3348f8829a4aSRandall Stewart } 3349e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { 3350f8829a4aSRandall Stewart /* event not enabled */ 3351f8829a4aSRandall Stewart return; 3352830d754dSRandall Stewart } 3353eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA); 3354f8829a4aSRandall Stewart if (m_notify == NULL) 3355f8829a4aSRandall Stewart /* no space left */ 3356f8829a4aSRandall Stewart return; 3357f8829a4aSRandall Stewart sse = mtod(m_notify, struct sctp_shutdown_event *); 3358e432298aSXin LI memset(sse, 0, sizeof(struct sctp_shutdown_event)); 3359f8829a4aSRandall Stewart sse->sse_type = SCTP_SHUTDOWN_EVENT; 3360f8829a4aSRandall Stewart sse->sse_flags = 0; 3361f8829a4aSRandall Stewart sse->sse_length = sizeof(struct sctp_shutdown_event); 3362f8829a4aSRandall Stewart sse->sse_assoc_id = sctp_get_associd(stcb); 3363f8829a4aSRandall Stewart 3364139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event); 3365139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3366f8829a4aSRandall Stewart 3367f8829a4aSRandall Stewart /* append to socket */ 3368f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 33697215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3370f8829a4aSRandall Stewart m_notify); 3371f8829a4aSRandall Stewart if (control == NULL) { 3372f8829a4aSRandall Stewart /* no memory */ 3373f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3374f8829a4aSRandall Stewart return; 3375f8829a4aSRandall Stewart } 3376139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 337728cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3378f8829a4aSRandall Stewart /* not that we need this */ 3379f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3380f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3381f8829a4aSRandall Stewart control, 3382cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3383f8829a4aSRandall Stewart } 3384f8829a4aSRandall Stewart 3385f8829a4aSRandall Stewart static void 3386830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb, 3387830d754dSRandall Stewart int so_locked 3388830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3389830d754dSRandall Stewart SCTP_UNUSED 3390830d754dSRandall Stewart #endif 3391830d754dSRandall Stewart ) 3392830d754dSRandall Stewart { 3393830d754dSRandall Stewart struct mbuf *m_notify; 3394830d754dSRandall Stewart struct sctp_sender_dry_event *event; 3395830d754dSRandall Stewart struct sctp_queued_to_read *control; 3396830d754dSRandall Stewart 339760990c0cSMichael Tuexen if ((stcb == NULL) || 339860990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { 3399830d754dSRandall Stewart /* event not enabled */ 3400830d754dSRandall Stewart return; 3401830d754dSRandall Stewart } 3402eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA); 3403830d754dSRandall Stewart if (m_notify == NULL) { 3404830d754dSRandall Stewart /* no space left */ 3405830d754dSRandall Stewart return; 3406830d754dSRandall Stewart } 3407830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3408830d754dSRandall Stewart event = mtod(m_notify, struct sctp_sender_dry_event *); 3409e432298aSXin LI memset(event, 0, sizeof(struct sctp_sender_dry_event)); 3410830d754dSRandall Stewart event->sender_dry_type = SCTP_SENDER_DRY_EVENT; 3411830d754dSRandall Stewart event->sender_dry_flags = 0; 3412830d754dSRandall Stewart event->sender_dry_length = sizeof(struct sctp_sender_dry_event); 3413830d754dSRandall Stewart event->sender_dry_assoc_id = sctp_get_associd(stcb); 3414830d754dSRandall Stewart 3415830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event); 3416830d754dSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3417830d754dSRandall Stewart 3418830d754dSRandall Stewart /* append to socket */ 3419830d754dSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 34207215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 34217215cc1bSMichael Tuexen m_notify); 3422830d754dSRandall Stewart if (control == NULL) { 3423830d754dSRandall Stewart /* no memory */ 3424830d754dSRandall Stewart sctp_m_freem(m_notify); 3425830d754dSRandall Stewart return; 3426830d754dSRandall Stewart } 3427830d754dSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3428830d754dSRandall Stewart control->spec_flags = M_NOTIFICATION; 3429830d754dSRandall Stewart /* not that we need this */ 3430830d754dSRandall Stewart control->tail_mbuf = m_notify; 3431830d754dSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control, 3432cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3433830d754dSRandall Stewart } 3434830d754dSRandall Stewart 3435ea44232bSRandall Stewart 3436c4e848b7SRandall Stewart void 3437c4e848b7SRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag) 3438ea44232bSRandall Stewart { 3439ea44232bSRandall Stewart struct mbuf *m_notify; 3440ea44232bSRandall Stewart struct sctp_queued_to_read *control; 3441c4e848b7SRandall Stewart struct sctp_stream_change_event *stradd; 3442ea44232bSRandall Stewart 34438c501e51SMichael Tuexen if ((stcb == NULL) || 34448c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) { 3445ea44232bSRandall Stewart /* event not enabled */ 3446ea44232bSRandall Stewart return; 3447ea44232bSRandall Stewart } 3448c4e848b7SRandall Stewart if ((stcb->asoc.peer_req_out) && flag) { 3449c4e848b7SRandall Stewart /* Peer made the request, don't tell the local user */ 3450c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3451c4e848b7SRandall Stewart return; 3452c4e848b7SRandall Stewart } 3453c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3454e432298aSXin LI m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA); 3455ea44232bSRandall Stewart if (m_notify == NULL) 3456ea44232bSRandall Stewart /* no space left */ 3457ea44232bSRandall Stewart return; 3458ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3459c4e848b7SRandall Stewart stradd = mtod(m_notify, struct sctp_stream_change_event *); 3460e432298aSXin LI memset(stradd, 0, sizeof(struct sctp_stream_change_event)); 3461c4e848b7SRandall Stewart stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT; 3462c4e848b7SRandall Stewart stradd->strchange_flags = flag; 3463e432298aSXin LI stradd->strchange_length = sizeof(struct sctp_stream_change_event); 3464c4e848b7SRandall Stewart stradd->strchange_assoc_id = sctp_get_associd(stcb); 3465c4e848b7SRandall Stewart stradd->strchange_instrms = numberin; 3466c4e848b7SRandall Stewart stradd->strchange_outstrms = numberout; 3467e432298aSXin LI SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event); 3468ea44232bSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3469ea44232bSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3470ea44232bSRandall Stewart /* no space */ 3471ea44232bSRandall Stewart sctp_m_freem(m_notify); 3472ea44232bSRandall Stewart return; 3473ea44232bSRandall Stewart } 3474ea44232bSRandall Stewart /* append to socket */ 3475ea44232bSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 34767215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3477ea44232bSRandall Stewart m_notify); 3478ea44232bSRandall Stewart if (control == NULL) { 3479ea44232bSRandall Stewart /* no memory */ 3480ea44232bSRandall Stewart sctp_m_freem(m_notify); 3481ea44232bSRandall Stewart return; 3482ea44232bSRandall Stewart } 3483ea44232bSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 348428cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3485ea44232bSRandall Stewart /* not that we need this */ 3486ea44232bSRandall Stewart control->tail_mbuf = m_notify; 3487ea44232bSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3488ea44232bSRandall Stewart control, 3489cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3490ea44232bSRandall Stewart } 3491ea44232bSRandall Stewart 3492c4e848b7SRandall Stewart void 3493c4e848b7SRandall Stewart sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag) 3494c4e848b7SRandall Stewart { 3495c4e848b7SRandall Stewart struct mbuf *m_notify; 3496c4e848b7SRandall Stewart struct sctp_queued_to_read *control; 3497c4e848b7SRandall Stewart struct sctp_assoc_reset_event *strasoc; 3498c4e848b7SRandall Stewart 34998c501e51SMichael Tuexen if ((stcb == NULL) || 35008c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) { 3501c4e848b7SRandall Stewart /* event not enabled */ 3502c4e848b7SRandall Stewart return; 3503c4e848b7SRandall Stewart } 3504e432298aSXin LI m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA); 3505c4e848b7SRandall Stewart if (m_notify == NULL) 3506c4e848b7SRandall Stewart /* no space left */ 3507c4e848b7SRandall Stewart return; 3508c4e848b7SRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3509c4e848b7SRandall Stewart strasoc = mtod(m_notify, struct sctp_assoc_reset_event *); 3510e432298aSXin LI memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event)); 3511c4e848b7SRandall Stewart strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT; 3512c4e848b7SRandall Stewart strasoc->assocreset_flags = flag; 3513e432298aSXin LI strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event); 3514c4e848b7SRandall Stewart strasoc->assocreset_assoc_id = sctp_get_associd(stcb); 3515c4e848b7SRandall Stewart strasoc->assocreset_local_tsn = sending_tsn; 3516c4e848b7SRandall Stewart strasoc->assocreset_remote_tsn = recv_tsn; 3517e432298aSXin LI SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event); 3518c4e848b7SRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3519c4e848b7SRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3520c4e848b7SRandall Stewart /* no space */ 3521c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3522c4e848b7SRandall Stewart return; 3523c4e848b7SRandall Stewart } 3524c4e848b7SRandall Stewart /* append to socket */ 3525c4e848b7SRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3526c4e848b7SRandall Stewart 0, 0, stcb->asoc.context, 0, 0, 0, 3527c4e848b7SRandall Stewart m_notify); 3528c4e848b7SRandall Stewart if (control == NULL) { 3529c4e848b7SRandall Stewart /* no memory */ 3530c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3531c4e848b7SRandall Stewart return; 3532c4e848b7SRandall Stewart } 3533c4e848b7SRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 353428cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3535c4e848b7SRandall Stewart /* not that we need this */ 3536c4e848b7SRandall Stewart control->tail_mbuf = m_notify; 3537c4e848b7SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3538c4e848b7SRandall Stewart control, 3539c4e848b7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3540c4e848b7SRandall Stewart } 3541c4e848b7SRandall Stewart 3542c4e848b7SRandall Stewart 3543ea44232bSRandall Stewart 3544830d754dSRandall Stewart static void 3545f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb, 3546f8829a4aSRandall Stewart int number_entries, uint16_t *list, int flag) 3547f8829a4aSRandall Stewart { 3548f8829a4aSRandall Stewart struct mbuf *m_notify; 3549f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3550f8829a4aSRandall Stewart struct sctp_stream_reset_event *strreset; 3551f8829a4aSRandall Stewart int len; 3552f8829a4aSRandall Stewart 35538c501e51SMichael Tuexen if ((stcb == NULL) || 35548c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) { 3555f8829a4aSRandall Stewart /* event not enabled */ 3556f8829a4aSRandall Stewart return; 3557830d754dSRandall Stewart } 3558eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); 3559f8829a4aSRandall Stewart if (m_notify == NULL) 3560f8829a4aSRandall Stewart /* no space left */ 3561f8829a4aSRandall Stewart return; 3562139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3563f8829a4aSRandall Stewart len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); 3564f8829a4aSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3565f8829a4aSRandall Stewart /* never enough room */ 3566f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3567f8829a4aSRandall Stewart return; 3568f8829a4aSRandall Stewart } 3569f8829a4aSRandall Stewart strreset = mtod(m_notify, struct sctp_stream_reset_event *); 3570e432298aSXin LI memset(strreset, 0, len); 3571f8829a4aSRandall Stewart strreset->strreset_type = SCTP_STREAM_RESET_EVENT; 3572c4e848b7SRandall Stewart strreset->strreset_flags = flag; 3573f8829a4aSRandall Stewart strreset->strreset_length = len; 3574f8829a4aSRandall Stewart strreset->strreset_assoc_id = sctp_get_associd(stcb); 3575f8829a4aSRandall Stewart if (number_entries) { 3576f8829a4aSRandall Stewart int i; 3577f8829a4aSRandall Stewart 3578f8829a4aSRandall Stewart for (i = 0; i < number_entries; i++) { 3579c4e848b7SRandall Stewart strreset->strreset_stream_list[i] = ntohs(list[i]); 3580f8829a4aSRandall Stewart } 3581f8829a4aSRandall Stewart } 3582139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3583139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3584139bc87fSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3585f8829a4aSRandall Stewart /* no space */ 3586f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3587f8829a4aSRandall Stewart return; 3588f8829a4aSRandall Stewart } 3589f8829a4aSRandall Stewart /* append to socket */ 3590f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 35917215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3592f8829a4aSRandall Stewart m_notify); 3593f8829a4aSRandall Stewart if (control == NULL) { 3594f8829a4aSRandall Stewart /* no memory */ 3595f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3596f8829a4aSRandall Stewart return; 3597f8829a4aSRandall Stewart } 3598139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 359928cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3600f8829a4aSRandall Stewart /* not that we need this */ 3601f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3602f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3603f8829a4aSRandall Stewart control, 3604cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3605f8829a4aSRandall Stewart } 3606f8829a4aSRandall Stewart 3607f8829a4aSRandall Stewart 3608389b1b11SMichael Tuexen static void 3609389b1b11SMichael Tuexen sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk) 3610389b1b11SMichael Tuexen { 3611389b1b11SMichael Tuexen struct mbuf *m_notify; 3612389b1b11SMichael Tuexen struct sctp_remote_error *sre; 3613389b1b11SMichael Tuexen struct sctp_queued_to_read *control; 36149a8e3088SMichael Tuexen unsigned int notif_len; 36159a8e3088SMichael Tuexen uint16_t chunk_len; 3616389b1b11SMichael Tuexen 3617389b1b11SMichael Tuexen if ((stcb == NULL) || 3618389b1b11SMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { 3619389b1b11SMichael Tuexen return; 3620389b1b11SMichael Tuexen } 3621389b1b11SMichael Tuexen if (chunk != NULL) { 3622c9eb4473SMichael Tuexen chunk_len = ntohs(chunk->ch.chunk_length); 36239669e724SMichael Tuexen /* 36249669e724SMichael Tuexen * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be 362545d41de5SMichael Tuexen * contiguous. 36269669e724SMichael Tuexen */ 36279669e724SMichael Tuexen if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) { 36289669e724SMichael Tuexen chunk_len = SCTP_CHUNK_BUFFER_SIZE; 36299669e724SMichael Tuexen } 3630389b1b11SMichael Tuexen } else { 3631389b1b11SMichael Tuexen chunk_len = 0; 3632389b1b11SMichael Tuexen } 36339a8e3088SMichael Tuexen notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len); 3634eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3635389b1b11SMichael Tuexen if (m_notify == NULL) { 3636389b1b11SMichael Tuexen /* Retry with smaller value. */ 36379a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_remote_error); 3638eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3639389b1b11SMichael Tuexen if (m_notify == NULL) { 3640389b1b11SMichael Tuexen return; 3641389b1b11SMichael Tuexen } 3642389b1b11SMichael Tuexen } 3643389b1b11SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 3644389b1b11SMichael Tuexen sre = mtod(m_notify, struct sctp_remote_error *); 364556711f94SMichael Tuexen memset(sre, 0, notif_len); 3646389b1b11SMichael Tuexen sre->sre_type = SCTP_REMOTE_ERROR; 3647389b1b11SMichael Tuexen sre->sre_flags = 0; 3648389b1b11SMichael Tuexen sre->sre_length = sizeof(struct sctp_remote_error); 3649389b1b11SMichael Tuexen sre->sre_error = error; 3650389b1b11SMichael Tuexen sre->sre_assoc_id = sctp_get_associd(stcb); 3651389b1b11SMichael Tuexen if (notif_len > sizeof(struct sctp_remote_error)) { 3652389b1b11SMichael Tuexen memcpy(sre->sre_data, chunk, chunk_len); 3653389b1b11SMichael Tuexen sre->sre_length += chunk_len; 3654389b1b11SMichael Tuexen } 3655389b1b11SMichael Tuexen SCTP_BUF_LEN(m_notify) = sre->sre_length; 3656389b1b11SMichael Tuexen control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3657389b1b11SMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3658389b1b11SMichael Tuexen m_notify); 3659389b1b11SMichael Tuexen if (control != NULL) { 3660389b1b11SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 366128cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3662389b1b11SMichael Tuexen /* not that we need this */ 3663389b1b11SMichael Tuexen control->tail_mbuf = m_notify; 3664389b1b11SMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, 3665389b1b11SMichael Tuexen control, 3666389b1b11SMichael Tuexen &stcb->sctp_socket->so_rcv, 1, 3667389b1b11SMichael Tuexen SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3668389b1b11SMichael Tuexen } else { 3669389b1b11SMichael Tuexen sctp_m_freem(m_notify); 3670389b1b11SMichael Tuexen } 3671389b1b11SMichael Tuexen } 3672389b1b11SMichael Tuexen 3673389b1b11SMichael Tuexen 3674f8829a4aSRandall Stewart void 3675f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, 3676ceaad40aSRandall Stewart uint32_t error, void *data, int so_locked 3677ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3678ceaad40aSRandall Stewart SCTP_UNUSED 3679ceaad40aSRandall Stewart #endif 3680ceaad40aSRandall Stewart ) 3681f8829a4aSRandall Stewart { 3682830d754dSRandall Stewart if ((stcb == NULL) || 3683830d754dSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3684f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3685830d754dSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 3686830d754dSRandall Stewart /* If the socket is gone we are out of here */ 3687f8829a4aSRandall Stewart return; 3688f8829a4aSRandall Stewart } 3689a99b6783SRandall Stewart if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { 3690a99b6783SRandall Stewart return; 3691a99b6783SRandall Stewart } 3692fb4a67d2SMichael Tuexen if ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || 3693fb4a67d2SMichael Tuexen (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED)) { 369417205eccSRandall Stewart if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || 369517205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_UP) || 369617205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { 369717205eccSRandall Stewart /* Don't report these in front states */ 369817205eccSRandall Stewart return; 369917205eccSRandall Stewart } 370017205eccSRandall Stewart } 3701f8829a4aSRandall Stewart switch (notification) { 3702f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_UP: 3703f8829a4aSRandall Stewart if (stcb->asoc.assoc_up_sent == 0) { 3704410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked); 3705f8829a4aSRandall Stewart stcb->asoc.assoc_up_sent = 1; 3706f8829a4aSRandall Stewart } 37072afb3e84SRandall Stewart if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { 37087215cc1bSMichael Tuexen sctp_notify_adaptation_layer(stcb); 37092afb3e84SRandall Stewart } 3710c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 0) { 3711830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 3712830d754dSRandall Stewart NULL, so_locked); 3713830d754dSRandall Stewart } 3714f8829a4aSRandall Stewart break; 3715f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_DOWN: 3716410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked); 3717f8829a4aSRandall Stewart break; 3718f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_DOWN: 3719f8829a4aSRandall Stewart { 3720f8829a4aSRandall Stewart struct sctp_nets *net; 3721f8829a4aSRandall Stewart 3722f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3723f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, 37243cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 3725f8829a4aSRandall Stewart break; 3726f8829a4aSRandall Stewart } 3727f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_UP: 3728f8829a4aSRandall Stewart { 3729f8829a4aSRandall Stewart struct sctp_nets *net; 3730f8829a4aSRandall Stewart 3731f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3732f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, 37333cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 3734f8829a4aSRandall Stewart break; 3735f8829a4aSRandall Stewart } 3736f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_CONFIRMED: 3737f8829a4aSRandall Stewart { 3738f8829a4aSRandall Stewart struct sctp_nets *net; 3739f8829a4aSRandall Stewart 3740f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3741f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, 37423cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 3743f8829a4aSRandall Stewart break; 3744f8829a4aSRandall Stewart } 3745f8829a4aSRandall Stewart case SCTP_NOTIFY_SPECIAL_SP_FAIL: 3746f8829a4aSRandall Stewart sctp_notify_send_failed2(stcb, error, 3747ceaad40aSRandall Stewart (struct sctp_stream_queue_pending *)data, so_locked); 3748f8829a4aSRandall Stewart break; 37491edc9dbaSMichael Tuexen case SCTP_NOTIFY_SENT_DG_FAIL: 37501edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 1, error, 37511edc9dbaSMichael Tuexen (struct sctp_tmit_chunk *)data, so_locked); 37521edc9dbaSMichael Tuexen break; 37531edc9dbaSMichael Tuexen case SCTP_NOTIFY_UNSENT_DG_FAIL: 37541edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 0, error, 3755ceaad40aSRandall Stewart (struct sctp_tmit_chunk *)data, so_locked); 3756f8829a4aSRandall Stewart break; 3757f8829a4aSRandall Stewart case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: 37589a6142d8SRandall Stewart { 37599a6142d8SRandall Stewart uint32_t val; 37609a6142d8SRandall Stewart 37619a6142d8SRandall Stewart val = *((uint32_t *)data); 37629a6142d8SRandall Stewart 3763810ec536SMichael Tuexen sctp_notify_partial_delivery_indication(stcb, error, val, so_locked); 3764f8829a4aSRandall Stewart break; 3765810ec536SMichael Tuexen } 3766410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_LOC_ABORTED: 3767fb4a67d2SMichael Tuexen if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) || 3768fb4a67d2SMichael Tuexen ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) { 3769410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked); 3770c105859eSRandall Stewart } else { 3771410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked); 3772410a3b1eSMichael Tuexen } 3773410a3b1eSMichael Tuexen break; 3774410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_REM_ABORTED: 3775fb4a67d2SMichael Tuexen if (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) || 3776fb4a67d2SMichael Tuexen ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED)) { 3777410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked); 3778410a3b1eSMichael Tuexen } else { 3779410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked); 3780c105859eSRandall Stewart } 3781f8829a4aSRandall Stewart break; 3782f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_RESTART: 3783410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked); 3784c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 0) { 3785830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 3786830d754dSRandall Stewart NULL, so_locked); 3787830d754dSRandall Stewart } 3788f8829a4aSRandall Stewart break; 3789f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_SEND: 3790d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_OUTGOING_SSN); 3791f8829a4aSRandall Stewart break; 3792f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_RECV: 3793d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_INCOMING); 3794f8829a4aSRandall Stewart break; 3795f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_OUT: 3796c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 3797d7714577SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED)); 3798f8829a4aSRandall Stewart break; 3799d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_OUT: 3800d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 3801d4260646SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED)); 3802d4260646SMichael Tuexen break; 3803f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_IN: 3804c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 3805d7714577SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED)); 3806f8829a4aSRandall Stewart break; 3807d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_IN: 3808d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 3809d4260646SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED)); 3810d4260646SMichael Tuexen break; 3811f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_ADD_IP: 3812f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, 38133cb3567dSMichael Tuexen error, so_locked); 3814f8829a4aSRandall Stewart break; 3815f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_DELETE_IP: 3816f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, 38173cb3567dSMichael Tuexen error, so_locked); 3818f8829a4aSRandall Stewart break; 3819f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_SET_PRIMARY: 3820f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data, 38213cb3567dSMichael Tuexen error, so_locked); 3822f8829a4aSRandall Stewart break; 3823f8829a4aSRandall Stewart case SCTP_NOTIFY_PEER_SHUTDOWN: 3824f8829a4aSRandall Stewart sctp_notify_shutdown_event(stcb); 3825f8829a4aSRandall Stewart break; 3826f8829a4aSRandall Stewart case SCTP_NOTIFY_AUTH_NEW_KEY: 382778f28045SMichael Tuexen sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error, 3828830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 3829830d754dSRandall Stewart so_locked); 3830f8829a4aSRandall Stewart break; 3831830d754dSRandall Stewart case SCTP_NOTIFY_AUTH_FREE_KEY: 3832830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, 3833830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 3834830d754dSRandall Stewart so_locked); 3835f8829a4aSRandall Stewart break; 3836830d754dSRandall Stewart case SCTP_NOTIFY_NO_PEER_AUTH: 3837830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, 3838830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 3839830d754dSRandall Stewart so_locked); 3840830d754dSRandall Stewart break; 3841830d754dSRandall Stewart case SCTP_NOTIFY_SENDER_DRY: 3842830d754dSRandall Stewart sctp_notify_sender_dry_event(stcb, so_locked); 3843830d754dSRandall Stewart break; 3844389b1b11SMichael Tuexen case SCTP_NOTIFY_REMOTE_ERROR: 3845389b1b11SMichael Tuexen sctp_notify_remote_error(stcb, error, data); 3846389b1b11SMichael Tuexen break; 3847f8829a4aSRandall Stewart default: 3848ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", 38496e9c45e0SMichael Tuexen __func__, notification, notification); 3850f8829a4aSRandall Stewart break; 3851f8829a4aSRandall Stewart } /* end switch */ 3852f8829a4aSRandall Stewart } 3853f8829a4aSRandall Stewart 3854f8829a4aSRandall Stewart void 38551edc9dbaSMichael Tuexen sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked 3856ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3857ceaad40aSRandall Stewart SCTP_UNUSED 3858ceaad40aSRandall Stewart #endif 3859ceaad40aSRandall Stewart ) 3860f8829a4aSRandall Stewart { 3861f8829a4aSRandall Stewart struct sctp_association *asoc; 3862f8829a4aSRandall Stewart struct sctp_stream_out *outs; 38634a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk; 38644a9ef3f8SMichael Tuexen struct sctp_stream_queue_pending *sp, *nsp; 38657f34832bSRandall Stewart int i; 3866f8829a4aSRandall Stewart 3867ad81507eSRandall Stewart if (stcb == NULL) { 3868ad81507eSRandall Stewart return; 3869ad81507eSRandall Stewart } 38704a9ef3f8SMichael Tuexen asoc = &stcb->asoc; 38714a9ef3f8SMichael Tuexen if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { 3872478fbccbSRandall Stewart /* already being freed */ 3873478fbccbSRandall Stewart return; 3874478fbccbSRandall Stewart } 3875f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3876f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 38774a9ef3f8SMichael Tuexen (asoc->state & SCTP_STATE_CLOSED_SOCKET)) { 3878f8829a4aSRandall Stewart return; 3879f8829a4aSRandall Stewart } 3880f8829a4aSRandall Stewart /* now through all the gunk freeing chunks */ 3881ad81507eSRandall Stewart if (holds_lock == 0) { 38827f34832bSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 3883ad81507eSRandall Stewart } 3884d00aff5dSRandall Stewart /* sent queue SHOULD be empty */ 38854a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { 3886d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); 3887d00aff5dSRandall Stewart asoc->sent_queue_cnt--; 3888325c8c46SMichael Tuexen if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { 388949656eefSMichael Tuexen if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { 389049656eefSMichael Tuexen asoc->strmout[chk->rec.data.sid].chunks_on_queues--; 3891a7ad6026SMichael Tuexen #ifdef INVARIANTS 3892a7ad6026SMichael Tuexen } else { 389349656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.sid); 3894a7ad6026SMichael Tuexen #endif 3895a7ad6026SMichael Tuexen } 3896a7ad6026SMichael Tuexen } 38970c0982b8SRandall Stewart if (chk->data != NULL) { 3898d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 38991edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 39001edc9dbaSMichael Tuexen error, chk, so_locked); 3901810ec536SMichael Tuexen if (chk->data) { 3902d00aff5dSRandall Stewart sctp_m_freem(chk->data); 3903d00aff5dSRandall Stewart chk->data = NULL; 3904d00aff5dSRandall Stewart } 3905810ec536SMichael Tuexen } 3906689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 3907d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 3908d00aff5dSRandall Stewart } 3909d00aff5dSRandall Stewart /* pending send queue SHOULD be empty */ 39104a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { 3911d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); 3912d00aff5dSRandall Stewart asoc->send_queue_cnt--; 391349656eefSMichael Tuexen if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { 391449656eefSMichael Tuexen asoc->strmout[chk->rec.data.sid].chunks_on_queues--; 3915a7ad6026SMichael Tuexen #ifdef INVARIANTS 3916a7ad6026SMichael Tuexen } else { 391749656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.sid); 3918a7ad6026SMichael Tuexen #endif 3919a7ad6026SMichael Tuexen } 39200c0982b8SRandall Stewart if (chk->data != NULL) { 3921d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 39221edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 39231edc9dbaSMichael Tuexen error, chk, so_locked); 3924810ec536SMichael Tuexen if (chk->data) { 3925d00aff5dSRandall Stewart sctp_m_freem(chk->data); 3926d00aff5dSRandall Stewart chk->data = NULL; 3927d00aff5dSRandall Stewart } 3928810ec536SMichael Tuexen } 3929689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 3930d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 3931d00aff5dSRandall Stewart } 39324a9ef3f8SMichael Tuexen for (i = 0; i < asoc->streamoutcnt; i++) { 39337f34832bSRandall Stewart /* For each stream */ 39344a9ef3f8SMichael Tuexen outs = &asoc->strmout[i]; 39357f34832bSRandall Stewart /* clean up any sends there */ 39364a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { 39374d58b0c3SMichael Tuexen atomic_subtract_int(&asoc->stream_queue_cnt, 1); 3938f8829a4aSRandall Stewart TAILQ_REMOVE(&outs->outqueue, sp, next); 39394d58b0c3SMichael Tuexen stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, holds_lock); 3940f8829a4aSRandall Stewart sctp_free_spbufspace(stcb, asoc, sp); 3941478fbccbSRandall Stewart if (sp->data) { 3942f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 39431edc9dbaSMichael Tuexen error, (void *)sp, so_locked); 3944f8829a4aSRandall Stewart if (sp->data) { 3945f8829a4aSRandall Stewart sctp_m_freem(sp->data); 3946f8829a4aSRandall Stewart sp->data = NULL; 3947d07b2ac6SMichael Tuexen sp->tail_mbuf = NULL; 3948d07b2ac6SMichael Tuexen sp->length = 0; 3949f8829a4aSRandall Stewart } 3950478fbccbSRandall Stewart } 39519eea4a2dSMichael Tuexen if (sp->net) { 3952f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 3953f8829a4aSRandall Stewart sp->net = NULL; 39549eea4a2dSMichael Tuexen } 3955f8829a4aSRandall Stewart /* Free the chunk */ 3956689e6a5fSMichael Tuexen sctp_free_a_strmoq(stcb, sp, so_locked); 39573c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 3958f8829a4aSRandall Stewart } 3959f8829a4aSRandall Stewart } 3960f8829a4aSRandall Stewart 3961ad81507eSRandall Stewart if (holds_lock == 0) { 39627f34832bSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 3963f8829a4aSRandall Stewart } 3964ad81507eSRandall Stewart } 3965f8829a4aSRandall Stewart 3966f8829a4aSRandall Stewart void 3967410a3b1eSMichael Tuexen sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error, 3968a2b42326SMichael Tuexen struct sctp_abort_chunk *abort, int so_locked 3969ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3970ceaad40aSRandall Stewart SCTP_UNUSED 3971ceaad40aSRandall Stewart #endif 3972ceaad40aSRandall Stewart ) 3973f8829a4aSRandall Stewart { 3974ad81507eSRandall Stewart if (stcb == NULL) { 3975ad81507eSRandall Stewart return; 3976ad81507eSRandall Stewart } 3977c55b70ceSMichael Tuexen if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3978c55b70ceSMichael Tuexen ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3979c55b70ceSMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { 3980c55b70ceSMichael Tuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; 3981c55b70ceSMichael Tuexen } 3982f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3983f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3984f8829a4aSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 3985f8829a4aSRandall Stewart return; 3986f8829a4aSRandall Stewart } 3987f8829a4aSRandall Stewart /* Tell them we lost the asoc */ 39881edc9dbaSMichael Tuexen sctp_report_all_outbound(stcb, error, 1, so_locked); 3989410a3b1eSMichael Tuexen if (from_peer) { 3990410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); 3991410a3b1eSMichael Tuexen } else { 3992410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); 3993410a3b1eSMichael Tuexen } 3994f8829a4aSRandall Stewart } 3995f8829a4aSRandall Stewart 3996f8829a4aSRandall Stewart void 3997f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 3998b1754ad1SMichael Tuexen struct mbuf *m, int iphlen, 3999b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4000b1754ad1SMichael Tuexen struct sctphdr *sh, struct mbuf *op_err, 4001457b4b88SMichael Tuexen uint8_t mflowtype, uint32_t mflowid, 4002c54a18d2SRandall Stewart uint32_t vrf_id, uint16_t port) 4003f8829a4aSRandall Stewart { 4004f8829a4aSRandall Stewart uint32_t vtag; 4005ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4006ceaad40aSRandall Stewart struct socket *so; 4007ceaad40aSRandall Stewart #endif 4008ceaad40aSRandall Stewart 4009f8829a4aSRandall Stewart vtag = 0; 4010f8829a4aSRandall Stewart if (stcb != NULL) { 4011f8829a4aSRandall Stewart vtag = stcb->asoc.peer_vtag; 401217205eccSRandall Stewart vrf_id = stcb->asoc.vrf_id; 4013f8829a4aSRandall Stewart } 4014b1754ad1SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, 4015d089f9b9SMichael Tuexen mflowtype, mflowid, inp->fibnum, 4016f30ac432SMichael Tuexen vrf_id, port); 4017f8829a4aSRandall Stewart if (stcb != NULL) { 4018884d8c53SMichael Tuexen /* We have a TCB to abort, send notification too */ 4019884d8c53SMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); 4020884d8c53SMichael Tuexen stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; 4021f8829a4aSRandall Stewart /* Ok, now lets free it */ 4022ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4023ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4024ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4025ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4026ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4027ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4028ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4029ceaad40aSRandall Stewart #endif 40300271d0cdSMichael Tuexen SCTP_STAT_INCR_COUNTER32(sctps_aborted); 40310271d0cdSMichael Tuexen if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 40320271d0cdSMichael Tuexen (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 40330271d0cdSMichael Tuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 40340271d0cdSMichael Tuexen } 4035ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 4036ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_4); 4037ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4038ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4039ceaad40aSRandall Stewart #endif 4040f8829a4aSRandall Stewart } 4041f8829a4aSRandall Stewart } 4042f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 4043f1f73e57SRandall Stewart void 4044f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb) 4045f1f73e57SRandall Stewart { 404618e198d3SRandall Stewart #ifdef NOSIY_PRINTS 4047f1f73e57SRandall Stewart int i; 4048f1f73e57SRandall Stewart 4049ad81507eSRandall Stewart SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code); 4050ad81507eSRandall Stewart SCTP_PRINTF("IN bound TSN log-aaa\n"); 4051f1f73e57SRandall Stewart if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) { 4052ad81507eSRandall Stewart SCTP_PRINTF("None rcvd\n"); 4053f1f73e57SRandall Stewart goto none_in; 4054f1f73e57SRandall Stewart } 4055f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_wrapped) { 4056f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) { 4057ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4058f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 4059f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 4060f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 4061f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 4062f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 4063f1f73e57SRandall Stewart } 4064f1f73e57SRandall Stewart } 4065f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_at) { 4066f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_in_at; i++) { 4067ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4068f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 4069f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 4070f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 4071f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 4072f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 4073f1f73e57SRandall Stewart } 4074f1f73e57SRandall Stewart } 4075f1f73e57SRandall Stewart none_in: 4076ad81507eSRandall Stewart SCTP_PRINTF("OUT bound TSN log-aaa\n"); 4077ad81507eSRandall Stewart if ((stcb->asoc.tsn_out_at == 0) && 4078ad81507eSRandall Stewart (stcb->asoc.tsn_out_wrapped == 0)) { 4079ad81507eSRandall Stewart SCTP_PRINTF("None sent\n"); 4080f1f73e57SRandall Stewart } 4081f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_wrapped) { 4082f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) { 4083ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4084f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 4085f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 4086f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 4087f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 4088f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 4089f1f73e57SRandall Stewart } 4090f1f73e57SRandall Stewart } 4091f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_at) { 4092f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_out_at; i++) { 4093ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4094f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 4095f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 4096f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 4097f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 4098f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 4099f1f73e57SRandall Stewart } 4100f1f73e57SRandall Stewart } 410118e198d3SRandall Stewart #endif 4102f1f73e57SRandall Stewart } 4103f1f73e57SRandall Stewart #endif 4104f1f73e57SRandall Stewart 4105f8829a4aSRandall Stewart void 4106f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 4107a2b42326SMichael Tuexen struct mbuf *op_err, 4108ceaad40aSRandall Stewart int so_locked 4109ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4110ceaad40aSRandall Stewart SCTP_UNUSED 4111ceaad40aSRandall Stewart #endif 4112ceaad40aSRandall Stewart ) 4113f8829a4aSRandall Stewart { 4114ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4115ceaad40aSRandall Stewart struct socket *so; 4116ceaad40aSRandall Stewart #endif 4117ceaad40aSRandall Stewart 4118ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4119ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4120ceaad40aSRandall Stewart #endif 4121f8829a4aSRandall Stewart if (stcb == NULL) { 4122f8829a4aSRandall Stewart /* Got to have a TCB */ 4123f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4124fe1831e0SMichael Tuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 4125b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4126b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4127f8829a4aSRandall Stewart } 4128f8829a4aSRandall Stewart } 4129f8829a4aSRandall Stewart return; 413063981c2bSRandall Stewart } else { 413163981c2bSRandall Stewart stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; 4132f8829a4aSRandall Stewart } 4133f8829a4aSRandall Stewart /* notify the peer */ 4134ceaad40aSRandall Stewart sctp_send_abort_tcb(stcb, op_err, so_locked); 4135f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_aborted); 4136f8829a4aSRandall Stewart if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 4137f8829a4aSRandall Stewart (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 4138f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 4139f8829a4aSRandall Stewart } 4140884d8c53SMichael Tuexen /* notify the ulp */ 4141884d8c53SMichael Tuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 4142884d8c53SMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, so_locked); 4143884d8c53SMichael Tuexen } 4144f8829a4aSRandall Stewart /* now free the asoc */ 4145f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 4146f1f73e57SRandall Stewart sctp_print_out_track_log(stcb); 4147f1f73e57SRandall Stewart #endif 4148ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4149ceaad40aSRandall Stewart if (!so_locked) { 4150ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4151ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4152ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4153ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4154ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4155ceaad40aSRandall Stewart } 4156ceaad40aSRandall Stewart #endif 4157ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 4158ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_5); 4159ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4160ceaad40aSRandall Stewart if (!so_locked) { 4161ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4162ceaad40aSRandall Stewart } 4163ceaad40aSRandall Stewart #endif 4164f8829a4aSRandall Stewart } 4165f8829a4aSRandall Stewart 4166f8829a4aSRandall Stewart void 4167b1754ad1SMichael Tuexen sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, 4168b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4169b1754ad1SMichael Tuexen struct sctphdr *sh, struct sctp_inpcb *inp, 4170ff1ffd74SMichael Tuexen struct mbuf *cause, 4171d089f9b9SMichael Tuexen uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, 4172f30ac432SMichael Tuexen uint32_t vrf_id, uint16_t port) 4173f8829a4aSRandall Stewart { 4174f8829a4aSRandall Stewart struct sctp_chunkhdr *ch, chunk_buf; 4175f8829a4aSRandall Stewart unsigned int chk_length; 4176c58e60beSMichael Tuexen int contains_init_chunk; 4177f8829a4aSRandall Stewart 4178f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue); 4179f8829a4aSRandall Stewart /* Generate a TO address for future reference */ 4180f8829a4aSRandall Stewart if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 4181fe1831e0SMichael Tuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 4182b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4183b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4184f8829a4aSRandall Stewart } 4185f8829a4aSRandall Stewart } 4186c58e60beSMichael Tuexen contains_init_chunk = 0; 4187f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4188f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4189f8829a4aSRandall Stewart while (ch != NULL) { 4190f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4191f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4192f8829a4aSRandall Stewart /* break to abort land */ 4193f8829a4aSRandall Stewart break; 4194f8829a4aSRandall Stewart } 4195f8829a4aSRandall Stewart switch (ch->chunk_type) { 4196c58e60beSMichael Tuexen case SCTP_INIT: 4197c58e60beSMichael Tuexen contains_init_chunk = 1; 4198c58e60beSMichael Tuexen break; 4199f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED: 4200f8829a4aSRandall Stewart /* we don't respond to pkt-dropped */ 4201f8829a4aSRandall Stewart return; 4202f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION: 4203f8829a4aSRandall Stewart /* we don't respond with an ABORT to an ABORT */ 4204f8829a4aSRandall Stewart return; 4205f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE: 4206f8829a4aSRandall Stewart /* 4207f8829a4aSRandall Stewart * we ignore it since we are not waiting for it and 4208f8829a4aSRandall Stewart * peer is gone 4209f8829a4aSRandall Stewart */ 4210f8829a4aSRandall Stewart return; 4211f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK: 4212b1754ad1SMichael Tuexen sctp_send_shutdown_complete2(src, dst, sh, 4213d089f9b9SMichael Tuexen mflowtype, mflowid, fibnum, 4214f30ac432SMichael Tuexen vrf_id, port); 4215f8829a4aSRandall Stewart return; 4216f8829a4aSRandall Stewart default: 4217f8829a4aSRandall Stewart break; 4218f8829a4aSRandall Stewart } 4219f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4220f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4221f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4222f8829a4aSRandall Stewart } 4223c58e60beSMichael Tuexen if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || 4224c58e60beSMichael Tuexen ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && 4225c58e60beSMichael Tuexen (contains_init_chunk == 0))) { 4226ff1ffd74SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, 0, cause, 4227d089f9b9SMichael Tuexen mflowtype, mflowid, fibnum, 4228f30ac432SMichael Tuexen vrf_id, port); 4229f8829a4aSRandall Stewart } 4230c58e60beSMichael Tuexen } 4231f8829a4aSRandall Stewart 4232f8829a4aSRandall Stewart /* 4233f8829a4aSRandall Stewart * check the inbound datagram to make sure there is not an abort inside it, 4234f8829a4aSRandall Stewart * if there is return 1, else return 0. 4235f8829a4aSRandall Stewart */ 4236f8829a4aSRandall Stewart int 4237f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtagfill) 4238f8829a4aSRandall Stewart { 4239f8829a4aSRandall Stewart struct sctp_chunkhdr *ch; 4240f8829a4aSRandall Stewart struct sctp_init_chunk *init_chk, chunk_buf; 4241f8829a4aSRandall Stewart int offset; 4242f8829a4aSRandall Stewart unsigned int chk_length; 4243f8829a4aSRandall Stewart 4244f8829a4aSRandall Stewart offset = iphlen + sizeof(struct sctphdr); 4245f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), 4246f8829a4aSRandall Stewart (uint8_t *)&chunk_buf); 4247f8829a4aSRandall Stewart while (ch != NULL) { 4248f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4249f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4250f8829a4aSRandall Stewart /* packet is probably corrupt */ 4251f8829a4aSRandall Stewart break; 4252f8829a4aSRandall Stewart } 4253f8829a4aSRandall Stewart /* we seem to be ok, is it an abort? */ 4254f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) { 4255f8829a4aSRandall Stewart /* yep, tell them */ 4256f8829a4aSRandall Stewart return (1); 4257f8829a4aSRandall Stewart } 4258f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_INITIATION) { 4259f8829a4aSRandall Stewart /* need to update the Vtag */ 4260f8829a4aSRandall Stewart init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 4261f8829a4aSRandall Stewart offset, sizeof(*init_chk), (uint8_t *)&chunk_buf); 4262f8829a4aSRandall Stewart if (init_chk != NULL) { 4263f8829a4aSRandall Stewart *vtagfill = ntohl(init_chk->init.initiate_tag); 4264f8829a4aSRandall Stewart } 4265f8829a4aSRandall Stewart } 4266f8829a4aSRandall Stewart /* Nope, move to the next chunk */ 4267f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4268f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4269f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4270f8829a4aSRandall Stewart } 4271f8829a4aSRandall Stewart return (0); 4272f8829a4aSRandall Stewart } 4273f8829a4aSRandall Stewart 4274f8829a4aSRandall Stewart /* 4275f8829a4aSRandall Stewart * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id 4276f8829a4aSRandall Stewart * set (i.e. it's 0) so, create this function to compare link local scopes 4277f8829a4aSRandall Stewart */ 42785e2c2d87SRandall Stewart #ifdef INET6 4279f8829a4aSRandall Stewart uint32_t 4280*b0471b4bSMichael Tuexen sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2) 4281*b0471b4bSMichael Tuexen { 4282f8829a4aSRandall Stewart struct sockaddr_in6 a, b; 4283f8829a4aSRandall Stewart 4284f8829a4aSRandall Stewart /* save copies */ 4285f8829a4aSRandall Stewart a = *addr1; 4286f8829a4aSRandall Stewart b = *addr2; 4287f8829a4aSRandall Stewart 4288f8829a4aSRandall Stewart if (a.sin6_scope_id == 0) 4289f8829a4aSRandall Stewart if (sa6_recoverscope(&a)) { 4290f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4291f8829a4aSRandall Stewart return (0); 4292f8829a4aSRandall Stewart } 4293f8829a4aSRandall Stewart if (b.sin6_scope_id == 0) 4294f8829a4aSRandall Stewart if (sa6_recoverscope(&b)) { 4295f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4296f8829a4aSRandall Stewart return (0); 4297f8829a4aSRandall Stewart } 4298f8829a4aSRandall Stewart if (a.sin6_scope_id != b.sin6_scope_id) 4299f8829a4aSRandall Stewart return (0); 4300f8829a4aSRandall Stewart 4301f8829a4aSRandall Stewart return (1); 4302f8829a4aSRandall Stewart } 4303f8829a4aSRandall Stewart 4304f8829a4aSRandall Stewart /* 4305f8829a4aSRandall Stewart * returns a sockaddr_in6 with embedded scope recovered and removed 4306f8829a4aSRandall Stewart */ 4307f8829a4aSRandall Stewart struct sockaddr_in6 * 4308f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store) 4309f8829a4aSRandall Stewart { 4310f8829a4aSRandall Stewart /* check and strip embedded scope junk */ 4311f8829a4aSRandall Stewart if (addr->sin6_family == AF_INET6) { 4312f8829a4aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) { 4313f8829a4aSRandall Stewart if (addr->sin6_scope_id == 0) { 4314f8829a4aSRandall Stewart *store = *addr; 4315f8829a4aSRandall Stewart if (!sa6_recoverscope(store)) { 4316f8829a4aSRandall Stewart /* use the recovered scope */ 4317f8829a4aSRandall Stewart addr = store; 4318f8829a4aSRandall Stewart } 4319f42a358aSRandall Stewart } else { 4320f8829a4aSRandall Stewart /* else, return the original "to" addr */ 4321f42a358aSRandall Stewart in6_clearscope(&addr->sin6_addr); 4322f8829a4aSRandall Stewart } 4323f8829a4aSRandall Stewart } 4324f8829a4aSRandall Stewart } 4325f8829a4aSRandall Stewart return (addr); 4326f8829a4aSRandall Stewart } 43275e2c2d87SRandall Stewart #endif 43285e2c2d87SRandall Stewart 4329f8829a4aSRandall Stewart /* 4330f8829a4aSRandall Stewart * are the two addresses the same? currently a "scopeless" check returns: 1 4331f8829a4aSRandall Stewart * if same, 0 if not 4332f8829a4aSRandall Stewart */ 433372fb6fdbSRandall Stewart int 4334f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2) 4335f8829a4aSRandall Stewart { 4336f8829a4aSRandall Stewart 4337f8829a4aSRandall Stewart /* must be valid */ 4338f8829a4aSRandall Stewart if (sa1 == NULL || sa2 == NULL) 4339f8829a4aSRandall Stewart return (0); 4340f8829a4aSRandall Stewart 4341f8829a4aSRandall Stewart /* must be the same family */ 4342f8829a4aSRandall Stewart if (sa1->sa_family != sa2->sa_family) 4343f8829a4aSRandall Stewart return (0); 4344f8829a4aSRandall Stewart 43455e2c2d87SRandall Stewart switch (sa1->sa_family) { 43465e2c2d87SRandall Stewart #ifdef INET6 43475e2c2d87SRandall Stewart case AF_INET6: 43485e2c2d87SRandall Stewart { 4349f8829a4aSRandall Stewart /* IPv6 addresses */ 4350f8829a4aSRandall Stewart struct sockaddr_in6 *sin6_1, *sin6_2; 4351f8829a4aSRandall Stewart 4352f8829a4aSRandall Stewart sin6_1 = (struct sockaddr_in6 *)sa1; 4353f8829a4aSRandall Stewart sin6_2 = (struct sockaddr_in6 *)sa2; 4354c54a18d2SRandall Stewart return (SCTP6_ARE_ADDR_EQUAL(sin6_1, 4355c54a18d2SRandall Stewart sin6_2)); 43565e2c2d87SRandall Stewart } 43575e2c2d87SRandall Stewart #endif 4358ea5eba11SMichael Tuexen #ifdef INET 43595e2c2d87SRandall Stewart case AF_INET: 43605e2c2d87SRandall Stewart { 4361f8829a4aSRandall Stewart /* IPv4 addresses */ 4362f8829a4aSRandall Stewart struct sockaddr_in *sin_1, *sin_2; 4363f8829a4aSRandall Stewart 4364f8829a4aSRandall Stewart sin_1 = (struct sockaddr_in *)sa1; 4365f8829a4aSRandall Stewart sin_2 = (struct sockaddr_in *)sa2; 4366f8829a4aSRandall Stewart return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr); 43675e2c2d87SRandall Stewart } 4368ea5eba11SMichael Tuexen #endif 43695e2c2d87SRandall Stewart default: 4370f8829a4aSRandall Stewart /* we don't do these... */ 4371f8829a4aSRandall Stewart return (0); 4372f8829a4aSRandall Stewart } 4373f8829a4aSRandall Stewart } 4374f8829a4aSRandall Stewart 4375f8829a4aSRandall Stewart void 4376f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa) 4377f8829a4aSRandall Stewart { 43785e2c2d87SRandall Stewart #ifdef INET6 43797d32aa0cSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 43805e2c2d87SRandall Stewart #endif 43815e2c2d87SRandall Stewart 43825e2c2d87SRandall Stewart switch (sa->sa_family) { 43835e2c2d87SRandall Stewart #ifdef INET6 43845e2c2d87SRandall Stewart case AF_INET6: 43855e2c2d87SRandall Stewart { 4386ad81507eSRandall Stewart struct sockaddr_in6 *sin6; 4387ad81507eSRandall Stewart 4388f8829a4aSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 4389ad81507eSRandall Stewart SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", 43907d32aa0cSBjoern A. Zeeb ip6_sprintf(ip6buf, &sin6->sin6_addr), 43917d32aa0cSBjoern A. Zeeb ntohs(sin6->sin6_port), 4392f8829a4aSRandall Stewart sin6->sin6_scope_id); 43935e2c2d87SRandall Stewart break; 43945e2c2d87SRandall Stewart } 43955e2c2d87SRandall Stewart #endif 4396ea5eba11SMichael Tuexen #ifdef INET 43975e2c2d87SRandall Stewart case AF_INET: 43985e2c2d87SRandall Stewart { 4399f8829a4aSRandall Stewart struct sockaddr_in *sin; 4400f8829a4aSRandall Stewart unsigned char *p; 4401f8829a4aSRandall Stewart 4402f8829a4aSRandall Stewart sin = (struct sockaddr_in *)sa; 4403f8829a4aSRandall Stewart p = (unsigned char *)&sin->sin_addr; 4404ad81507eSRandall Stewart SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n", 4405f8829a4aSRandall Stewart p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); 44065e2c2d87SRandall Stewart break; 44075e2c2d87SRandall Stewart } 4408ea5eba11SMichael Tuexen #endif 44095e2c2d87SRandall Stewart default: 4410ad81507eSRandall Stewart SCTP_PRINTF("?\n"); 44115e2c2d87SRandall Stewart break; 4412f8829a4aSRandall Stewart } 4413f8829a4aSRandall Stewart } 4414f8829a4aSRandall Stewart 4415f8829a4aSRandall Stewart void 4416f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, 4417f8829a4aSRandall Stewart struct sctp_inpcb *new_inp, 4418d06c82f1SRandall Stewart struct sctp_tcb *stcb, 4419d06c82f1SRandall Stewart int waitflags) 4420f8829a4aSRandall Stewart { 4421f8829a4aSRandall Stewart /* 4422f8829a4aSRandall Stewart * go through our old INP and pull off any control structures that 4423f8829a4aSRandall Stewart * belong to stcb and move then to the new inp. 4424f8829a4aSRandall Stewart */ 4425f8829a4aSRandall Stewart struct socket *old_so, *new_so; 4426f8829a4aSRandall Stewart struct sctp_queued_to_read *control, *nctl; 4427f8829a4aSRandall Stewart struct sctp_readhead tmp_queue; 4428f8829a4aSRandall Stewart struct mbuf *m; 4429bff64a4dSRandall Stewart int error = 0; 4430f8829a4aSRandall Stewart 4431f8829a4aSRandall Stewart old_so = old_inp->sctp_socket; 4432f8829a4aSRandall Stewart new_so = new_inp->sctp_socket; 4433f8829a4aSRandall Stewart TAILQ_INIT(&tmp_queue); 4434d06c82f1SRandall Stewart error = sblock(&old_so->so_rcv, waitflags); 4435f8829a4aSRandall Stewart if (error) { 4436f8829a4aSRandall Stewart /* 4437f8829a4aSRandall Stewart * Gak, can't get sblock, we have a problem. data will be 4438f8829a4aSRandall Stewart * left stranded.. and we don't dare look at it since the 4439f8829a4aSRandall Stewart * other thread may be reading something. Oh well, its a 4440f8829a4aSRandall Stewart * screwed up app that does a peeloff OR a accept while 4441f8829a4aSRandall Stewart * reading from the main socket... actually its only the 4442f8829a4aSRandall Stewart * peeloff() case, since I think read will fail on a 4443f8829a4aSRandall Stewart * listening socket.. 4444f8829a4aSRandall Stewart */ 4445f8829a4aSRandall Stewart return; 4446f8829a4aSRandall Stewart } 4447f8829a4aSRandall Stewart /* lock the socket buffers */ 4448f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(old_inp); 44494a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) { 4450f8829a4aSRandall Stewart /* Pull off all for out target stcb */ 4451f8829a4aSRandall Stewart if (control->stcb == stcb) { 4452f8829a4aSRandall Stewart /* remove it we want it */ 4453f8829a4aSRandall Stewart TAILQ_REMOVE(&old_inp->read_queue, control, next); 4454f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&tmp_queue, control, next); 4455f8829a4aSRandall Stewart m = control->data; 4456f8829a4aSRandall Stewart while (m) { 4457b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4458139bc87fSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 445980fefe0aSRandall Stewart } 4460f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &old_so->so_rcv, m); 4461b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4462f8829a4aSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 446380fefe0aSRandall Stewart } 4464139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4465f8829a4aSRandall Stewart } 4466f8829a4aSRandall Stewart } 4467f8829a4aSRandall Stewart } 4468f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(old_inp); 4469f8829a4aSRandall Stewart /* Remove the sb-lock on the old socket */ 4470f8829a4aSRandall Stewart 4471f8829a4aSRandall Stewart sbunlock(&old_so->so_rcv); 4472f8829a4aSRandall Stewart /* Now we move them over to the new socket buffer */ 4473f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(new_inp); 44744a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) { 4475f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next); 4476f8829a4aSRandall Stewart m = control->data; 4477f8829a4aSRandall Stewart while (m) { 4478b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4479139bc87fSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 448080fefe0aSRandall Stewart } 4481f8829a4aSRandall Stewart sctp_sballoc(stcb, &new_so->so_rcv, m); 4482b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4483f8829a4aSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 448480fefe0aSRandall Stewart } 4485139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4486f8829a4aSRandall Stewart } 4487f8829a4aSRandall Stewart } 4488f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(new_inp); 4489f8829a4aSRandall Stewart } 4490f8829a4aSRandall Stewart 4491f8829a4aSRandall Stewart void 4492b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, 4493b1deed45SMichael Tuexen struct sctp_tcb *stcb, 4494b1deed45SMichael Tuexen int so_locked 4495b1deed45SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4496b1deed45SMichael Tuexen SCTP_UNUSED 4497b1deed45SMichael Tuexen #endif 4498b1deed45SMichael Tuexen ) 449944249214SRandall Stewart { 4500b1deed45SMichael Tuexen if ((inp != NULL) && (inp->sctp_socket != NULL)) { 450144249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 450244249214SRandall Stewart struct socket *so; 450344249214SRandall Stewart 450444249214SRandall Stewart so = SCTP_INP_SO(inp); 450544249214SRandall Stewart if (!so_locked) { 450644249214SRandall Stewart if (stcb) { 450744249214SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 450844249214SRandall Stewart SCTP_TCB_UNLOCK(stcb); 450944249214SRandall Stewart } 451044249214SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 451144249214SRandall Stewart if (stcb) { 451244249214SRandall Stewart SCTP_TCB_LOCK(stcb); 451344249214SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 451444249214SRandall Stewart } 451544249214SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 451644249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 451744249214SRandall Stewart return; 451844249214SRandall Stewart } 451944249214SRandall Stewart } 452044249214SRandall Stewart #endif 452144249214SRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 452244249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 452344249214SRandall Stewart if (!so_locked) { 452444249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 452544249214SRandall Stewart } 452644249214SRandall Stewart #endif 452744249214SRandall Stewart } 452844249214SRandall Stewart } 452944249214SRandall Stewart 453044249214SRandall Stewart void 4531f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp, 4532f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4533f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4534f8829a4aSRandall Stewart struct sockbuf *sb, 4535ceaad40aSRandall Stewart int end, 4536cfde3ff7SRandall Stewart int inp_read_lock_held, 4537ceaad40aSRandall Stewart int so_locked 4538ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4539ceaad40aSRandall Stewart SCTP_UNUSED 4540ceaad40aSRandall Stewart #endif 4541ceaad40aSRandall Stewart ) 4542f8829a4aSRandall Stewart { 4543f8829a4aSRandall Stewart /* 4544f8829a4aSRandall Stewart * Here we must place the control on the end of the socket read 45454e88d37aSMichael Tuexen * queue AND increment sb_cc so that select will work properly on 4546f8829a4aSRandall Stewart * read. 4547f8829a4aSRandall Stewart */ 4548f8829a4aSRandall Stewart struct mbuf *m, *prev = NULL; 4549f8829a4aSRandall Stewart 455003b0b021SRandall Stewart if (inp == NULL) { 455103b0b021SRandall Stewart /* Gak, TSNH!! */ 4552a5d547adSRandall Stewart #ifdef INVARIANTS 455303b0b021SRandall Stewart panic("Gak, inp NULL on add_to_readq"); 455403b0b021SRandall Stewart #endif 455503b0b021SRandall Stewart return; 455603b0b021SRandall Stewart } 4557cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4558f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4559cd1386abSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 4560cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4561cd1386abSMichael Tuexen if (control->data) { 4562cd1386abSMichael Tuexen sctp_m_freem(control->data); 4563cd1386abSMichael Tuexen control->data = NULL; 4564cd1386abSMichael Tuexen } 456544249214SRandall Stewart sctp_free_a_readq(stcb, control); 4566cd1386abSMichael Tuexen if (inp_read_lock_held == 0) 4567cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4568cd1386abSMichael Tuexen return; 4569cd1386abSMichael Tuexen } 457042551e99SRandall Stewart if (!(control->spec_flags & M_NOTIFICATION)) { 4571a5d547adSRandall Stewart atomic_add_int(&inp->total_recvs, 1); 457242551e99SRandall Stewart if (!control->do_not_ref_stcb) { 4573a5d547adSRandall Stewart atomic_add_int(&stcb->total_recvs, 1); 457442551e99SRandall Stewart } 457542551e99SRandall Stewart } 4576f8829a4aSRandall Stewart m = control->data; 4577f8829a4aSRandall Stewart control->held_length = 0; 4578f8829a4aSRandall Stewart control->length = 0; 4579f8829a4aSRandall Stewart while (m) { 4580139bc87fSRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 4581f8829a4aSRandall Stewart /* Skip mbufs with NO length */ 4582f8829a4aSRandall Stewart if (prev == NULL) { 4583f8829a4aSRandall Stewart /* First one */ 4584f8829a4aSRandall Stewart control->data = sctp_m_free(m); 4585f8829a4aSRandall Stewart m = control->data; 4586f8829a4aSRandall Stewart } else { 4587139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 4588139bc87fSRandall Stewart m = SCTP_BUF_NEXT(prev); 4589f8829a4aSRandall Stewart } 4590f8829a4aSRandall Stewart if (m == NULL) { 4591c2ede4b3SMartin Blapp control->tail_mbuf = prev; 4592f8829a4aSRandall Stewart } 4593f8829a4aSRandall Stewart continue; 4594f8829a4aSRandall Stewart } 4595f8829a4aSRandall Stewart prev = m; 4596b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4597139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 459880fefe0aSRandall Stewart } 4599f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, m); 4600b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4601f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 460280fefe0aSRandall Stewart } 4603139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 4604139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4605f8829a4aSRandall Stewart } 4606f8829a4aSRandall Stewart if (prev != NULL) { 4607f8829a4aSRandall Stewart control->tail_mbuf = prev; 4608f8829a4aSRandall Stewart } else { 4609139bc87fSRandall Stewart /* Everything got collapsed out?? */ 4610cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 461144249214SRandall Stewart sctp_free_a_readq(stcb, control); 4612cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 461347a490cbSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4614f8829a4aSRandall Stewart return; 4615f8829a4aSRandall Stewart } 4616f8829a4aSRandall Stewart if (end) { 4617f8829a4aSRandall Stewart control->end_added = 1; 4618f8829a4aSRandall Stewart } 4619f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&inp->read_queue, control, next); 462044249214SRandall Stewart control->on_read_q = 1; 4621cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4622f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4623f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 4624b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(inp, stcb, so_locked); 4625f8829a4aSRandall Stewart } 4626f8829a4aSRandall Stewart } 4627f8829a4aSRandall Stewart 4628f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF 4629f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4630f8829a4aSRandall Stewart */ 4631f8829a4aSRandall Stewart 4632f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF 4633f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4634f8829a4aSRandall Stewart */ 4635f8829a4aSRandall Stewart 4636f8829a4aSRandall Stewart struct mbuf * 4637ff1ffd74SMichael Tuexen sctp_generate_cause(uint16_t code, char *info) 4638f8829a4aSRandall Stewart { 4639f8829a4aSRandall Stewart struct mbuf *m; 4640ff1ffd74SMichael Tuexen struct sctp_gen_error_cause *cause; 46419a8e3088SMichael Tuexen size_t info_len; 46429a8e3088SMichael Tuexen uint16_t len; 4643f8829a4aSRandall Stewart 4644ff1ffd74SMichael Tuexen if ((code == 0) || (info == NULL)) { 4645ff1ffd74SMichael Tuexen return (NULL); 4646ff1ffd74SMichael Tuexen } 4647ff1ffd74SMichael Tuexen info_len = strlen(info); 46489a8e3088SMichael Tuexen if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) { 46499a8e3088SMichael Tuexen return (NULL); 46509a8e3088SMichael Tuexen } 46519a8e3088SMichael Tuexen len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len); 4652ff1ffd74SMichael Tuexen m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); 4653ff1ffd74SMichael Tuexen if (m != NULL) { 4654ff1ffd74SMichael Tuexen SCTP_BUF_LEN(m) = len; 4655ff1ffd74SMichael Tuexen cause = mtod(m, struct sctp_gen_error_cause *); 4656ff1ffd74SMichael Tuexen cause->code = htons(code); 46579a8e3088SMichael Tuexen cause->length = htons(len); 4658ff1ffd74SMichael Tuexen memcpy(cause->info, info, info_len); 4659f8829a4aSRandall Stewart } 4660f8829a4aSRandall Stewart return (m); 4661f8829a4aSRandall Stewart } 4662f8829a4aSRandall Stewart 466332451da4SMichael Tuexen struct mbuf * 466432451da4SMichael Tuexen sctp_generate_no_user_data_cause(uint32_t tsn) 466532451da4SMichael Tuexen { 466632451da4SMichael Tuexen struct mbuf *m; 466732451da4SMichael Tuexen struct sctp_error_no_user_data *no_user_data_cause; 46689a8e3088SMichael Tuexen uint16_t len; 466932451da4SMichael Tuexen 46709a8e3088SMichael Tuexen len = (uint16_t)sizeof(struct sctp_error_no_user_data); 467132451da4SMichael Tuexen m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); 467232451da4SMichael Tuexen if (m != NULL) { 467332451da4SMichael Tuexen SCTP_BUF_LEN(m) = len; 467432451da4SMichael Tuexen no_user_data_cause = mtod(m, struct sctp_error_no_user_data *); 467532451da4SMichael Tuexen no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA); 46769a8e3088SMichael Tuexen no_user_data_cause->cause.length = htons(len); 46778b9c95f4SMichael Tuexen no_user_data_cause->tsn = htonl(tsn); 467832451da4SMichael Tuexen } 467932451da4SMichael Tuexen return (m); 468032451da4SMichael Tuexen } 468132451da4SMichael Tuexen 4682f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING 4683f8829a4aSRandall Stewart void 4684f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, 4685f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, int chk_cnt) 4686f8829a4aSRandall Stewart { 4687f8829a4aSRandall Stewart if (tp1->data == NULL) { 4688f8829a4aSRandall Stewart return; 4689f8829a4aSRandall Stewart } 4690f8829a4aSRandall Stewart asoc->chunks_on_out_queue -= chk_cnt; 4691b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { 4692f8829a4aSRandall Stewart sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, 4693f8829a4aSRandall Stewart asoc->total_output_queue_size, 4694f8829a4aSRandall Stewart tp1->book_size, 4695f8829a4aSRandall Stewart 0, 4696f8829a4aSRandall Stewart tp1->mbcnt); 469780fefe0aSRandall Stewart } 4698f8829a4aSRandall Stewart if (asoc->total_output_queue_size >= tp1->book_size) { 469944b7479bSRandall Stewart atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size); 4700f8829a4aSRandall Stewart } else { 4701f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 4702f8829a4aSRandall Stewart } 4703f8829a4aSRandall Stewart 4704f8829a4aSRandall Stewart if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || 4705f8829a4aSRandall Stewart ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { 47064e88d37aSMichael Tuexen if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { 47074e88d37aSMichael Tuexen stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size; 4708f8829a4aSRandall Stewart } else { 47094e88d37aSMichael Tuexen stcb->sctp_socket->so_snd.sb_cc = 0; 4710f8829a4aSRandall Stewart 4711f8829a4aSRandall Stewart } 4712f8829a4aSRandall Stewart } 4713f8829a4aSRandall Stewart } 4714f8829a4aSRandall Stewart 4715f8829a4aSRandall Stewart #endif 4716f8829a4aSRandall Stewart 4717f8829a4aSRandall Stewart int 4718f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, 47191edc9dbaSMichael Tuexen uint8_t sent, int so_locked 4720ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4721ceaad40aSRandall Stewart SCTP_UNUSED 4722ceaad40aSRandall Stewart #endif 4723ceaad40aSRandall Stewart ) 4724f8829a4aSRandall Stewart { 47250c0982b8SRandall Stewart struct sctp_stream_out *strq; 47264a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk = NULL, *tp2; 47270c0982b8SRandall Stewart struct sctp_stream_queue_pending *sp; 472849656eefSMichael Tuexen uint32_t mid; 472949656eefSMichael Tuexen uint16_t sid; 47300c0982b8SRandall Stewart uint8_t foundeom = 0; 4731f8829a4aSRandall Stewart int ret_sz = 0; 4732f8829a4aSRandall Stewart int notdone; 47330c0982b8SRandall Stewart int do_wakeup_routine = 0; 4734f8829a4aSRandall Stewart 473549656eefSMichael Tuexen sid = tp1->rec.data.sid; 473649656eefSMichael Tuexen mid = tp1->rec.data.mid; 4737f0396ad1SMichael Tuexen if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { 4738f0396ad1SMichael Tuexen stcb->asoc.abandoned_sent[0]++; 4739f0396ad1SMichael Tuexen stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; 474049656eefSMichael Tuexen stcb->asoc.strmout[sid].abandoned_sent[0]++; 4741f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 4742ad15e154SMichael Tuexen stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; 4743f0396ad1SMichael Tuexen #endif 4744f0396ad1SMichael Tuexen } else { 4745f0396ad1SMichael Tuexen stcb->asoc.abandoned_unsent[0]++; 4746f0396ad1SMichael Tuexen stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; 474749656eefSMichael Tuexen stcb->asoc.strmout[sid].abandoned_unsent[0]++; 4748f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 4749ad15e154SMichael Tuexen stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; 4750f0396ad1SMichael Tuexen #endif 4751f0396ad1SMichael Tuexen } 4752f8829a4aSRandall Stewart do { 4753f8829a4aSRandall Stewart ret_sz += tp1->book_size; 47540c0982b8SRandall Stewart if (tp1->data != NULL) { 47558933fa13SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 4756830d754dSRandall Stewart sctp_flight_size_decrease(tp1); 4757830d754dSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 47588933fa13SRandall Stewart } 47598933fa13SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 47600c0982b8SRandall Stewart stcb->asoc.peers_rwnd += tp1->send_size; 47610c0982b8SRandall Stewart stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); 47621edc9dbaSMichael Tuexen if (sent) { 47631edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 47641edc9dbaSMichael Tuexen } else { 47651edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 47661edc9dbaSMichael Tuexen } 47672f99457bSMichael Tuexen if (tp1->data) { 4768f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 4769f8829a4aSRandall Stewart tp1->data = NULL; 47702f99457bSMichael Tuexen } 47710c0982b8SRandall Stewart do_wakeup_routine = 1; 4772f8829a4aSRandall Stewart if (PR_SCTP_BUF_ENABLED(tp1->flags)) { 4773f8829a4aSRandall Stewart stcb->asoc.sent_queue_cnt_removeable--; 4774f8829a4aSRandall Stewart } 4775f8829a4aSRandall Stewart } 47768933fa13SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 4777f8829a4aSRandall Stewart if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 4778f8829a4aSRandall Stewart SCTP_DATA_NOT_FRAG) { 4779f8829a4aSRandall Stewart /* not frag'ed we ae done */ 4780f8829a4aSRandall Stewart notdone = 0; 4781f8829a4aSRandall Stewart foundeom = 1; 4782f8829a4aSRandall Stewart } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 4783f8829a4aSRandall Stewart /* end of frag, we are done */ 4784f8829a4aSRandall Stewart notdone = 0; 4785f8829a4aSRandall Stewart foundeom = 1; 4786f8829a4aSRandall Stewart } else { 4787f8829a4aSRandall Stewart /* 4788f8829a4aSRandall Stewart * Its a begin or middle piece, we must mark all of 4789f8829a4aSRandall Stewart * it 4790f8829a4aSRandall Stewart */ 4791f8829a4aSRandall Stewart notdone = 1; 4792f8829a4aSRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next); 4793f8829a4aSRandall Stewart } 4794f8829a4aSRandall Stewart } while (tp1 && notdone); 47950c0982b8SRandall Stewart if (foundeom == 0) { 4796f8829a4aSRandall Stewart /* 4797f8829a4aSRandall Stewart * The multi-part message was scattered across the send and 4798f8829a4aSRandall Stewart * sent queue. 4799f8829a4aSRandall Stewart */ 48004a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) { 480149656eefSMichael Tuexen if ((tp1->rec.data.sid != sid) || 480249656eefSMichael Tuexen (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) { 48034a9ef3f8SMichael Tuexen break; 48044a9ef3f8SMichael Tuexen } 48050c0982b8SRandall Stewart /* 48060c0982b8SRandall Stewart * save to chk in case we have some on stream out 48070c0982b8SRandall Stewart * queue. If so and we have an un-transmitted one we 48080c0982b8SRandall Stewart * don't have to fudge the TSN. 48090c0982b8SRandall Stewart */ 48100c0982b8SRandall Stewart chk = tp1; 48110c0982b8SRandall Stewart ret_sz += tp1->book_size; 48120c0982b8SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 48131edc9dbaSMichael Tuexen if (sent) { 48141edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 48151edc9dbaSMichael Tuexen } else { 48161edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 48171edc9dbaSMichael Tuexen } 48182f99457bSMichael Tuexen if (tp1->data) { 48190c0982b8SRandall Stewart sctp_m_freem(tp1->data); 48202f99457bSMichael Tuexen tp1->data = NULL; 48212f99457bSMichael Tuexen } 48228933fa13SRandall Stewart /* No flight involved here book the size to 0 */ 48238933fa13SRandall Stewart tp1->book_size = 0; 48240c0982b8SRandall Stewart if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 48250c0982b8SRandall Stewart foundeom = 1; 4826f8829a4aSRandall Stewart } 48270c0982b8SRandall Stewart do_wakeup_routine = 1; 48280c0982b8SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 48290c0982b8SRandall Stewart TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next); 4830b7b84c0eSMichael Tuexen /* 4831b7b84c0eSMichael Tuexen * on to the sent queue so we can wait for it to be 4832b7b84c0eSMichael Tuexen * passed by. 4833b7b84c0eSMichael Tuexen */ 48340c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1, 48350c0982b8SRandall Stewart sctp_next); 48360c0982b8SRandall Stewart stcb->asoc.send_queue_cnt--; 48370c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 48380c0982b8SRandall Stewart } 48390c0982b8SRandall Stewart } 48400c0982b8SRandall Stewart if (foundeom == 0) { 48410c0982b8SRandall Stewart /* 48420c0982b8SRandall Stewart * Still no eom found. That means there is stuff left on the 48430c0982b8SRandall Stewart * stream out queue.. yuck. 48440c0982b8SRandall Stewart */ 48450c0982b8SRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 484649656eefSMichael Tuexen strq = &stcb->asoc.strmout[sid]; 4847f3b05218SMichael Tuexen sp = TAILQ_FIRST(&strq->outqueue); 4848f3b05218SMichael Tuexen if (sp != NULL) { 48490c0982b8SRandall Stewart sp->discard_rest = 1; 48500c0982b8SRandall Stewart /* 4851f3b05218SMichael Tuexen * We may need to put a chunk on the queue that 4852f3b05218SMichael Tuexen * holds the TSN that would have been sent with the 4853f3b05218SMichael Tuexen * LAST bit. 48540c0982b8SRandall Stewart */ 48550c0982b8SRandall Stewart if (chk == NULL) { 48560c0982b8SRandall Stewart /* Yep, we have to */ 48570c0982b8SRandall Stewart sctp_alloc_a_chunk(stcb, chk); 48580c0982b8SRandall Stewart if (chk == NULL) { 48590c0982b8SRandall Stewart /* 4860f3b05218SMichael Tuexen * we are hosed. All we can do is 4861f3b05218SMichael Tuexen * nothing.. which will cause an 4862f3b05218SMichael Tuexen * abort if the peer is paying 48630c0982b8SRandall Stewart * attention. 48640c0982b8SRandall Stewart */ 48650c0982b8SRandall Stewart goto oh_well; 48660c0982b8SRandall Stewart } 48670c0982b8SRandall Stewart memset(chk, 0, sizeof(*chk)); 486863d5b568SMichael Tuexen chk->rec.data.rcv_flags = 0; 48690c0982b8SRandall Stewart chk->sent = SCTP_FORWARD_TSN_SKIP; 48700c0982b8SRandall Stewart chk->asoc = &stcb->asoc; 487163d5b568SMichael Tuexen if (stcb->asoc.idata_supported == 0) { 487263d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 487349656eefSMichael Tuexen chk->rec.data.mid = 0; 487463d5b568SMichael Tuexen } else { 487549656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_ordered; 487663d5b568SMichael Tuexen } 487763d5b568SMichael Tuexen } else { 487863d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 487949656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_unordered; 488063d5b568SMichael Tuexen } else { 488149656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_ordered; 488263d5b568SMichael Tuexen } 488363d5b568SMichael Tuexen } 488449656eefSMichael Tuexen chk->rec.data.sid = sp->sid; 488549656eefSMichael Tuexen chk->rec.data.ppid = sp->ppid; 48860c0982b8SRandall Stewart chk->rec.data.context = sp->context; 48870c0982b8SRandall Stewart chk->flags = sp->act_flags; 48887fd5b436SMichael Tuexen chk->whoTo = NULL; 488949656eefSMichael Tuexen chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); 48907fd5b436SMichael Tuexen strq->chunks_on_queues++; 48910c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); 48920c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 48938933fa13SRandall Stewart stcb->asoc.pr_sctp_cnt++; 48940c0982b8SRandall Stewart } 489563d5b568SMichael Tuexen chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; 4896d1ea5fa9SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 4897d1ea5fa9SMichael Tuexen chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED; 4898d1ea5fa9SMichael Tuexen } 489963d5b568SMichael Tuexen if (stcb->asoc.idata_supported == 0) { 490063d5b568SMichael Tuexen if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) { 490163d5b568SMichael Tuexen strq->next_mid_ordered++; 490263d5b568SMichael Tuexen } 490363d5b568SMichael Tuexen } else { 490463d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 490563d5b568SMichael Tuexen strq->next_mid_unordered++; 490663d5b568SMichael Tuexen } else { 490763d5b568SMichael Tuexen strq->next_mid_ordered++; 490863d5b568SMichael Tuexen } 490963d5b568SMichael Tuexen } 49100c0982b8SRandall Stewart oh_well: 49110c0982b8SRandall Stewart if (sp->data) { 49120c0982b8SRandall Stewart /* 4913f3b05218SMichael Tuexen * Pull any data to free up the SB and allow 4914f3b05218SMichael Tuexen * sender to "add more" while we will throw 4915f3b05218SMichael Tuexen * away :-) 49160c0982b8SRandall Stewart */ 4917f3b05218SMichael Tuexen sctp_free_spbufspace(stcb, &stcb->asoc, sp); 49180c0982b8SRandall Stewart ret_sz += sp->length; 49190c0982b8SRandall Stewart do_wakeup_routine = 1; 49200c0982b8SRandall Stewart sp->some_taken = 1; 49210c0982b8SRandall Stewart sctp_m_freem(sp->data); 49220c0982b8SRandall Stewart sp->data = NULL; 49230c0982b8SRandall Stewart sp->tail_mbuf = NULL; 4924d07b2ac6SMichael Tuexen sp->length = 0; 49250c0982b8SRandall Stewart } 49260c0982b8SRandall Stewart } 49270c0982b8SRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 49280c0982b8SRandall Stewart } 49290c0982b8SRandall Stewart if (do_wakeup_routine) { 49300c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 49318933fa13SRandall Stewart struct socket *so; 49328933fa13SRandall Stewart 49330c0982b8SRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 49340c0982b8SRandall Stewart if (!so_locked) { 49350c0982b8SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 49360c0982b8SRandall Stewart SCTP_TCB_UNLOCK(stcb); 49370c0982b8SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 49380c0982b8SRandall Stewart SCTP_TCB_LOCK(stcb); 49390c0982b8SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 49400c0982b8SRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 49410c0982b8SRandall Stewart /* assoc was freed while we were unlocked */ 49420c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 49430c0982b8SRandall Stewart return (ret_sz); 49440c0982b8SRandall Stewart } 49450c0982b8SRandall Stewart } 49460c0982b8SRandall Stewart #endif 49470c0982b8SRandall Stewart sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 49480c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 49490c0982b8SRandall Stewart if (!so_locked) { 49500c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 49510c0982b8SRandall Stewart } 49520c0982b8SRandall Stewart #endif 4953f8829a4aSRandall Stewart } 4954f8829a4aSRandall Stewart return (ret_sz); 4955f8829a4aSRandall Stewart } 4956f8829a4aSRandall Stewart 4957f8829a4aSRandall Stewart /* 4958f8829a4aSRandall Stewart * checks to see if the given address, sa, is one that is currently known by 4959f8829a4aSRandall Stewart * the kernel note: can't distinguish the same address on multiple interfaces 4960f8829a4aSRandall Stewart * and doesn't handle multiple addresses with different zone/scope id's note: 4961f8829a4aSRandall Stewart * ifa_ifwithaddr() compares the entire sockaddr struct 4962f8829a4aSRandall Stewart */ 496342551e99SRandall Stewart struct sctp_ifa * 496480fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, 496580fefe0aSRandall Stewart int holds_lock) 4966f8829a4aSRandall Stewart { 496742551e99SRandall Stewart struct sctp_laddr *laddr; 4968f8829a4aSRandall Stewart 4969ad81507eSRandall Stewart if (holds_lock == 0) { 497042551e99SRandall Stewart SCTP_INP_RLOCK(inp); 4971ad81507eSRandall Stewart } 497242551e99SRandall Stewart LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 497342551e99SRandall Stewart if (laddr->ifa == NULL) 4974f8829a4aSRandall Stewart continue; 497542551e99SRandall Stewart if (addr->sa_family != laddr->ifa->address.sa.sa_family) 497642551e99SRandall Stewart continue; 4977e6194c2eSMichael Tuexen #ifdef INET 497842551e99SRandall Stewart if (addr->sa_family == AF_INET) { 497942551e99SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 498042551e99SRandall Stewart laddr->ifa->address.sin.sin_addr.s_addr) { 498142551e99SRandall Stewart /* found him. */ 4982ad81507eSRandall Stewart if (holds_lock == 0) { 498342551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4984ad81507eSRandall Stewart } 498542551e99SRandall Stewart return (laddr->ifa); 498642551e99SRandall Stewart break; 498742551e99SRandall Stewart } 49885e2c2d87SRandall Stewart } 4989e6194c2eSMichael Tuexen #endif 49905e2c2d87SRandall Stewart #ifdef INET6 49915e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 4992c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 4993c54a18d2SRandall Stewart &laddr->ifa->address.sin6)) { 499442551e99SRandall Stewart /* found him. */ 4995ad81507eSRandall Stewart if (holds_lock == 0) { 499642551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4997ad81507eSRandall Stewart } 499842551e99SRandall Stewart return (laddr->ifa); 499942551e99SRandall Stewart break; 500042551e99SRandall Stewart } 500142551e99SRandall Stewart } 50025e2c2d87SRandall Stewart #endif 500342551e99SRandall Stewart } 5004ad81507eSRandall Stewart if (holds_lock == 0) { 500542551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5006ad81507eSRandall Stewart } 500742551e99SRandall Stewart return (NULL); 500842551e99SRandall Stewart } 5009f8829a4aSRandall Stewart 50106a27c376SRandall Stewart uint32_t 5011*b0471b4bSMichael Tuexen sctp_get_ifa_hash_val(struct sockaddr *addr) 5012*b0471b4bSMichael Tuexen { 5013ea5eba11SMichael Tuexen switch (addr->sa_family) { 5014ea5eba11SMichael Tuexen #ifdef INET 5015ea5eba11SMichael Tuexen case AF_INET: 5016ea5eba11SMichael Tuexen { 50176a27c376SRandall Stewart struct sockaddr_in *sin; 50186a27c376SRandall Stewart 50196a27c376SRandall Stewart sin = (struct sockaddr_in *)addr; 50206a27c376SRandall Stewart return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); 5021ea5eba11SMichael Tuexen } 5022ea5eba11SMichael Tuexen #endif 5023ea5eba11SMichael Tuexen #ifdef INET6 50242c2e3218SMichael Tuexen case AF_INET6: 5025ea5eba11SMichael Tuexen { 50266a27c376SRandall Stewart struct sockaddr_in6 *sin6; 50276a27c376SRandall Stewart uint32_t hash_of_addr; 50286a27c376SRandall Stewart 50296a27c376SRandall Stewart sin6 = (struct sockaddr_in6 *)addr; 50306a27c376SRandall Stewart hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + 50316a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[1] + 50326a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[2] + 50336a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[3]); 50346a27c376SRandall Stewart hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); 50356a27c376SRandall Stewart return (hash_of_addr); 50366a27c376SRandall Stewart } 5037ea5eba11SMichael Tuexen #endif 5038ea5eba11SMichael Tuexen default: 5039ea5eba11SMichael Tuexen break; 5040ea5eba11SMichael Tuexen } 50416a27c376SRandall Stewart return (0); 50426a27c376SRandall Stewart } 50436a27c376SRandall Stewart 504442551e99SRandall Stewart struct sctp_ifa * 504542551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) 504642551e99SRandall Stewart { 504742551e99SRandall Stewart struct sctp_ifa *sctp_ifap; 504842551e99SRandall Stewart struct sctp_vrf *vrf; 50496a27c376SRandall Stewart struct sctp_ifalist *hash_head; 50506a27c376SRandall Stewart uint32_t hash_of_addr; 505142551e99SRandall Stewart 505242551e99SRandall Stewart if (holds_lock == 0) 5053c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 505442551e99SRandall Stewart 5055bff64a4dSRandall Stewart vrf = sctp_find_vrf(vrf_id); 5056bff64a4dSRandall Stewart if (vrf == NULL) { 5057bff64a4dSRandall Stewart if (holds_lock == 0) 5058c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5059bff64a4dSRandall Stewart return (NULL); 5060bff64a4dSRandall Stewart } 5061bff64a4dSRandall Stewart hash_of_addr = sctp_get_ifa_hash_val(addr); 5062bff64a4dSRandall Stewart 506317205eccSRandall Stewart hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; 5064bff64a4dSRandall Stewart if (hash_head == NULL) { 5065ad81507eSRandall Stewart SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ", 5066c99efcf6SRandall Stewart hash_of_addr, (uint32_t)vrf->vrf_addr_hashmark, 5067c99efcf6SRandall Stewart (uint32_t)(hash_of_addr & vrf->vrf_addr_hashmark)); 5068bff64a4dSRandall Stewart sctp_print_address(addr); 5069ad81507eSRandall Stewart SCTP_PRINTF("No such bucket for address\n"); 5070bff64a4dSRandall Stewart if (holds_lock == 0) 5071c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5072bff64a4dSRandall Stewart 5073bff64a4dSRandall Stewart return (NULL); 5074bff64a4dSRandall Stewart } 50756a27c376SRandall Stewart LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { 50766a27c376SRandall Stewart if (addr->sa_family != sctp_ifap->address.sa.sa_family) 50776a27c376SRandall Stewart continue; 5078e6194c2eSMichael Tuexen #ifdef INET 50796a27c376SRandall Stewart if (addr->sa_family == AF_INET) { 50806a27c376SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 50816a27c376SRandall Stewart sctp_ifap->address.sin.sin_addr.s_addr) { 50826a27c376SRandall Stewart /* found him. */ 508342551e99SRandall Stewart if (holds_lock == 0) 5084c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 508542551e99SRandall Stewart return (sctp_ifap); 50866a27c376SRandall Stewart break; 50876a27c376SRandall Stewart } 50885e2c2d87SRandall Stewart } 5089e6194c2eSMichael Tuexen #endif 50905e2c2d87SRandall Stewart #ifdef INET6 50915e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 5092c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 5093c54a18d2SRandall Stewart &sctp_ifap->address.sin6)) { 50946a27c376SRandall Stewart /* found him. */ 50956a27c376SRandall Stewart if (holds_lock == 0) 5096c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 50976a27c376SRandall Stewart return (sctp_ifap); 50986a27c376SRandall Stewart break; 50996a27c376SRandall Stewart } 510042551e99SRandall Stewart } 51015e2c2d87SRandall Stewart #endif 510242551e99SRandall Stewart } 510342551e99SRandall Stewart if (holds_lock == 0) 5104c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5105f8829a4aSRandall Stewart return (NULL); 5106f8829a4aSRandall Stewart } 5107f8829a4aSRandall Stewart 5108f8829a4aSRandall Stewart static void 51094c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock, 5110f8829a4aSRandall Stewart uint32_t rwnd_req) 5111f8829a4aSRandall Stewart { 5112f8829a4aSRandall Stewart /* User pulled some data, do we need a rwnd update? */ 5113f8829a4aSRandall Stewart int r_unlocked = 0; 5114f8829a4aSRandall Stewart uint32_t dif, rwnd; 5115f8829a4aSRandall Stewart struct socket *so = NULL; 5116f8829a4aSRandall Stewart 5117f8829a4aSRandall Stewart if (stcb == NULL) 5118f8829a4aSRandall Stewart return; 5119f8829a4aSRandall Stewart 512050cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5121f8829a4aSRandall Stewart 512262c1ff9cSRandall Stewart if (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | 512362c1ff9cSRandall Stewart SCTP_STATE_SHUTDOWN_RECEIVED | 51244c9179adSRandall Stewart SCTP_STATE_SHUTDOWN_ACK_SENT)) { 5125f8829a4aSRandall Stewart /* Pre-check If we are freeing no update */ 5126f8829a4aSRandall Stewart goto no_lock; 5127f8829a4aSRandall Stewart } 5128f8829a4aSRandall Stewart SCTP_INP_INCR_REF(stcb->sctp_ep); 5129f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5130f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5131f8829a4aSRandall Stewart goto out; 5132f8829a4aSRandall Stewart } 5133f8829a4aSRandall Stewart so = stcb->sctp_socket; 5134f8829a4aSRandall Stewart if (so == NULL) { 5135f8829a4aSRandall Stewart goto out; 5136f8829a4aSRandall Stewart } 5137f8829a4aSRandall Stewart atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); 5138f8829a4aSRandall Stewart /* Have you have freed enough to look */ 5139f8829a4aSRandall Stewart *freed_so_far = 0; 5140f8829a4aSRandall Stewart /* Yep, its worth a look and the lock overhead */ 5141f8829a4aSRandall Stewart 5142f8829a4aSRandall Stewart /* Figure out what the rwnd would be */ 5143f8829a4aSRandall Stewart rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); 5144f8829a4aSRandall Stewart if (rwnd >= stcb->asoc.my_last_reported_rwnd) { 5145f8829a4aSRandall Stewart dif = rwnd - stcb->asoc.my_last_reported_rwnd; 5146f8829a4aSRandall Stewart } else { 5147f8829a4aSRandall Stewart dif = 0; 5148f8829a4aSRandall Stewart } 5149f8829a4aSRandall Stewart if (dif >= rwnd_req) { 5150f8829a4aSRandall Stewart if (hold_rlock) { 5151f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 5152f8829a4aSRandall Stewart r_unlocked = 1; 5153f8829a4aSRandall Stewart } 5154f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5155f8829a4aSRandall Stewart /* 5156f8829a4aSRandall Stewart * One last check before we allow the guy possibly 5157f8829a4aSRandall Stewart * to get in. There is a race, where the guy has not 5158f8829a4aSRandall Stewart * reached the gate. In that case 5159f8829a4aSRandall Stewart */ 5160f8829a4aSRandall Stewart goto out; 5161f8829a4aSRandall Stewart } 5162f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 5163f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5164f8829a4aSRandall Stewart /* No reports here */ 5165f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5166f8829a4aSRandall Stewart goto out; 5167f8829a4aSRandall Stewart } 5168f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_wu_sacks_sent); 5169689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_LOCKED); 5170830d754dSRandall Stewart 5171f8829a4aSRandall Stewart sctp_chunk_output(stcb->sctp_ep, stcb, 5172ceaad40aSRandall Stewart SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); 5173f8829a4aSRandall Stewart /* make sure no timer is running */ 5174ba785902SMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, 5175ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_6); 5176f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5177f8829a4aSRandall Stewart } else { 5178f8829a4aSRandall Stewart /* Update how much we have pending */ 5179f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = dif; 5180f8829a4aSRandall Stewart } 5181f8829a4aSRandall Stewart out: 5182f8829a4aSRandall Stewart if (so && r_unlocked && hold_rlock) { 5183f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 5184f8829a4aSRandall Stewart } 5185f8829a4aSRandall Stewart SCTP_INP_DECR_REF(stcb->sctp_ep); 5186f8829a4aSRandall Stewart no_lock: 518750cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 5188f8829a4aSRandall Stewart return; 5189f8829a4aSRandall Stewart } 5190f8829a4aSRandall Stewart 5191f8829a4aSRandall Stewart int 5192f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so, 5193f8829a4aSRandall Stewart struct uio *uio, 5194f8829a4aSRandall Stewart struct mbuf **mp, 5195f8829a4aSRandall Stewart struct sockaddr *from, 5196f8829a4aSRandall Stewart int fromlen, 5197f8829a4aSRandall Stewart int *msg_flags, 5198f8829a4aSRandall Stewart struct sctp_sndrcvinfo *sinfo, 5199f8829a4aSRandall Stewart int filling_sinfo) 5200f8829a4aSRandall Stewart { 5201f8829a4aSRandall Stewart /* 5202f8829a4aSRandall Stewart * MSG flags we will look at MSG_DONTWAIT - non-blocking IO. 5203f8829a4aSRandall Stewart * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy 5204f8829a4aSRandall Stewart * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ?? 5205f8829a4aSRandall Stewart * On the way out we may send out any combination of: 5206f8829a4aSRandall Stewart * MSG_NOTIFICATION MSG_EOR 5207f8829a4aSRandall Stewart * 5208f8829a4aSRandall Stewart */ 5209f8829a4aSRandall Stewart struct sctp_inpcb *inp = NULL; 5210f8829a4aSRandall Stewart int my_len = 0; 5211f8829a4aSRandall Stewart int cp_len = 0, error = 0; 5212f8829a4aSRandall Stewart struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; 521394b0d969SMichael Tuexen struct mbuf *m = NULL; 5214f8829a4aSRandall Stewart struct sctp_tcb *stcb = NULL; 5215f8829a4aSRandall Stewart int wakeup_read_socket = 0; 5216f8829a4aSRandall Stewart int freecnt_applied = 0; 5217f8829a4aSRandall Stewart int out_flags = 0, in_flags = 0; 5218f8829a4aSRandall Stewart int block_allowed = 1; 52194c9179adSRandall Stewart uint32_t freed_so_far = 0; 522081aca91aSRandall Stewart uint32_t copied_so_far = 0; 522193164cf9SRandall Stewart int in_eeor_mode = 0; 5222f8829a4aSRandall Stewart int no_rcv_needed = 0; 5223f8829a4aSRandall Stewart uint32_t rwnd_req = 0; 5224f8829a4aSRandall Stewart int hold_sblock = 0; 5225f8829a4aSRandall Stewart int hold_rlock = 0; 52269a8e3088SMichael Tuexen ssize_t slen = 0; 52274c9179adSRandall Stewart uint32_t held_length = 0; 52287abab911SRobert Watson int sockbuf_lock = 0; 5229f8829a4aSRandall Stewart 523017205eccSRandall Stewart if (uio == NULL) { 5231c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 523217205eccSRandall Stewart return (EINVAL); 523317205eccSRandall Stewart } 5234f8829a4aSRandall Stewart if (msg_flags) { 5235f8829a4aSRandall Stewart in_flags = *msg_flags; 5236c105859eSRandall Stewart if (in_flags & MSG_PEEK) 5237c105859eSRandall Stewart SCTP_STAT_INCR(sctps_read_peeks); 5238f8829a4aSRandall Stewart } else { 5239f8829a4aSRandall Stewart in_flags = 0; 5240f8829a4aSRandall Stewart } 5241f8829a4aSRandall Stewart slen = uio->uio_resid; 524217205eccSRandall Stewart 5243f8829a4aSRandall Stewart /* Pull in and set up our int flags */ 5244f8829a4aSRandall Stewart if (in_flags & MSG_OOB) { 5245f8829a4aSRandall Stewart /* Out of band's NOT supported */ 5246f8829a4aSRandall Stewart return (EOPNOTSUPP); 5247f8829a4aSRandall Stewart } 5248f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) && (mp != NULL)) { 5249c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 5250f8829a4aSRandall Stewart return (EINVAL); 5251f8829a4aSRandall Stewart } 5252f8829a4aSRandall Stewart if ((in_flags & (MSG_DONTWAIT 5253f8829a4aSRandall Stewart | MSG_NBIO 5254f8829a4aSRandall Stewart )) || 525542551e99SRandall Stewart SCTP_SO_IS_NBIO(so)) { 5256f8829a4aSRandall Stewart block_allowed = 0; 5257f8829a4aSRandall Stewart } 5258f8829a4aSRandall Stewart /* setup the endpoint */ 5259f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 5260f8829a4aSRandall Stewart if (inp == NULL) { 5261c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 5262f8829a4aSRandall Stewart return (EFAULT); 5263f8829a4aSRandall Stewart } 526462c1ff9cSRandall Stewart rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); 5265f8829a4aSRandall Stewart /* Must be at least a MTU's worth */ 5266f8829a4aSRandall Stewart if (rwnd_req < SCTP_MIN_RWND) 5267f8829a4aSRandall Stewart rwnd_req = SCTP_MIN_RWND; 5268f8829a4aSRandall Stewart in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 5269b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5270f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTER, 52719a8e3088SMichael Tuexen rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); 527280fefe0aSRandall Stewart } 5273b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5274f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTERPL, 52759a8e3088SMichael Tuexen rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); 527680fefe0aSRandall Stewart } 5277265de5bbSRobert Watson error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); 5278f8829a4aSRandall Stewart if (error) { 5279f8829a4aSRandall Stewart goto release_unlocked; 5280f8829a4aSRandall Stewart } 52818e1e6e5fSMateusz Guzik sockbuf_lock = 1; 5282f8829a4aSRandall Stewart restart: 52837abab911SRobert Watson 5284f8829a4aSRandall Stewart 5285f8829a4aSRandall Stewart restart_nosblocks: 5286f8829a4aSRandall Stewart if (hold_sblock == 0) { 5287f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5288f8829a4aSRandall Stewart hold_sblock = 1; 5289f8829a4aSRandall Stewart } 5290f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5291f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5292f8829a4aSRandall Stewart goto out; 5293f8829a4aSRandall Stewart } 52944e88d37aSMichael Tuexen if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) { 5295f8829a4aSRandall Stewart if (so->so_error) { 5296f8829a4aSRandall Stewart error = so->so_error; 529744b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 529844b7479bSRandall Stewart so->so_error = 0; 52999f22f500SRandall Stewart goto out; 5300f8829a4aSRandall Stewart } else { 53014e88d37aSMichael Tuexen if (so->so_rcv.sb_cc == 0) { 53027924093fSRandall Stewart /* indicate EOF */ 53037924093fSRandall Stewart error = 0; 5304f8829a4aSRandall Stewart goto out; 5305f8829a4aSRandall Stewart } 53069f22f500SRandall Stewart } 53079f22f500SRandall Stewart } 53089de217ceSMichael Tuexen if (so->so_rcv.sb_cc <= held_length) { 53099de217ceSMichael Tuexen if (so->so_error) { 53109de217ceSMichael Tuexen error = so->so_error; 53119de217ceSMichael Tuexen if ((in_flags & MSG_PEEK) == 0) { 53129de217ceSMichael Tuexen so->so_error = 0; 53139de217ceSMichael Tuexen } 53149de217ceSMichael Tuexen goto out; 53159de217ceSMichael Tuexen } 53164e88d37aSMichael Tuexen if ((so->so_rcv.sb_cc == 0) && 5317f8829a4aSRandall Stewart ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5318f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 5319f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 5320f8829a4aSRandall Stewart /* 5321f8829a4aSRandall Stewart * For active open side clear flags for 5322f8829a4aSRandall Stewart * re-use passive open is blocked by 5323f8829a4aSRandall Stewart * connect. 5324f8829a4aSRandall Stewart */ 5325f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 5326b7b84c0eSMichael Tuexen /* 5327b7b84c0eSMichael Tuexen * You were aborted, passive side 5328b7b84c0eSMichael Tuexen * always hits here 5329b7b84c0eSMichael Tuexen */ 5330c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 5331f8829a4aSRandall Stewart error = ECONNRESET; 5332f8829a4aSRandall Stewart } 5333f8829a4aSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 5334f8829a4aSRandall Stewart SS_ISDISCONNECTING | 5335f8829a4aSRandall Stewart SS_ISCONFIRMING | 5336f8829a4aSRandall Stewart SS_ISCONNECTED); 5337f8829a4aSRandall Stewart if (error == 0) { 5338f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5339c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 5340f8829a4aSRandall Stewart error = ENOTCONN; 5341f8829a4aSRandall Stewart } 5342f8829a4aSRandall Stewart } 5343f8829a4aSRandall Stewart goto out; 5344f8829a4aSRandall Stewart } 5345f8829a4aSRandall Stewart } 53469de217ceSMichael Tuexen if (block_allowed) { 5347f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5348f8829a4aSRandall Stewart if (error) { 5349f8829a4aSRandall Stewart goto out; 5350f8829a4aSRandall Stewart } 5351f8829a4aSRandall Stewart held_length = 0; 5352f8829a4aSRandall Stewart goto restart_nosblocks; 535344b7479bSRandall Stewart } else { 5354c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); 5355f8829a4aSRandall Stewart error = EWOULDBLOCK; 5356f8829a4aSRandall Stewart goto out; 5357f8829a4aSRandall Stewart } 53589de217ceSMichael Tuexen } 5359d06c82f1SRandall Stewart if (hold_sblock == 1) { 5360d06c82f1SRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5361d06c82f1SRandall Stewart hold_sblock = 0; 5362d06c82f1SRandall Stewart } 5363f8829a4aSRandall Stewart /* we possibly have data we can read */ 53643c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 5365f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5366f8829a4aSRandall Stewart if (control == NULL) { 5367f8829a4aSRandall Stewart /* 5368f8829a4aSRandall Stewart * This could be happening since the appender did the 5369f8829a4aSRandall Stewart * increment but as not yet did the tailq insert onto the 5370f8829a4aSRandall Stewart * read_queue 5371f8829a4aSRandall Stewart */ 5372f8829a4aSRandall Stewart if (hold_rlock == 0) { 5373f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5374f8829a4aSRandall Stewart } 5375f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 53764e88d37aSMichael Tuexen if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { 5377a5d547adSRandall Stewart #ifdef INVARIANTS 5378f8829a4aSRandall Stewart panic("Huh, its non zero and nothing on control?"); 5379f8829a4aSRandall Stewart #endif 53804e88d37aSMichael Tuexen so->so_rcv.sb_cc = 0; 5381f8829a4aSRandall Stewart } 5382f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5383f8829a4aSRandall Stewart hold_rlock = 0; 5384f8829a4aSRandall Stewart goto restart; 5385f8829a4aSRandall Stewart } 5386f8829a4aSRandall Stewart if ((control->length == 0) && 5387f8829a4aSRandall Stewart (control->do_not_ref_stcb)) { 5388f8829a4aSRandall Stewart /* 5389f8829a4aSRandall Stewart * Clean up code for freeing assoc that left behind a 5390f8829a4aSRandall Stewart * pdapi.. maybe a peer in EEOR that just closed after 5391f8829a4aSRandall Stewart * sending and never indicated a EOR. 5392f8829a4aSRandall Stewart */ 5393f8829a4aSRandall Stewart if (hold_rlock == 0) { 5394f8829a4aSRandall Stewart hold_rlock = 1; 5395f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5396f8829a4aSRandall Stewart } 5397f8829a4aSRandall Stewart control->held_length = 0; 5398f8829a4aSRandall Stewart if (control->data) { 5399f8829a4aSRandall Stewart /* Hmm there is data here .. fix */ 54004c9179adSRandall Stewart struct mbuf *m_tmp; 5401f8829a4aSRandall Stewart int cnt = 0; 5402f8829a4aSRandall Stewart 54034c9179adSRandall Stewart m_tmp = control->data; 54044c9179adSRandall Stewart while (m_tmp) { 54054c9179adSRandall Stewart cnt += SCTP_BUF_LEN(m_tmp); 54064c9179adSRandall Stewart if (SCTP_BUF_NEXT(m_tmp) == NULL) { 54074c9179adSRandall Stewart control->tail_mbuf = m_tmp; 5408f8829a4aSRandall Stewart control->end_added = 1; 5409f8829a4aSRandall Stewart } 54104c9179adSRandall Stewart m_tmp = SCTP_BUF_NEXT(m_tmp); 5411f8829a4aSRandall Stewart } 5412f8829a4aSRandall Stewart control->length = cnt; 5413f8829a4aSRandall Stewart } else { 5414f8829a4aSRandall Stewart /* remove it */ 5415f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5416f8829a4aSRandall Stewart /* Add back any hiddend data */ 5417f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5418f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5419f8829a4aSRandall Stewart } 5420f8829a4aSRandall Stewart if (hold_rlock) { 5421f8829a4aSRandall Stewart hold_rlock = 0; 5422f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5423f8829a4aSRandall Stewart } 5424f8829a4aSRandall Stewart goto restart; 5425f8829a4aSRandall Stewart } 5426810ec536SMichael Tuexen if ((control->length == 0) && 5427810ec536SMichael Tuexen (control->end_added == 1)) { 5428b7b84c0eSMichael Tuexen /* 5429b7b84c0eSMichael Tuexen * Do we also need to check for (control->pdapi_aborted == 5430b7b84c0eSMichael Tuexen * 1)? 5431b7b84c0eSMichael Tuexen */ 5432810ec536SMichael Tuexen if (hold_rlock == 0) { 5433810ec536SMichael Tuexen hold_rlock = 1; 5434810ec536SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5435810ec536SMichael Tuexen } 5436810ec536SMichael Tuexen TAILQ_REMOVE(&inp->read_queue, control, next); 5437810ec536SMichael Tuexen if (control->data) { 5438810ec536SMichael Tuexen #ifdef INVARIANTS 5439810ec536SMichael Tuexen panic("control->data not null but control->length == 0"); 5440810ec536SMichael Tuexen #else 5441810ec536SMichael Tuexen SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n"); 5442810ec536SMichael Tuexen sctp_m_freem(control->data); 5443810ec536SMichael Tuexen control->data = NULL; 5444810ec536SMichael Tuexen #endif 5445810ec536SMichael Tuexen } 5446810ec536SMichael Tuexen if (control->aux_data) { 5447810ec536SMichael Tuexen sctp_m_free(control->aux_data); 5448810ec536SMichael Tuexen control->aux_data = NULL; 5449810ec536SMichael Tuexen } 545098d5fd97SMichael Tuexen #ifdef INVARIANTS 545144249214SRandall Stewart if (control->on_strm_q) { 545244249214SRandall Stewart panic("About to free ctl:%p so:%p and its in %d", 545344249214SRandall Stewart control, so, control->on_strm_q); 545444249214SRandall Stewart } 545598d5fd97SMichael Tuexen #endif 5456810ec536SMichael Tuexen sctp_free_remote_addr(control->whoFrom); 5457810ec536SMichael Tuexen sctp_free_a_readq(stcb, control); 5458810ec536SMichael Tuexen if (hold_rlock) { 5459810ec536SMichael Tuexen hold_rlock = 0; 5460810ec536SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 5461810ec536SMichael Tuexen } 5462810ec536SMichael Tuexen goto restart; 5463810ec536SMichael Tuexen } 5464f8829a4aSRandall Stewart if (control->length == 0) { 5465f8829a4aSRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && 5466f8829a4aSRandall Stewart (filling_sinfo)) { 5467f8829a4aSRandall Stewart /* find a more suitable one then this */ 5468f8829a4aSRandall Stewart ctl = TAILQ_NEXT(control, next); 5469f8829a4aSRandall Stewart while (ctl) { 54709a6142d8SRandall Stewart if ((ctl->stcb != control->stcb) && (ctl->length) && 54719a6142d8SRandall Stewart (ctl->some_taken || 54726114cd96SRandall Stewart (ctl->spec_flags & M_NOTIFICATION) || 54739a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 54749a6142d8SRandall Stewart (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) 54759a6142d8SRandall Stewart ) { 54769a6142d8SRandall Stewart /*- 54779a6142d8SRandall Stewart * If we have a different TCB next, and there is data 54789a6142d8SRandall Stewart * present. If we have already taken some (pdapi), OR we can 54799a6142d8SRandall Stewart * ref the tcb and no delivery as started on this stream, we 548017205eccSRandall Stewart * take it. Note we allow a notification on a different 548117205eccSRandall Stewart * assoc to be delivered.. 54829a6142d8SRandall Stewart */ 54839a6142d8SRandall Stewart control = ctl; 54849a6142d8SRandall Stewart goto found_one; 54859a6142d8SRandall Stewart } else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) && 54869a6142d8SRandall Stewart (ctl->length) && 54879a6142d8SRandall Stewart ((ctl->some_taken) || 54889a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 548917205eccSRandall Stewart ((ctl->spec_flags & M_NOTIFICATION) == 0) && 5490b5c16493SMichael Tuexen (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) { 54919a6142d8SRandall Stewart /*- 54929a6142d8SRandall Stewart * If we have the same tcb, and there is data present, and we 54939a6142d8SRandall Stewart * have the strm interleave feature present. Then if we have 54949a6142d8SRandall Stewart * taken some (pdapi) or we can refer to tht tcb AND we have 54959a6142d8SRandall Stewart * not started a delivery for this stream, we can take it. 549617205eccSRandall Stewart * Note we do NOT allow a notificaiton on the same assoc to 549717205eccSRandall Stewart * be delivered. 54989a6142d8SRandall Stewart */ 5499f8829a4aSRandall Stewart control = ctl; 5500f8829a4aSRandall Stewart goto found_one; 5501f8829a4aSRandall Stewart } 5502f8829a4aSRandall Stewart ctl = TAILQ_NEXT(ctl, next); 5503f8829a4aSRandall Stewart } 5504f8829a4aSRandall Stewart } 5505f8829a4aSRandall Stewart /* 5506f8829a4aSRandall Stewart * if we reach here, not suitable replacement is available 55074e88d37aSMichael Tuexen * <or> fragment interleave is NOT on. So stuff the sb_cc 5508f8829a4aSRandall Stewart * into the our held count, and its time to sleep again. 5509f8829a4aSRandall Stewart */ 55104e88d37aSMichael Tuexen held_length = so->so_rcv.sb_cc; 55114e88d37aSMichael Tuexen control->held_length = so->so_rcv.sb_cc; 5512f8829a4aSRandall Stewart goto restart; 5513f8829a4aSRandall Stewart } 5514f8829a4aSRandall Stewart /* Clear the held length since there is something to read */ 5515f8829a4aSRandall Stewart control->held_length = 0; 5516f8829a4aSRandall Stewart found_one: 5517f8829a4aSRandall Stewart /* 5518f8829a4aSRandall Stewart * If we reach here, control has a some data for us to read off. 5519f8829a4aSRandall Stewart * Note that stcb COULD be NULL. 5520f8829a4aSRandall Stewart */ 55219c5ca6f2SMichael Tuexen if (hold_rlock == 0) { 55229c5ca6f2SMichael Tuexen hold_rlock = 1; 55239c5ca6f2SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5524f8829a4aSRandall Stewart } 55259c5ca6f2SMichael Tuexen control->some_taken++; 5526f8829a4aSRandall Stewart stcb = control->stcb; 5527f8829a4aSRandall Stewart if (stcb) { 55280696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 55290696e120SRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { 553050cec919SRandall Stewart if (freecnt_applied == 0) 5531f8829a4aSRandall Stewart stcb = NULL; 5532f8829a4aSRandall Stewart } else if (control->do_not_ref_stcb == 0) { 5533f8829a4aSRandall Stewart /* you can't free it on me please */ 5534f8829a4aSRandall Stewart /* 5535f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the 5536f8829a4aSRandall Stewart * free code will stop. But since we used the 5537f8829a4aSRandall Stewart * socketbuf lock and the sender uses the tcb_lock 5538f8829a4aSRandall Stewart * to increment, we need to use the atomic add to 5539f8829a4aSRandall Stewart * the refcnt 5540f8829a4aSRandall Stewart */ 5541d55b0b1bSRandall Stewart if (freecnt_applied) { 5542d55b0b1bSRandall Stewart #ifdef INVARIANTS 5543207304d4SRandall Stewart panic("refcnt already incremented"); 5544d55b0b1bSRandall Stewart #else 5545cd3fd531SMichael Tuexen SCTP_PRINTF("refcnt already incremented?\n"); 5546d55b0b1bSRandall Stewart #endif 5547d55b0b1bSRandall Stewart } else { 554850cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5549f8829a4aSRandall Stewart freecnt_applied = 1; 5550d55b0b1bSRandall Stewart } 5551f8829a4aSRandall Stewart /* 5552f8829a4aSRandall Stewart * Setup to remember how much we have not yet told 5553f8829a4aSRandall Stewart * the peer our rwnd has opened up. Note we grab the 5554f8829a4aSRandall Stewart * value from the tcb from last time. Note too that 55550696e120SRandall Stewart * sack sending clears this when a sack is sent, 5556f8829a4aSRandall Stewart * which is fine. Once we hit the rwnd_req, we then 5557f8829a4aSRandall Stewart * will go to the sctp_user_rcvd() that will not 5558f8829a4aSRandall Stewart * lock until it KNOWs it MUST send a WUP-SACK. 5559f8829a4aSRandall Stewart */ 5560f8829a4aSRandall Stewart freed_so_far = stcb->freed_by_sorcv_sincelast; 5561f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = 0; 5562f8829a4aSRandall Stewart } 5563f8829a4aSRandall Stewart } 55646114cd96SRandall Stewart if (stcb && 55656114cd96SRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0) && 55666114cd96SRandall Stewart control->do_not_ref_stcb == 0) { 5567d06c82f1SRandall Stewart stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; 5568d06c82f1SRandall Stewart } 5569f8829a4aSRandall Stewart /* First lets get off the sinfo and sockaddr info */ 55705f05199cSMichael Tuexen if ((sinfo != NULL) && (filling_sinfo != 0)) { 55715f05199cSMichael Tuexen sinfo->sinfo_stream = control->sinfo_stream; 557249656eefSMichael Tuexen sinfo->sinfo_ssn = (uint16_t)control->mid; 55735f05199cSMichael Tuexen sinfo->sinfo_flags = control->sinfo_flags; 55745f05199cSMichael Tuexen sinfo->sinfo_ppid = control->sinfo_ppid; 55755f05199cSMichael Tuexen sinfo->sinfo_context = control->sinfo_context; 55765f05199cSMichael Tuexen sinfo->sinfo_timetolive = control->sinfo_timetolive; 55775f05199cSMichael Tuexen sinfo->sinfo_tsn = control->sinfo_tsn; 55785f05199cSMichael Tuexen sinfo->sinfo_cumtsn = control->sinfo_cumtsn; 55795f05199cSMichael Tuexen sinfo->sinfo_assoc_id = control->sinfo_assoc_id; 5580f8829a4aSRandall Stewart nxt = TAILQ_NEXT(control, next); 5581e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 5582e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { 5583f8829a4aSRandall Stewart struct sctp_extrcvinfo *s_extra; 5584f8829a4aSRandall Stewart 5585f8829a4aSRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 55869a6142d8SRandall Stewart if ((nxt) && 55879a6142d8SRandall Stewart (nxt->length)) { 5588b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL; 5589f8829a4aSRandall Stewart if (nxt->sinfo_flags & SCTP_UNORDERED) { 5590b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED; 5591f8829a4aSRandall Stewart } 5592f42a358aSRandall Stewart if (nxt->spec_flags & M_NOTIFICATION) { 5593b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION; 5594f42a358aSRandall Stewart } 5595b70b526dSMichael Tuexen s_extra->serinfo_next_aid = nxt->sinfo_assoc_id; 5596b70b526dSMichael Tuexen s_extra->serinfo_next_length = nxt->length; 5597b70b526dSMichael Tuexen s_extra->serinfo_next_ppid = nxt->sinfo_ppid; 5598b70b526dSMichael Tuexen s_extra->serinfo_next_stream = nxt->sinfo_stream; 5599f8829a4aSRandall Stewart if (nxt->tail_mbuf != NULL) { 5600139bc87fSRandall Stewart if (nxt->end_added) { 5601b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE; 5602f8829a4aSRandall Stewart } 5603f8829a4aSRandall Stewart } 5604f8829a4aSRandall Stewart } else { 5605f8829a4aSRandall Stewart /* 5606f8829a4aSRandall Stewart * we explicitly 0 this, since the memcpy 5607f8829a4aSRandall Stewart * got some other things beyond the older 5608f8829a4aSRandall Stewart * sinfo_ that is on the control's structure 5609f8829a4aSRandall Stewart * :-D 5610f8829a4aSRandall Stewart */ 56119a6142d8SRandall Stewart nxt = NULL; 5612b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; 5613b70b526dSMichael Tuexen s_extra->serinfo_next_aid = 0; 5614b70b526dSMichael Tuexen s_extra->serinfo_next_length = 0; 5615b70b526dSMichael Tuexen s_extra->serinfo_next_ppid = 0; 5616b70b526dSMichael Tuexen s_extra->serinfo_next_stream = 0; 5617f8829a4aSRandall Stewart } 5618f8829a4aSRandall Stewart } 5619f8829a4aSRandall Stewart /* 5620f8829a4aSRandall Stewart * update off the real current cum-ack, if we have an stcb. 5621f8829a4aSRandall Stewart */ 56220696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb) 5623f8829a4aSRandall Stewart sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 5624f8829a4aSRandall Stewart /* 5625f8829a4aSRandall Stewart * mask off the high bits, we keep the actual chunk bits in 5626f8829a4aSRandall Stewart * there. 5627f8829a4aSRandall Stewart */ 5628f8829a4aSRandall Stewart sinfo->sinfo_flags &= 0x00ff; 56295f26a41dSRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { 56305f26a41dSRandall Stewart sinfo->sinfo_flags |= SCTP_UNORDERED; 56315f26a41dSRandall Stewart } 5632f8829a4aSRandall Stewart } 563318e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 563418e198d3SRandall Stewart { 563518e198d3SRandall Stewart int index, newindex; 563618e198d3SRandall Stewart struct sctp_pcbtsn_rlog *entry; 563718e198d3SRandall Stewart 563818e198d3SRandall Stewart do { 563918e198d3SRandall Stewart index = inp->readlog_index; 564018e198d3SRandall Stewart newindex = index + 1; 564118e198d3SRandall Stewart if (newindex >= SCTP_READ_LOG_SIZE) { 564218e198d3SRandall Stewart newindex = 0; 564318e198d3SRandall Stewart } 564418e198d3SRandall Stewart } while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0); 564518e198d3SRandall Stewart entry = &inp->readlog[index]; 564618e198d3SRandall Stewart entry->vtag = control->sinfo_assoc_id; 564718e198d3SRandall Stewart entry->strm = control->sinfo_stream; 564849656eefSMichael Tuexen entry->seq = (uint16_t)control->mid; 564918e198d3SRandall Stewart entry->sz = control->length; 565018e198d3SRandall Stewart entry->flgs = control->sinfo_flags; 565118e198d3SRandall Stewart } 565218e198d3SRandall Stewart #endif 5653d59107f7SMichael Tuexen if ((fromlen > 0) && (from != NULL)) { 5654d59107f7SMichael Tuexen union sctp_sockstore store; 5655d59107f7SMichael Tuexen size_t len; 5656d59107f7SMichael Tuexen 5657b5b6e5c2SMichael Tuexen switch (control->whoFrom->ro._l_addr.sa.sa_family) { 5658b5b6e5c2SMichael Tuexen #ifdef INET6 5659b5b6e5c2SMichael Tuexen case AF_INET6: 5660d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in6); 5661d59107f7SMichael Tuexen store.sin6 = control->whoFrom->ro._l_addr.sin6; 5662d59107f7SMichael Tuexen store.sin6.sin6_port = control->port_from; 5663b5b6e5c2SMichael Tuexen break; 5664f8829a4aSRandall Stewart #endif 5665b5b6e5c2SMichael Tuexen #ifdef INET 5666b5b6e5c2SMichael Tuexen case AF_INET: 5667d59107f7SMichael Tuexen #ifdef INET6 5668d59107f7SMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 5669d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in6); 5670d59107f7SMichael Tuexen in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin, 5671d59107f7SMichael Tuexen &store.sin6); 5672d59107f7SMichael Tuexen store.sin6.sin6_port = control->port_from; 5673d59107f7SMichael Tuexen } else { 5674d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in); 5675d59107f7SMichael Tuexen store.sin = control->whoFrom->ro._l_addr.sin; 5676d59107f7SMichael Tuexen store.sin.sin_port = control->port_from; 5677d59107f7SMichael Tuexen } 5678d59107f7SMichael Tuexen #else 5679d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in); 5680d59107f7SMichael Tuexen store.sin = control->whoFrom->ro._l_addr.sin; 5681d59107f7SMichael Tuexen store.sin.sin_port = control->port_from; 5682d59107f7SMichael Tuexen #endif 5683b5b6e5c2SMichael Tuexen break; 5684b5b6e5c2SMichael Tuexen #endif 5685b5b6e5c2SMichael Tuexen default: 5686d59107f7SMichael Tuexen len = 0; 5687b5b6e5c2SMichael Tuexen break; 5688b5b6e5c2SMichael Tuexen } 5689d59107f7SMichael Tuexen memcpy(from, &store, min((size_t)fromlen, len)); 5690e0e00a4dSMichael Tuexen #ifdef INET6 5691f8829a4aSRandall Stewart { 5692b5b6e5c2SMichael Tuexen struct sockaddr_in6 lsa6, *from6; 5693f8829a4aSRandall Stewart 5694b5b6e5c2SMichael Tuexen from6 = (struct sockaddr_in6 *)from; 5695b5b6e5c2SMichael Tuexen sctp_recover_scope_mac(from6, (&lsa6)); 5696f8829a4aSRandall Stewart } 5697f8829a4aSRandall Stewart #endif 5698f8829a4aSRandall Stewart } 56999c5ca6f2SMichael Tuexen if (hold_rlock) { 57009c5ca6f2SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 57019c5ca6f2SMichael Tuexen hold_rlock = 0; 57029c5ca6f2SMichael Tuexen } 57039c5ca6f2SMichael Tuexen if (hold_sblock) { 57049c5ca6f2SMichael Tuexen SOCKBUF_UNLOCK(&so->so_rcv); 57059c5ca6f2SMichael Tuexen hold_sblock = 0; 57069c5ca6f2SMichael Tuexen } 5707f8829a4aSRandall Stewart /* now copy out what data we can */ 5708f8829a4aSRandall Stewart if (mp == NULL) { 5709f8829a4aSRandall Stewart /* copy out each mbuf in the chain up to length */ 5710f8829a4aSRandall Stewart get_more_data: 5711f8829a4aSRandall Stewart m = control->data; 5712f8829a4aSRandall Stewart while (m) { 5713f8829a4aSRandall Stewart /* Move out all we can */ 5714f8829a4aSRandall Stewart cp_len = (int)uio->uio_resid; 5715139bc87fSRandall Stewart my_len = (int)SCTP_BUF_LEN(m); 5716f8829a4aSRandall Stewart if (cp_len > my_len) { 5717f8829a4aSRandall Stewart /* not enough in this buf */ 5718f8829a4aSRandall Stewart cp_len = my_len; 5719f8829a4aSRandall Stewart } 5720f8829a4aSRandall Stewart if (hold_rlock) { 5721f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5722f8829a4aSRandall Stewart hold_rlock = 0; 5723f8829a4aSRandall Stewart } 5724f8829a4aSRandall Stewart if (cp_len > 0) 5725f8829a4aSRandall Stewart error = uiomove(mtod(m, char *), cp_len, uio); 5726f8829a4aSRandall Stewart /* re-read */ 5727f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 5728f8829a4aSRandall Stewart goto release; 5729f8829a4aSRandall Stewart } 57300696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb && 5731f8829a4aSRandall Stewart stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5732f8829a4aSRandall Stewart no_rcv_needed = 1; 5733f8829a4aSRandall Stewart } 5734f8829a4aSRandall Stewart if (error) { 5735f8829a4aSRandall Stewart /* error we are out of here */ 5736f8829a4aSRandall Stewart goto release; 5737f8829a4aSRandall Stewart } 5738f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5739f8829a4aSRandall Stewart hold_rlock = 1; 5740139bc87fSRandall Stewart if (cp_len == SCTP_BUF_LEN(m)) { 5741139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 5742139bc87fSRandall Stewart (control->end_added)) { 5743f8829a4aSRandall Stewart out_flags |= MSG_EOR; 574452129fcdSRandall Stewart if ((control->do_not_ref_stcb == 0) && 574552129fcdSRandall Stewart (control->stcb != NULL) && 574652129fcdSRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0)) 5747ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 5748f8829a4aSRandall Stewart } 5749139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5750f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5751f8829a4aSRandall Stewart } 5752f8829a4aSRandall Stewart /* we ate up the mbuf */ 5753f8829a4aSRandall Stewart if (in_flags & MSG_PEEK) { 5754f8829a4aSRandall Stewart /* just looking */ 5755139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 5756f8829a4aSRandall Stewart copied_so_far += cp_len; 5757f8829a4aSRandall Stewart } else { 5758f8829a4aSRandall Stewart /* dispose of the mbuf */ 5759b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5760f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5761139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 576280fefe0aSRandall Stewart } 5763f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 5764b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5765f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5766f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 576780fefe0aSRandall Stewart } 5768f8829a4aSRandall Stewart copied_so_far += cp_len; 5769f8829a4aSRandall Stewart freed_so_far += cp_len; 5770c4739e2fSRandall Stewart freed_so_far += MSIZE; 577118e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 5772f8829a4aSRandall Stewart control->data = sctp_m_free(m); 5773f8829a4aSRandall Stewart m = control->data; 5774b7b84c0eSMichael Tuexen /* 5775b7b84c0eSMichael Tuexen * been through it all, must hold sb 5776b7b84c0eSMichael Tuexen * lock ok to null tail 5777b7b84c0eSMichael Tuexen */ 5778f8829a4aSRandall Stewart if (control->data == NULL) { 5779a5d547adSRandall Stewart #ifdef INVARIANTS 5780f8829a4aSRandall Stewart if ((control->end_added == 0) || 5781f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 5782f8829a4aSRandall Stewart /* 5783f8829a4aSRandall Stewart * If the end is not 5784f8829a4aSRandall Stewart * added, OR the 5785f8829a4aSRandall Stewart * next is NOT null 5786f8829a4aSRandall Stewart * we MUST have the 5787f8829a4aSRandall Stewart * lock. 5788f8829a4aSRandall Stewart */ 5789f8829a4aSRandall Stewart if (mtx_owned(&inp->inp_rdata_mtx) == 0) { 5790f8829a4aSRandall Stewart panic("Hmm we don't own the lock?"); 5791f8829a4aSRandall Stewart } 5792f8829a4aSRandall Stewart } 5793f8829a4aSRandall Stewart #endif 5794f8829a4aSRandall Stewart control->tail_mbuf = NULL; 5795a5d547adSRandall Stewart #ifdef INVARIANTS 5796f8829a4aSRandall Stewart if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { 5797f8829a4aSRandall Stewart panic("end_added, nothing left and no MSG_EOR"); 5798f8829a4aSRandall Stewart } 5799f8829a4aSRandall Stewart #endif 5800f8829a4aSRandall Stewart } 5801f8829a4aSRandall Stewart } 5802f8829a4aSRandall Stewart } else { 5803f8829a4aSRandall Stewart /* Do we need to trim the mbuf? */ 5804139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5805f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5806f8829a4aSRandall Stewart } 5807f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) == 0) { 5808139bc87fSRandall Stewart SCTP_BUF_RESV_UF(m, cp_len); 5809139bc87fSRandall Stewart SCTP_BUF_LEN(m) -= cp_len; 5810b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5811f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len); 581280fefe0aSRandall Stewart } 58134e88d37aSMichael Tuexen atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); 58140696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 58150696e120SRandall Stewart stcb) { 58164e88d37aSMichael Tuexen atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); 5817f8829a4aSRandall Stewart } 5818f8829a4aSRandall Stewart copied_so_far += cp_len; 5819f8829a4aSRandall Stewart freed_so_far += cp_len; 5820c4739e2fSRandall Stewart freed_so_far += MSIZE; 5821b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5822f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, 5823f8829a4aSRandall Stewart SCTP_LOG_SBRESULT, 0); 582480fefe0aSRandall Stewart } 582518e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 5826f8829a4aSRandall Stewart } else { 5827f8829a4aSRandall Stewart copied_so_far += cp_len; 5828f8829a4aSRandall Stewart } 5829f8829a4aSRandall Stewart } 5830d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { 5831f8829a4aSRandall Stewart break; 5832f8829a4aSRandall Stewart } 5833f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 5834f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 5835f8829a4aSRandall Stewart (freed_so_far >= rwnd_req)) { 5836f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5837f8829a4aSRandall Stewart } 5838f8829a4aSRandall Stewart } /* end while(m) */ 5839f8829a4aSRandall Stewart /* 5840f8829a4aSRandall Stewart * At this point we have looked at it all and we either have 5841f8829a4aSRandall Stewart * a MSG_EOR/or read all the user wants... <OR> 5842f8829a4aSRandall Stewart * control->length == 0. 5843f8829a4aSRandall Stewart */ 5844d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) { 5845f8829a4aSRandall Stewart /* we are done with this control */ 5846f8829a4aSRandall Stewart if (control->length == 0) { 5847f8829a4aSRandall Stewart if (control->data) { 5848a5d547adSRandall Stewart #ifdef INVARIANTS 5849f8829a4aSRandall Stewart panic("control->data not null at read eor?"); 5850f8829a4aSRandall Stewart #else 5851ad81507eSRandall Stewart SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n"); 5852f8829a4aSRandall Stewart sctp_m_freem(control->data); 5853f8829a4aSRandall Stewart control->data = NULL; 5854f8829a4aSRandall Stewart #endif 5855f8829a4aSRandall Stewart } 5856f8829a4aSRandall Stewart done_with_control: 5857f8829a4aSRandall Stewart if (hold_rlock == 0) { 5858f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5859f8829a4aSRandall Stewart hold_rlock = 1; 5860f8829a4aSRandall Stewart } 5861f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5862f8829a4aSRandall Stewart /* Add back any hiddend data */ 5863f8829a4aSRandall Stewart if (control->held_length) { 5864f8829a4aSRandall Stewart held_length = 0; 5865f8829a4aSRandall Stewart control->held_length = 0; 5866f8829a4aSRandall Stewart wakeup_read_socket = 1; 5867f8829a4aSRandall Stewart } 586817205eccSRandall Stewart if (control->aux_data) { 586917205eccSRandall Stewart sctp_m_free(control->aux_data); 587017205eccSRandall Stewart control->aux_data = NULL; 587117205eccSRandall Stewart } 5872f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 5873f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5874f8829a4aSRandall Stewart control->data = NULL; 587598d5fd97SMichael Tuexen #ifdef INVARIANTS 587644249214SRandall Stewart if (control->on_strm_q) { 587744249214SRandall Stewart panic("About to free ctl:%p so:%p and its in %d", 587844249214SRandall Stewart control, so, control->on_strm_q); 587944249214SRandall Stewart } 588098d5fd97SMichael Tuexen #endif 5881f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5882f8829a4aSRandall Stewart control = NULL; 58830696e120SRandall Stewart if ((freed_so_far >= rwnd_req) && 58840696e120SRandall Stewart (no_rcv_needed == 0)) 5885f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5886f8829a4aSRandall Stewart 5887f8829a4aSRandall Stewart } else { 5888f8829a4aSRandall Stewart /* 5889f8829a4aSRandall Stewart * The user did not read all of this 5890f8829a4aSRandall Stewart * message, turn off the returned MSG_EOR 5891f8829a4aSRandall Stewart * since we are leaving more behind on the 5892f8829a4aSRandall Stewart * control to read. 5893f8829a4aSRandall Stewart */ 5894a5d547adSRandall Stewart #ifdef INVARIANTS 58950696e120SRandall Stewart if (control->end_added && 58960696e120SRandall Stewart (control->data == NULL) && 5897f8829a4aSRandall Stewart (control->tail_mbuf == NULL)) { 5898f8829a4aSRandall Stewart panic("Gak, control->length is corrupt?"); 5899f8829a4aSRandall Stewart } 5900f8829a4aSRandall Stewart #endif 5901f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 5902f8829a4aSRandall Stewart out_flags &= ~MSG_EOR; 5903f8829a4aSRandall Stewart } 5904f8829a4aSRandall Stewart } 5905f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 5906f8829a4aSRandall Stewart goto release; 5907f8829a4aSRandall Stewart } 5908f8829a4aSRandall Stewart if ((uio->uio_resid == 0) || 590904aab884SMichael Tuexen ((in_eeor_mode) && 591004aab884SMichael Tuexen (copied_so_far >= (uint32_t)max(so->so_rcv.sb_lowat, 1)))) { 5911f8829a4aSRandall Stewart goto release; 5912f8829a4aSRandall Stewart } 5913f8829a4aSRandall Stewart /* 5914f8829a4aSRandall Stewart * If I hit here the receiver wants more and this message is 5915f8829a4aSRandall Stewart * NOT done (pd-api). So two questions. Can we block? if not 5916f8829a4aSRandall Stewart * we are done. Did the user NOT set MSG_WAITALL? 5917f8829a4aSRandall Stewart */ 5918f8829a4aSRandall Stewart if (block_allowed == 0) { 5919f8829a4aSRandall Stewart goto release; 5920f8829a4aSRandall Stewart } 5921f8829a4aSRandall Stewart /* 5922f8829a4aSRandall Stewart * We need to wait for more data a few things: - We don't 5923f8829a4aSRandall Stewart * sbunlock() so we don't get someone else reading. - We 5924f8829a4aSRandall Stewart * must be sure to account for the case where what is added 5925f8829a4aSRandall Stewart * is NOT to our control when we wakeup. 5926f8829a4aSRandall Stewart */ 5927f8829a4aSRandall Stewart 5928f8829a4aSRandall Stewart /* 5929f8829a4aSRandall Stewart * Do we need to tell the transport a rwnd update might be 5930f8829a4aSRandall Stewart * needed before we go to sleep? 5931f8829a4aSRandall Stewart */ 5932f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 5933f8829a4aSRandall Stewart ((freed_so_far >= rwnd_req) && 5934f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 5935f8829a4aSRandall Stewart (no_rcv_needed == 0))) { 5936f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5937f8829a4aSRandall Stewart } 5938f8829a4aSRandall Stewart wait_some_more: 593944b7479bSRandall Stewart if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { 5940f8829a4aSRandall Stewart goto release; 5941f8829a4aSRandall Stewart } 5942f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) 5943f8829a4aSRandall Stewart goto release; 5944f8829a4aSRandall Stewart 5945f8829a4aSRandall Stewart if (hold_rlock == 1) { 5946f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5947f8829a4aSRandall Stewart hold_rlock = 0; 5948f8829a4aSRandall Stewart } 5949f8829a4aSRandall Stewart if (hold_sblock == 0) { 5950f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5951f8829a4aSRandall Stewart hold_sblock = 1; 5952f8829a4aSRandall Stewart } 5953851b7298SRandall Stewart if ((copied_so_far) && (control->length == 0) && 5954b5c16493SMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) { 5955851b7298SRandall Stewart goto release; 5956851b7298SRandall Stewart } 59574e88d37aSMichael Tuexen if (so->so_rcv.sb_cc <= control->held_length) { 5958f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5959f8829a4aSRandall Stewart if (error) { 5960f8829a4aSRandall Stewart goto release; 5961f8829a4aSRandall Stewart } 5962f8829a4aSRandall Stewart control->held_length = 0; 5963f8829a4aSRandall Stewart } 5964f8829a4aSRandall Stewart if (hold_sblock) { 5965f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5966f8829a4aSRandall Stewart hold_sblock = 0; 5967f8829a4aSRandall Stewart } 5968f8829a4aSRandall Stewart if (control->length == 0) { 5969f8829a4aSRandall Stewart /* still nothing here */ 5970f8829a4aSRandall Stewart if (control->end_added == 1) { 5971f8829a4aSRandall Stewart /* he aborted, or is done i.e.did a shutdown */ 5972f8829a4aSRandall Stewart out_flags |= MSG_EOR; 59739a6142d8SRandall Stewart if (control->pdapi_aborted) { 59746114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5975ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 59769a6142d8SRandall Stewart 597703b0b021SRandall Stewart out_flags |= MSG_TRUNC; 59789a6142d8SRandall Stewart } else { 59796114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5980ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 59819a6142d8SRandall Stewart } 5982f8829a4aSRandall Stewart goto done_with_control; 5983f8829a4aSRandall Stewart } 59844e88d37aSMichael Tuexen if (so->so_rcv.sb_cc > held_length) { 59854e88d37aSMichael Tuexen control->held_length = so->so_rcv.sb_cc; 5986f8829a4aSRandall Stewart held_length = 0; 5987f8829a4aSRandall Stewart } 5988f8829a4aSRandall Stewart goto wait_some_more; 5989f8829a4aSRandall Stewart } else if (control->data == NULL) { 599050cec919SRandall Stewart /* 599150cec919SRandall Stewart * we must re-sync since data is probably being 599250cec919SRandall Stewart * added 599350cec919SRandall Stewart */ 599450cec919SRandall Stewart SCTP_INP_READ_LOCK(inp); 599550cec919SRandall Stewart if ((control->length > 0) && (control->data == NULL)) { 5996b7b84c0eSMichael Tuexen /* 5997b7b84c0eSMichael Tuexen * big trouble.. we have the lock and its 5998b7b84c0eSMichael Tuexen * corrupt? 5999b7b84c0eSMichael Tuexen */ 60009c04b296SRandall Stewart #ifdef INVARIANTS 60019d18771fSRandall Stewart panic("Impossible data==NULL length !=0"); 60029c04b296SRandall Stewart #endif 60039c04b296SRandall Stewart out_flags |= MSG_EOR; 60049c04b296SRandall Stewart out_flags |= MSG_TRUNC; 60059c04b296SRandall Stewart control->length = 0; 60069c04b296SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 60079c04b296SRandall Stewart goto done_with_control; 6008f8829a4aSRandall Stewart } 600950cec919SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 601050cec919SRandall Stewart /* We will fall around to get more data */ 601150cec919SRandall Stewart } 6012f8829a4aSRandall Stewart goto get_more_data; 6013f8829a4aSRandall Stewart } else { 601417205eccSRandall Stewart /*- 601517205eccSRandall Stewart * Give caller back the mbuf chain, 601617205eccSRandall Stewart * store in uio_resid the length 6017f8829a4aSRandall Stewart */ 601817205eccSRandall Stewart wakeup_read_socket = 0; 6019f8829a4aSRandall Stewart if ((control->end_added == 0) || 6020f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 6021f8829a4aSRandall Stewart /* Need to get rlock */ 6022f8829a4aSRandall Stewart if (hold_rlock == 0) { 6023f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6024f8829a4aSRandall Stewart hold_rlock = 1; 6025f8829a4aSRandall Stewart } 6026f8829a4aSRandall Stewart } 6027139bc87fSRandall Stewart if (control->end_added) { 6028f8829a4aSRandall Stewart out_flags |= MSG_EOR; 602960990c0cSMichael Tuexen if ((control->do_not_ref_stcb == 0) && 603060990c0cSMichael Tuexen (control->stcb != NULL) && 603160990c0cSMichael Tuexen ((control->spec_flags & M_NOTIFICATION) == 0)) 6032ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 6033f8829a4aSRandall Stewart } 6034139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6035f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6036f8829a4aSRandall Stewart } 603717205eccSRandall Stewart uio->uio_resid = control->length; 6038f8829a4aSRandall Stewart *mp = control->data; 6039f8829a4aSRandall Stewart m = control->data; 6040f8829a4aSRandall Stewart while (m) { 6041b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6042f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6043139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 604480fefe0aSRandall Stewart } 6045f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 6046139bc87fSRandall Stewart freed_so_far += SCTP_BUF_LEN(m); 6047c4739e2fSRandall Stewart freed_so_far += MSIZE; 6048b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6049f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6050f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 605180fefe0aSRandall Stewart } 6052139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 6053f8829a4aSRandall Stewart } 6054f8829a4aSRandall Stewart control->data = control->tail_mbuf = NULL; 6055f8829a4aSRandall Stewart control->length = 0; 6056f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 6057f8829a4aSRandall Stewart /* Done with this control */ 6058f8829a4aSRandall Stewart goto done_with_control; 6059f8829a4aSRandall Stewart } 6060f8829a4aSRandall Stewart } 6061f8829a4aSRandall Stewart release: 6062f8829a4aSRandall Stewart if (hold_rlock == 1) { 6063f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6064f8829a4aSRandall Stewart hold_rlock = 0; 6065f8829a4aSRandall Stewart } 60667abab911SRobert Watson if (hold_sblock == 1) { 60677abab911SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 60687abab911SRobert Watson hold_sblock = 0; 6069f8829a4aSRandall Stewart } 6070f8829a4aSRandall Stewart sbunlock(&so->so_rcv); 60717abab911SRobert Watson sockbuf_lock = 0; 6072f8829a4aSRandall Stewart 6073f8829a4aSRandall Stewart release_unlocked: 6074f8829a4aSRandall Stewart if (hold_sblock) { 6075f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6076f8829a4aSRandall Stewart hold_sblock = 0; 6077f8829a4aSRandall Stewart } 6078f8829a4aSRandall Stewart if ((stcb) && (in_flags & MSG_PEEK) == 0) { 6079f8829a4aSRandall Stewart if ((freed_so_far >= rwnd_req) && 6080f8829a4aSRandall Stewart (control && (control->do_not_ref_stcb == 0)) && 6081f8829a4aSRandall Stewart (no_rcv_needed == 0)) 6082f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6083f8829a4aSRandall Stewart } 6084f8829a4aSRandall Stewart out: 60851b9f62a0SRandall Stewart if (msg_flags) { 60861b9f62a0SRandall Stewart *msg_flags = out_flags; 60871b9f62a0SRandall Stewart } 60889a6142d8SRandall Stewart if (((out_flags & MSG_EOR) == 0) && 60899a6142d8SRandall Stewart ((in_flags & MSG_PEEK) == 0) && 60909a6142d8SRandall Stewart (sinfo) && 6091e2e7c62eSMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 6092e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) { 60939a6142d8SRandall Stewart struct sctp_extrcvinfo *s_extra; 60949a6142d8SRandall Stewart 60959a6142d8SRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 6096b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; 60979a6142d8SRandall Stewart } 6098f8829a4aSRandall Stewart if (hold_rlock == 1) { 6099f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6100f8829a4aSRandall Stewart } 6101f8829a4aSRandall Stewart if (hold_sblock) { 6102f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6103f8829a4aSRandall Stewart } 61047abab911SRobert Watson if (sockbuf_lock) { 61057abab911SRobert Watson sbunlock(&so->so_rcv); 61067abab911SRobert Watson } 610750cec919SRandall Stewart if (freecnt_applied) { 6108f8829a4aSRandall Stewart /* 6109f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the free 6110f8829a4aSRandall Stewart * code will stop. But since we used the socketbuf lock and 6111f8829a4aSRandall Stewart * the sender uses the tcb_lock to increment, we need to use 6112f8829a4aSRandall Stewart * the atomic add to the refcnt. 6113f8829a4aSRandall Stewart */ 611450cec919SRandall Stewart if (stcb == NULL) { 6115df6e0cc3SRandall Stewart #ifdef INVARIANTS 611650cec919SRandall Stewart panic("stcb for refcnt has gone NULL?"); 6117df6e0cc3SRandall Stewart goto stage_left; 6118df6e0cc3SRandall Stewart #else 6119df6e0cc3SRandall Stewart goto stage_left; 6120df6e0cc3SRandall Stewart #endif 612150cec919SRandall Stewart } 6122f8829a4aSRandall Stewart /* Save the value back for next time */ 6123f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = freed_so_far; 6124cf46caceSMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, -1); 6125f8829a4aSRandall Stewart } 6126b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 6127f8829a4aSRandall Stewart if (stcb) { 6128f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6129f8829a4aSRandall Stewart freed_so_far, 61309a8e3088SMichael Tuexen (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), 6131f8829a4aSRandall Stewart stcb->asoc.my_rwnd, 61324e88d37aSMichael Tuexen so->so_rcv.sb_cc); 6133f8829a4aSRandall Stewart } else { 6134f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6135f8829a4aSRandall Stewart freed_so_far, 61369a8e3088SMichael Tuexen (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), 6137f8829a4aSRandall Stewart 0, 61384e88d37aSMichael Tuexen so->so_rcv.sb_cc); 6139f8829a4aSRandall Stewart } 614080fefe0aSRandall Stewart } 6141df6e0cc3SRandall Stewart stage_left: 6142f8829a4aSRandall Stewart if (wakeup_read_socket) { 6143f8829a4aSRandall Stewart sctp_sorwakeup(inp, so); 6144f8829a4aSRandall Stewart } 6145f8829a4aSRandall Stewart return (error); 6146f8829a4aSRandall Stewart } 6147f8829a4aSRandall Stewart 6148f8829a4aSRandall Stewart 6149f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING 6150f8829a4aSRandall Stewart struct mbuf * 6151f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m) 6152f8829a4aSRandall Stewart { 6153b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 6154f8829a4aSRandall Stewart sctp_log_mb(m, SCTP_MBUF_IFREE); 6155f8829a4aSRandall Stewart } 6156f8829a4aSRandall Stewart return (m_free(m)); 6157f8829a4aSRandall Stewart } 6158f8829a4aSRandall Stewart 6159f8829a4aSRandall Stewart void 6160f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb) 6161f8829a4aSRandall Stewart { 6162f8829a4aSRandall Stewart while (mb != NULL) 6163f8829a4aSRandall Stewart mb = sctp_m_free(mb); 6164f8829a4aSRandall Stewart } 6165f8829a4aSRandall Stewart 6166f8829a4aSRandall Stewart #endif 6167f8829a4aSRandall Stewart 616842551e99SRandall Stewart int 616942551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) 617042551e99SRandall Stewart { 617142551e99SRandall Stewart /* 617242551e99SRandall Stewart * Given a local address. For all associations that holds the 617342551e99SRandall Stewart * address, request a peer-set-primary. 617442551e99SRandall Stewart */ 617542551e99SRandall Stewart struct sctp_ifa *ifa; 617642551e99SRandall Stewart struct sctp_laddr *wi; 617742551e99SRandall Stewart 617842551e99SRandall Stewart ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); 617942551e99SRandall Stewart if (ifa == NULL) { 6180c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); 618142551e99SRandall Stewart return (EADDRNOTAVAIL); 618242551e99SRandall Stewart } 618342551e99SRandall Stewart /* 618442551e99SRandall Stewart * Now that we have the ifa we must awaken the iterator with this 618542551e99SRandall Stewart * message. 618642551e99SRandall Stewart */ 6187b3f1ea41SRandall Stewart wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); 618842551e99SRandall Stewart if (wi == NULL) { 6189c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 619042551e99SRandall Stewart return (ENOMEM); 619142551e99SRandall Stewart } 619242551e99SRandall Stewart /* Now incr the count and int wi structure */ 619342551e99SRandall Stewart SCTP_INCR_LADDR_COUNT(); 61945ba7f91fSMichael Tuexen memset(wi, 0, sizeof(*wi)); 6195d61a0ae0SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); 619642551e99SRandall Stewart wi->ifa = ifa; 619742551e99SRandall Stewart wi->action = SCTP_SET_PRIM_ADDR; 619842551e99SRandall Stewart atomic_add_int(&ifa->refcount, 1); 619942551e99SRandall Stewart 620042551e99SRandall Stewart /* Now add it to the work queue */ 6201f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 620242551e99SRandall Stewart /* 620342551e99SRandall Stewart * Should this really be a tailq? As it is we will process the 620442551e99SRandall Stewart * newest first :-0 620542551e99SRandall Stewart */ 6206b3f1ea41SRandall Stewart LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 620742551e99SRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 620842551e99SRandall Stewart (struct sctp_inpcb *)NULL, 620942551e99SRandall Stewart (struct sctp_tcb *)NULL, 621042551e99SRandall Stewart (struct sctp_nets *)NULL); 62112c62ba73SMichael Tuexen SCTP_WQ_ADDR_UNLOCK(); 621242551e99SRandall Stewart return (0); 621342551e99SRandall Stewart } 621442551e99SRandall Stewart 621542551e99SRandall Stewart 6216f8829a4aSRandall Stewart int 621717205eccSRandall Stewart sctp_soreceive(struct socket *so, 621817205eccSRandall Stewart struct sockaddr **psa, 621917205eccSRandall Stewart struct uio *uio, 622017205eccSRandall Stewart struct mbuf **mp0, 622117205eccSRandall Stewart struct mbuf **controlp, 622217205eccSRandall Stewart int *flagsp) 6223f8829a4aSRandall Stewart { 6224f8829a4aSRandall Stewart int error, fromlen; 6225f8829a4aSRandall Stewart uint8_t sockbuf[256]; 6226f8829a4aSRandall Stewart struct sockaddr *from; 6227f8829a4aSRandall Stewart struct sctp_extrcvinfo sinfo; 6228f8829a4aSRandall Stewart int filling_sinfo = 1; 622946bf534cSMichael Tuexen int flags; 6230f8829a4aSRandall Stewart struct sctp_inpcb *inp; 6231f8829a4aSRandall Stewart 6232f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 6233f8829a4aSRandall Stewart /* pickup the assoc we are reading from */ 6234f8829a4aSRandall Stewart if (inp == NULL) { 6235c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6236f8829a4aSRandall Stewart return (EINVAL); 6237f8829a4aSRandall Stewart } 6238e2e7c62eSMichael Tuexen if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && 6239e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && 6240e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) || 6241f8829a4aSRandall Stewart (controlp == NULL)) { 6242f8829a4aSRandall Stewart /* user does not want the sndrcv ctl */ 6243f8829a4aSRandall Stewart filling_sinfo = 0; 6244f8829a4aSRandall Stewart } 6245f8829a4aSRandall Stewart if (psa) { 6246f8829a4aSRandall Stewart from = (struct sockaddr *)sockbuf; 6247f8829a4aSRandall Stewart fromlen = sizeof(sockbuf); 6248f8829a4aSRandall Stewart from->sa_len = 0; 6249f8829a4aSRandall Stewart } else { 6250f8829a4aSRandall Stewart from = NULL; 6251f8829a4aSRandall Stewart fromlen = 0; 6252f8829a4aSRandall Stewart } 6253f8829a4aSRandall Stewart 6254e432298aSXin LI if (filling_sinfo) { 6255e432298aSXin LI memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo)); 6256e432298aSXin LI } 625746bf534cSMichael Tuexen if (flagsp != NULL) { 625846bf534cSMichael Tuexen flags = *flagsp; 625946bf534cSMichael Tuexen } else { 626046bf534cSMichael Tuexen flags = 0; 626146bf534cSMichael Tuexen } 626246bf534cSMichael Tuexen error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags, 6263f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo); 626446bf534cSMichael Tuexen if (flagsp != NULL) { 626546bf534cSMichael Tuexen *flagsp = flags; 626646bf534cSMichael Tuexen } 6267e432298aSXin LI if (controlp != NULL) { 6268f8829a4aSRandall Stewart /* copy back the sinfo in a CMSG format */ 626946bf534cSMichael Tuexen if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) { 6270f8829a4aSRandall Stewart *controlp = sctp_build_ctl_nchunk(inp, 6271f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo); 627246bf534cSMichael Tuexen } else { 6273f8829a4aSRandall Stewart *controlp = NULL; 6274f8829a4aSRandall Stewart } 627546bf534cSMichael Tuexen } 6276f8829a4aSRandall Stewart if (psa) { 6277f8829a4aSRandall Stewart /* copy back the address info */ 6278f8829a4aSRandall Stewart if (from && from->sa_len) { 6279f8829a4aSRandall Stewart *psa = sodupsockaddr(from, M_NOWAIT); 6280f8829a4aSRandall Stewart } else { 6281f8829a4aSRandall Stewart *psa = NULL; 6282f8829a4aSRandall Stewart } 6283f8829a4aSRandall Stewart } 6284f8829a4aSRandall Stewart return (error); 6285f8829a4aSRandall Stewart } 628617205eccSRandall Stewart 628717205eccSRandall Stewart 628817205eccSRandall Stewart 628917205eccSRandall Stewart 629017205eccSRandall Stewart 629117205eccSRandall Stewart int 6292d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, 6293d61a0ae0SRandall Stewart int totaddr, int *error) 629417205eccSRandall Stewart { 629517205eccSRandall Stewart int added = 0; 629617205eccSRandall Stewart int i; 629717205eccSRandall Stewart struct sctp_inpcb *inp; 629817205eccSRandall Stewart struct sockaddr *sa; 629917205eccSRandall Stewart size_t incr = 0; 630092776dfdSMichael Tuexen #ifdef INET 630192776dfdSMichael Tuexen struct sockaddr_in *sin; 630292776dfdSMichael Tuexen #endif 630392776dfdSMichael Tuexen #ifdef INET6 630492776dfdSMichael Tuexen struct sockaddr_in6 *sin6; 630592776dfdSMichael Tuexen #endif 630692776dfdSMichael Tuexen 630717205eccSRandall Stewart sa = addr; 630817205eccSRandall Stewart inp = stcb->sctp_ep; 630917205eccSRandall Stewart *error = 0; 631017205eccSRandall Stewart for (i = 0; i < totaddr; i++) { 6311ea5eba11SMichael Tuexen switch (sa->sa_family) { 6312ea5eba11SMichael Tuexen #ifdef INET 6313ea5eba11SMichael Tuexen case AF_INET: 631417205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 631592776dfdSMichael Tuexen sin = (struct sockaddr_in *)sa; 631692776dfdSMichael Tuexen if ((sin->sin_addr.s_addr == INADDR_ANY) || 631792776dfdSMichael Tuexen (sin->sin_addr.s_addr == INADDR_BROADCAST) || 631892776dfdSMichael Tuexen IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 631992776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6320ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6321ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_7); 632292776dfdSMichael Tuexen *error = EINVAL; 632392776dfdSMichael Tuexen goto out_now; 632492776dfdSMichael Tuexen } 63257154bf4aSMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, 63267154bf4aSMichael Tuexen SCTP_DONOT_SETSCOPE, 63277154bf4aSMichael Tuexen SCTP_ADDR_IS_CONFIRMED)) { 632817205eccSRandall Stewart /* assoc gone no un-lock */ 6329c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6330ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6331ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_8); 633217205eccSRandall Stewart *error = ENOBUFS; 633317205eccSRandall Stewart goto out_now; 633417205eccSRandall Stewart } 633517205eccSRandall Stewart added++; 6336ea5eba11SMichael Tuexen break; 6337ea5eba11SMichael Tuexen #endif 6338ea5eba11SMichael Tuexen #ifdef INET6 6339ea5eba11SMichael Tuexen case AF_INET6: 634017205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 634192776dfdSMichael Tuexen sin6 = (struct sockaddr_in6 *)sa; 634292776dfdSMichael Tuexen if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 634392776dfdSMichael Tuexen IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 634492776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6345ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6346ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_9); 634792776dfdSMichael Tuexen *error = EINVAL; 634892776dfdSMichael Tuexen goto out_now; 634992776dfdSMichael Tuexen } 63507154bf4aSMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, 63517154bf4aSMichael Tuexen SCTP_DONOT_SETSCOPE, 63527154bf4aSMichael Tuexen SCTP_ADDR_IS_CONFIRMED)) { 635317205eccSRandall Stewart /* assoc gone no un-lock */ 6354c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6355ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6356ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_10); 635717205eccSRandall Stewart *error = ENOBUFS; 635817205eccSRandall Stewart goto out_now; 635917205eccSRandall Stewart } 636017205eccSRandall Stewart added++; 6361ea5eba11SMichael Tuexen break; 6362ea5eba11SMichael Tuexen #endif 6363ea5eba11SMichael Tuexen default: 6364ea5eba11SMichael Tuexen break; 636517205eccSRandall Stewart } 636617205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 636717205eccSRandall Stewart } 636817205eccSRandall Stewart out_now: 636917205eccSRandall Stewart return (added); 637017205eccSRandall Stewart } 637117205eccSRandall Stewart 637217205eccSRandall Stewart struct sctp_tcb * 6373d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, 63749a8e3088SMichael Tuexen unsigned int *totaddr, 63759a8e3088SMichael Tuexen unsigned int *num_v4, unsigned int *num_v6, int *error, 63769a8e3088SMichael Tuexen unsigned int limit, int *bad_addr) 637717205eccSRandall Stewart { 637817205eccSRandall Stewart struct sockaddr *sa; 637917205eccSRandall Stewart struct sctp_tcb *stcb = NULL; 63809a8e3088SMichael Tuexen unsigned int incr, at, i; 638117205eccSRandall Stewart 6382e1949767SMichael Tuexen at = 0; 638317205eccSRandall Stewart sa = addr; 638417205eccSRandall Stewart *error = *num_v6 = *num_v4 = 0; 638517205eccSRandall Stewart /* account and validate addresses */ 63869a8e3088SMichael Tuexen for (i = 0; i < *totaddr; i++) { 6387ea5eba11SMichael Tuexen switch (sa->sa_family) { 6388ea5eba11SMichael Tuexen #ifdef INET 6389ea5eba11SMichael Tuexen case AF_INET: 6390e1949767SMichael Tuexen incr = (unsigned int)sizeof(struct sockaddr_in); 6391d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6392c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6393d61a0ae0SRandall Stewart *error = EINVAL; 6394d61a0ae0SRandall Stewart *bad_addr = 1; 6395d61a0ae0SRandall Stewart return (NULL); 6396d61a0ae0SRandall Stewart } 63979a8e3088SMichael Tuexen (*num_v4) += 1; 6398ea5eba11SMichael Tuexen break; 6399ea5eba11SMichael Tuexen #endif 6400ea5eba11SMichael Tuexen #ifdef INET6 6401ea5eba11SMichael Tuexen case AF_INET6: 6402ea5eba11SMichael Tuexen { 640317205eccSRandall Stewart struct sockaddr_in6 *sin6; 640417205eccSRandall Stewart 640517205eccSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 640617205eccSRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 640717205eccSRandall Stewart /* Must be non-mapped for connectx */ 6408c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 640917205eccSRandall Stewart *error = EINVAL; 6410d61a0ae0SRandall Stewart *bad_addr = 1; 641117205eccSRandall Stewart return (NULL); 641217205eccSRandall Stewart } 6413e1949767SMichael Tuexen incr = (unsigned int)sizeof(struct sockaddr_in6); 6414d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6415c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6416d61a0ae0SRandall Stewart *error = EINVAL; 6417d61a0ae0SRandall Stewart *bad_addr = 1; 6418d61a0ae0SRandall Stewart return (NULL); 6419d61a0ae0SRandall Stewart } 64209a8e3088SMichael Tuexen (*num_v6) += 1; 6421ea5eba11SMichael Tuexen break; 6422ea5eba11SMichael Tuexen } 6423ea5eba11SMichael Tuexen #endif 6424ea5eba11SMichael Tuexen default: 642517205eccSRandall Stewart *totaddr = i; 6426884d8c53SMichael Tuexen incr = 0; 642717205eccSRandall Stewart /* we are done */ 642817205eccSRandall Stewart break; 642917205eccSRandall Stewart } 64309a8e3088SMichael Tuexen if (i == *totaddr) { 6431ea5eba11SMichael Tuexen break; 6432ea5eba11SMichael Tuexen } 6433d61a0ae0SRandall Stewart SCTP_INP_INCR_REF(inp); 643417205eccSRandall Stewart stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 643517205eccSRandall Stewart if (stcb != NULL) { 643617205eccSRandall Stewart /* Already have or am bring up an association */ 643717205eccSRandall Stewart return (stcb); 6438d61a0ae0SRandall Stewart } else { 6439d61a0ae0SRandall Stewart SCTP_INP_DECR_REF(inp); 644017205eccSRandall Stewart } 64419a8e3088SMichael Tuexen if ((at + incr) > limit) { 644217205eccSRandall Stewart *totaddr = i; 644317205eccSRandall Stewart break; 644417205eccSRandall Stewart } 644517205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 644617205eccSRandall Stewart } 644717205eccSRandall Stewart return ((struct sctp_tcb *)NULL); 644817205eccSRandall Stewart } 644935918f85SRandall Stewart 645035918f85SRandall Stewart /* 645135918f85SRandall Stewart * sctp_bindx(ADD) for one address. 645235918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 645335918f85SRandall Stewart */ 645435918f85SRandall Stewart void 645535918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, 645635918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 645735918f85SRandall Stewart uint32_t vrf_id, int *error, void *p) 645835918f85SRandall Stewart { 645935918f85SRandall Stewart struct sockaddr *addr_touse; 6460d59107f7SMichael Tuexen #if defined(INET) && defined(INET6) 646135918f85SRandall Stewart struct sockaddr_in sin; 64625e2c2d87SRandall Stewart #endif 64635e2c2d87SRandall Stewart 646435918f85SRandall Stewart /* see if we're bound all already! */ 646535918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6466c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 646735918f85SRandall Stewart *error = EINVAL; 646835918f85SRandall Stewart return; 646935918f85SRandall Stewart } 647035918f85SRandall Stewart addr_touse = sa; 6471ea5eba11SMichael Tuexen #ifdef INET6 647235918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 6473d59107f7SMichael Tuexen #ifdef INET 647435918f85SRandall Stewart struct sockaddr_in6 *sin6; 647535918f85SRandall Stewart 6476d59107f7SMichael Tuexen #endif 647735918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6478c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 647935918f85SRandall Stewart *error = EINVAL; 648035918f85SRandall Stewart return; 648135918f85SRandall Stewart } 6482db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6483db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6484c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6485db4fd95bSRandall Stewart *error = EINVAL; 6486db4fd95bSRandall Stewart return; 6487db4fd95bSRandall Stewart } 6488d59107f7SMichael Tuexen #ifdef INET 648935918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 649035918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6491db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6492db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6493db4fd95bSRandall Stewart /* can't bind v4-mapped on PF_INET sockets */ 6494c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6495db4fd95bSRandall Stewart *error = EINVAL; 6496db4fd95bSRandall Stewart return; 6497db4fd95bSRandall Stewart } 649835918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 649935918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 650035918f85SRandall Stewart } 6501d59107f7SMichael Tuexen #endif 650235918f85SRandall Stewart } 650335918f85SRandall Stewart #endif 6504ea5eba11SMichael Tuexen #ifdef INET 650535918f85SRandall Stewart if (sa->sa_family == AF_INET) { 650635918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6507c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 650835918f85SRandall Stewart *error = EINVAL; 650935918f85SRandall Stewart return; 651035918f85SRandall Stewart } 6511db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6512db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6513db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6514c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6515db4fd95bSRandall Stewart *error = EINVAL; 6516db4fd95bSRandall Stewart return; 6517db4fd95bSRandall Stewart } 651835918f85SRandall Stewart } 6519ea5eba11SMichael Tuexen #endif 652035918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 652135918f85SRandall Stewart if (p == NULL) { 652235918f85SRandall Stewart /* Can't get proc for Net/Open BSD */ 6523c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 652435918f85SRandall Stewart *error = EINVAL; 652535918f85SRandall Stewart return; 652635918f85SRandall Stewart } 65271b649582SRandall Stewart *error = sctp_inpcb_bind(so, addr_touse, NULL, p); 652835918f85SRandall Stewart return; 652935918f85SRandall Stewart } 653035918f85SRandall Stewart /* 653135918f85SRandall Stewart * No locks required here since bind and mgmt_ep_sa all do their own 653235918f85SRandall Stewart * locking. If we do something for the FIX: below we may need to 653335918f85SRandall Stewart * lock in that case. 653435918f85SRandall Stewart */ 653535918f85SRandall Stewart if (assoc_id == 0) { 653635918f85SRandall Stewart /* add the address */ 653735918f85SRandall Stewart struct sctp_inpcb *lep; 653897c76f10SRandall Stewart struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse; 653935918f85SRandall Stewart 654097c76f10SRandall Stewart /* validate the incoming port */ 654197c76f10SRandall Stewart if ((lsin->sin_port != 0) && 654297c76f10SRandall Stewart (lsin->sin_port != inp->sctp_lport)) { 6543c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 654497c76f10SRandall Stewart *error = EINVAL; 654597c76f10SRandall Stewart return; 654697c76f10SRandall Stewart } else { 654797c76f10SRandall Stewart /* user specified 0 port, set it to existing port */ 654897c76f10SRandall Stewart lsin->sin_port = inp->sctp_lport; 654997c76f10SRandall Stewart } 655097c76f10SRandall Stewart 655135918f85SRandall Stewart lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id); 655235918f85SRandall Stewart if (lep != NULL) { 655335918f85SRandall Stewart /* 655435918f85SRandall Stewart * We must decrement the refcount since we have the 655535918f85SRandall Stewart * ep already and are binding. No remove going on 655635918f85SRandall Stewart * here. 655735918f85SRandall Stewart */ 65586d9e8f2bSRandall Stewart SCTP_INP_DECR_REF(lep); 655935918f85SRandall Stewart } 656035918f85SRandall Stewart if (lep == inp) { 656135918f85SRandall Stewart /* already bound to it.. ok */ 656235918f85SRandall Stewart return; 656335918f85SRandall Stewart } else if (lep == NULL) { 656435918f85SRandall Stewart ((struct sockaddr_in *)addr_touse)->sin_port = 0; 656535918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 656635918f85SRandall Stewart SCTP_ADD_IP_ADDRESS, 656780fefe0aSRandall Stewart vrf_id, NULL); 656835918f85SRandall Stewart } else { 656935918f85SRandall Stewart *error = EADDRINUSE; 657035918f85SRandall Stewart } 657135918f85SRandall Stewart if (*error) 657235918f85SRandall Stewart return; 657335918f85SRandall Stewart } else { 657435918f85SRandall Stewart /* 657535918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 657635918f85SRandall Stewart */ 657735918f85SRandall Stewart } 657835918f85SRandall Stewart } 657935918f85SRandall Stewart 658035918f85SRandall Stewart /* 658135918f85SRandall Stewart * sctp_bindx(DELETE) for one address. 658235918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 658335918f85SRandall Stewart */ 658435918f85SRandall Stewart void 65857215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp, 658635918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 658735918f85SRandall Stewart uint32_t vrf_id, int *error) 658835918f85SRandall Stewart { 658935918f85SRandall Stewart struct sockaddr *addr_touse; 6590d59107f7SMichael Tuexen #if defined(INET) && defined(INET6) 659135918f85SRandall Stewart struct sockaddr_in sin; 65925e2c2d87SRandall Stewart #endif 65935e2c2d87SRandall Stewart 659435918f85SRandall Stewart /* see if we're bound all already! */ 659535918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6596c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 659735918f85SRandall Stewart *error = EINVAL; 659835918f85SRandall Stewart return; 659935918f85SRandall Stewart } 660035918f85SRandall Stewart addr_touse = sa; 6601e0e00a4dSMichael Tuexen #ifdef INET6 660235918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 6603d59107f7SMichael Tuexen #ifdef INET 660435918f85SRandall Stewart struct sockaddr_in6 *sin6; 6605d59107f7SMichael Tuexen #endif 6606d59107f7SMichael Tuexen 660735918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6608c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 660935918f85SRandall Stewart *error = EINVAL; 661035918f85SRandall Stewart return; 661135918f85SRandall Stewart } 6612db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6613db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6614c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6615db4fd95bSRandall Stewart *error = EINVAL; 6616db4fd95bSRandall Stewart return; 6617db4fd95bSRandall Stewart } 6618d59107f7SMichael Tuexen #ifdef INET 661935918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 662035918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6621db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6622db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6623db4fd95bSRandall Stewart /* can't bind mapped-v4 on PF_INET sockets */ 6624c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6625db4fd95bSRandall Stewart *error = EINVAL; 6626db4fd95bSRandall Stewart return; 6627db4fd95bSRandall Stewart } 662835918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 662935918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 663035918f85SRandall Stewart } 6631d59107f7SMichael Tuexen #endif 663235918f85SRandall Stewart } 663335918f85SRandall Stewart #endif 6634ea5eba11SMichael Tuexen #ifdef INET 663535918f85SRandall Stewart if (sa->sa_family == AF_INET) { 663635918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6637c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 663835918f85SRandall Stewart *error = EINVAL; 663935918f85SRandall Stewart return; 664035918f85SRandall Stewart } 6641db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6642db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6643db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6644c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6645db4fd95bSRandall Stewart *error = EINVAL; 6646db4fd95bSRandall Stewart return; 6647db4fd95bSRandall Stewart } 664835918f85SRandall Stewart } 6649ea5eba11SMichael Tuexen #endif 665035918f85SRandall Stewart /* 665135918f85SRandall Stewart * No lock required mgmt_ep_sa does its own locking. If the FIX: 665235918f85SRandall Stewart * below is ever changed we may need to lock before calling 665335918f85SRandall Stewart * association level binding. 665435918f85SRandall Stewart */ 665535918f85SRandall Stewart if (assoc_id == 0) { 665635918f85SRandall Stewart /* delete the address */ 665735918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 665835918f85SRandall Stewart SCTP_DEL_IP_ADDRESS, 665980fefe0aSRandall Stewart vrf_id, NULL); 666035918f85SRandall Stewart } else { 666135918f85SRandall Stewart /* 666235918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 666335918f85SRandall Stewart */ 666435918f85SRandall Stewart } 666535918f85SRandall Stewart } 66661b649582SRandall Stewart 66671b649582SRandall Stewart /* 66681b649582SRandall Stewart * returns the valid local address count for an assoc, taking into account 66691b649582SRandall Stewart * all scoping rules 66701b649582SRandall Stewart */ 66711b649582SRandall Stewart int 66721b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb) 66731b649582SRandall Stewart { 6674b54ddf22SMichael Tuexen int loopback_scope; 6675b54ddf22SMichael Tuexen #if defined(INET) 6676b54ddf22SMichael Tuexen int ipv4_local_scope, ipv4_addr_legal; 6677b54ddf22SMichael Tuexen #endif 6678b54ddf22SMichael Tuexen #if defined (INET6) 6679b54ddf22SMichael Tuexen int local_scope, site_scope, ipv6_addr_legal; 6680b54ddf22SMichael Tuexen #endif 66811b649582SRandall Stewart struct sctp_vrf *vrf; 66821b649582SRandall Stewart struct sctp_ifn *sctp_ifn; 66831b649582SRandall Stewart struct sctp_ifa *sctp_ifa; 66841b649582SRandall Stewart int count = 0; 66851b649582SRandall Stewart 66861b649582SRandall Stewart /* Turn on all the appropriate scopes */ 6687a1cb341bSMichael Tuexen loopback_scope = stcb->asoc.scope.loopback_scope; 6688b54ddf22SMichael Tuexen #if defined(INET) 6689a1cb341bSMichael Tuexen ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; 6690b54ddf22SMichael Tuexen ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; 6691b54ddf22SMichael Tuexen #endif 6692b54ddf22SMichael Tuexen #if defined(INET6) 6693a1cb341bSMichael Tuexen local_scope = stcb->asoc.scope.local_scope; 6694a1cb341bSMichael Tuexen site_scope = stcb->asoc.scope.site_scope; 6695a1cb341bSMichael Tuexen ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; 6696b54ddf22SMichael Tuexen #endif 6697c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 66981b649582SRandall Stewart vrf = sctp_find_vrf(stcb->asoc.vrf_id); 66991b649582SRandall Stewart if (vrf == NULL) { 67001b649582SRandall Stewart /* no vrf, no addresses */ 6701c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 67021b649582SRandall Stewart return (0); 67031b649582SRandall Stewart } 67041b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 67051b649582SRandall Stewart /* 67061b649582SRandall Stewart * bound all case: go through all ifns on the vrf 67071b649582SRandall Stewart */ 67081b649582SRandall Stewart LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 67091b649582SRandall Stewart if ((loopback_scope == 0) && 67101b649582SRandall Stewart SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 67111b649582SRandall Stewart continue; 67121b649582SRandall Stewart } 67131b649582SRandall Stewart LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 67141b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, sctp_ifa)) 67151b649582SRandall Stewart continue; 67165e2c2d87SRandall Stewart switch (sctp_ifa->address.sa.sa_family) { 6717ea5eba11SMichael Tuexen #ifdef INET 67185e2c2d87SRandall Stewart case AF_INET: 67195e2c2d87SRandall Stewart if (ipv4_addr_legal) { 67201b649582SRandall Stewart struct sockaddr_in *sin; 67211b649582SRandall Stewart 672224aaac8dSMichael Tuexen sin = &sctp_ifa->address.sin; 67231b649582SRandall Stewart if (sin->sin_addr.s_addr == 0) { 6724b7b84c0eSMichael Tuexen /* 6725b7b84c0eSMichael Tuexen * skip unspecified 6726b7b84c0eSMichael Tuexen * addrs 6727b7b84c0eSMichael Tuexen */ 67281b649582SRandall Stewart continue; 67291b649582SRandall Stewart } 67306ba22f19SMichael Tuexen if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, 67316ba22f19SMichael Tuexen &sin->sin_addr) != 0) { 67326ba22f19SMichael Tuexen continue; 67336ba22f19SMichael Tuexen } 67341b649582SRandall Stewart if ((ipv4_local_scope == 0) && 67351b649582SRandall Stewart (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 67361b649582SRandall Stewart continue; 67371b649582SRandall Stewart } 67381b649582SRandall Stewart /* count this one */ 67391b649582SRandall Stewart count++; 67405e2c2d87SRandall Stewart } else { 67415e2c2d87SRandall Stewart continue; 67425e2c2d87SRandall Stewart } 67435e2c2d87SRandall Stewart break; 6744ea5eba11SMichael Tuexen #endif 67455e2c2d87SRandall Stewart #ifdef INET6 67465e2c2d87SRandall Stewart case AF_INET6: 67475e2c2d87SRandall Stewart if (ipv6_addr_legal) { 67481b649582SRandall Stewart struct sockaddr_in6 *sin6; 67491b649582SRandall Stewart 675024aaac8dSMichael Tuexen sin6 = &sctp_ifa->address.sin6; 67511b649582SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 67521b649582SRandall Stewart continue; 67531b649582SRandall Stewart } 67546ba22f19SMichael Tuexen if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, 67556ba22f19SMichael Tuexen &sin6->sin6_addr) != 0) { 67566ba22f19SMichael Tuexen continue; 67576ba22f19SMichael Tuexen } 67581b649582SRandall Stewart if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 67591b649582SRandall Stewart if (local_scope == 0) 67601b649582SRandall Stewart continue; 67611b649582SRandall Stewart if (sin6->sin6_scope_id == 0) { 67621b649582SRandall Stewart if (sa6_recoverscope(sin6) != 0) 67631b649582SRandall Stewart /* 67645e2c2d87SRandall Stewart * 67655e2c2d87SRandall Stewart * bad 67665b495f17SMichael Tuexen * link 67675e2c2d87SRandall Stewart * 67685b495f17SMichael Tuexen * local 67695e2c2d87SRandall Stewart * 67705b495f17SMichael Tuexen * address 67715b495f17SMichael Tuexen */ 67721b649582SRandall Stewart continue; 67731b649582SRandall Stewart } 67741b649582SRandall Stewart } 67751b649582SRandall Stewart if ((site_scope == 0) && 67761b649582SRandall Stewart (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 67771b649582SRandall Stewart continue; 67781b649582SRandall Stewart } 67791b649582SRandall Stewart /* count this one */ 67801b649582SRandall Stewart count++; 67811b649582SRandall Stewart } 67825e2c2d87SRandall Stewart break; 67835e2c2d87SRandall Stewart #endif 67845e2c2d87SRandall Stewart default: 67855e2c2d87SRandall Stewart /* TSNH */ 67865e2c2d87SRandall Stewart break; 67875e2c2d87SRandall Stewart } 67881b649582SRandall Stewart } 67891b649582SRandall Stewart } 67901b649582SRandall Stewart } else { 67911b649582SRandall Stewart /* 67921b649582SRandall Stewart * subset bound case 67931b649582SRandall Stewart */ 67941b649582SRandall Stewart struct sctp_laddr *laddr; 67951b649582SRandall Stewart 67961b649582SRandall Stewart LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, 67971b649582SRandall Stewart sctp_nxt_addr) { 67981b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 67991b649582SRandall Stewart continue; 68001b649582SRandall Stewart } 68011b649582SRandall Stewart /* count this one */ 68021b649582SRandall Stewart count++; 68031b649582SRandall Stewart } 68041b649582SRandall Stewart } 6805c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 68061b649582SRandall Stewart return (count); 68071b649582SRandall Stewart } 6808c4739e2fSRandall Stewart 6809c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF) 6810c4739e2fSRandall Stewart 6811c4739e2fSRandall Stewart void 6812b27a6b7dSRandall Stewart sctp_log_trace(uint32_t subsys, const char *str SCTP_UNUSED, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) 6813c4739e2fSRandall Stewart { 6814b27a6b7dSRandall Stewart uint32_t saveindex, newindex; 6815c4739e2fSRandall Stewart 6816c4739e2fSRandall Stewart do { 6817b3f1ea41SRandall Stewart saveindex = SCTP_BASE_SYSCTL(sctp_log).index; 6818c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 6819c4739e2fSRandall Stewart newindex = 1; 6820c4739e2fSRandall Stewart } else { 6821c4739e2fSRandall Stewart newindex = saveindex + 1; 6822c4739e2fSRandall Stewart } 6823b3f1ea41SRandall Stewart } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0); 6824c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 6825c4739e2fSRandall Stewart saveindex = 0; 6826c4739e2fSRandall Stewart } 6827b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; 6828b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys; 6829b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a; 6830b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b; 6831b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c; 6832b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d; 6833b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e; 6834b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f; 6835c4739e2fSRandall Stewart } 6836c4739e2fSRandall Stewart 6837c4739e2fSRandall Stewart #endif 6838a99b6783SRandall Stewart static void 68397cca1775SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, 684081d3ec17SBryan Venteicher const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) 6841a99b6783SRandall Stewart { 6842a99b6783SRandall Stewart struct ip *iph; 68433a51a264SMichael Tuexen #ifdef INET6 68443a51a264SMichael Tuexen struct ip6_hdr *ip6; 68453a51a264SMichael Tuexen #endif 6846a99b6783SRandall Stewart struct mbuf *sp, *last; 6847a99b6783SRandall Stewart struct udphdr *uhdr; 6848285052f0SMichael Tuexen uint16_t port; 6849a99b6783SRandall Stewart 6850a99b6783SRandall Stewart if ((m->m_flags & M_PKTHDR) == 0) { 6851a99b6783SRandall Stewart /* Can't handle one that is not a pkt hdr */ 6852a99b6783SRandall Stewart goto out; 6853a99b6783SRandall Stewart } 6854285052f0SMichael Tuexen /* Pull the src port */ 6855a99b6783SRandall Stewart iph = mtod(m, struct ip *); 6856a99b6783SRandall Stewart uhdr = (struct udphdr *)((caddr_t)iph + off); 6857a99b6783SRandall Stewart port = uhdr->uh_sport; 6858285052f0SMichael Tuexen /* 6859285052f0SMichael Tuexen * Split out the mbuf chain. Leave the IP header in m, place the 6860285052f0SMichael Tuexen * rest in the sp. 6861285052f0SMichael Tuexen */ 6862eb1b1807SGleb Smirnoff sp = m_split(m, off, M_NOWAIT); 6863a99b6783SRandall Stewart if (sp == NULL) { 6864a99b6783SRandall Stewart /* Gak, drop packet, we can't do a split */ 6865a99b6783SRandall Stewart goto out; 6866a99b6783SRandall Stewart } 6867285052f0SMichael Tuexen if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) { 6868285052f0SMichael Tuexen /* Gak, packet can't have an SCTP header in it - too small */ 6869a99b6783SRandall Stewart m_freem(sp); 6870a99b6783SRandall Stewart goto out; 6871a99b6783SRandall Stewart } 6872285052f0SMichael Tuexen /* Now pull up the UDP header and SCTP header together */ 6873285052f0SMichael Tuexen sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr)); 6874a99b6783SRandall Stewart if (sp == NULL) { 6875a99b6783SRandall Stewart /* Gak pullup failed */ 6876a99b6783SRandall Stewart goto out; 6877a99b6783SRandall Stewart } 6878285052f0SMichael Tuexen /* Trim out the UDP header */ 6879a99b6783SRandall Stewart m_adj(sp, sizeof(struct udphdr)); 6880a99b6783SRandall Stewart 6881a99b6783SRandall Stewart /* Now reconstruct the mbuf chain */ 6882285052f0SMichael Tuexen for (last = m; last->m_next; last = last->m_next); 6883a99b6783SRandall Stewart last->m_next = sp; 6884a99b6783SRandall Stewart m->m_pkthdr.len += sp->m_pkthdr.len; 688552f175beSMichael Tuexen /* 688652f175beSMichael Tuexen * The CSUM_DATA_VALID flags indicates that the HW checked the UDP 688752f175beSMichael Tuexen * checksum and it was valid. Since CSUM_DATA_VALID == 688852f175beSMichael Tuexen * CSUM_SCTP_VALID this would imply that the HW also verified the 688952f175beSMichael Tuexen * SCTP checksum. Therefore, clear the bit. 689052f175beSMichael Tuexen */ 689152f175beSMichael Tuexen SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 689252f175beSMichael Tuexen "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n", 689352f175beSMichael Tuexen m->m_pkthdr.len, 689452f175beSMichael Tuexen if_name(m->m_pkthdr.rcvif), 689552f175beSMichael Tuexen (int)m->m_pkthdr.csum_flags, CSUM_BITS); 689652f175beSMichael Tuexen m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID; 6897a99b6783SRandall Stewart iph = mtod(m, struct ip *); 6898a99b6783SRandall Stewart switch (iph->ip_v) { 6899e6194c2eSMichael Tuexen #ifdef INET 6900a99b6783SRandall Stewart case IPVERSION: 690109c1c856SMichael Tuexen iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); 6902a99b6783SRandall Stewart sctp_input_with_port(m, off, port); 6903a99b6783SRandall Stewart break; 6904e6194c2eSMichael Tuexen #endif 6905a99b6783SRandall Stewart #ifdef INET6 6906a99b6783SRandall Stewart case IPV6_VERSION >> 4: 69073a51a264SMichael Tuexen ip6 = mtod(m, struct ip6_hdr *); 69083a51a264SMichael Tuexen ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr)); 69093a51a264SMichael Tuexen sctp6_input_with_port(&m, &off, port); 6910a99b6783SRandall Stewart break; 6911a99b6783SRandall Stewart #endif 6912a99b6783SRandall Stewart default: 6913285052f0SMichael Tuexen goto out; 6914a99b6783SRandall Stewart break; 6915a99b6783SRandall Stewart } 6916a99b6783SRandall Stewart return; 6917a99b6783SRandall Stewart out: 6918a99b6783SRandall Stewart m_freem(m); 6919a99b6783SRandall Stewart } 6920c54a18d2SRandall Stewart 6921fd7af143SMichael Tuexen #ifdef INET 6922fd7af143SMichael Tuexen static void 6923fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED) 6924fd7af143SMichael Tuexen { 6925fd7af143SMichael Tuexen struct ip *outer_ip, *inner_ip; 6926fd7af143SMichael Tuexen struct sctphdr *sh; 6927fd7af143SMichael Tuexen struct icmp *icmp; 6928fd7af143SMichael Tuexen struct udphdr *udp; 6929fd7af143SMichael Tuexen struct sctp_inpcb *inp; 6930fd7af143SMichael Tuexen struct sctp_tcb *stcb; 6931fd7af143SMichael Tuexen struct sctp_nets *net; 6932fd7af143SMichael Tuexen struct sctp_init_chunk *ch; 6933fd7af143SMichael Tuexen struct sockaddr_in src, dst; 6934fd7af143SMichael Tuexen uint8_t type, code; 6935fd7af143SMichael Tuexen 6936fd7af143SMichael Tuexen inner_ip = (struct ip *)vip; 6937fd7af143SMichael Tuexen icmp = (struct icmp *)((caddr_t)inner_ip - 6938fd7af143SMichael Tuexen (sizeof(struct icmp) - sizeof(struct ip))); 6939fd7af143SMichael Tuexen outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); 6940fd7af143SMichael Tuexen if (ntohs(outer_ip->ip_len) < 6941fd7af143SMichael Tuexen sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { 6942fd7af143SMichael Tuexen return; 6943fd7af143SMichael Tuexen } 6944fd7af143SMichael Tuexen udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); 6945fd7af143SMichael Tuexen sh = (struct sctphdr *)(udp + 1); 6946fd7af143SMichael Tuexen memset(&src, 0, sizeof(struct sockaddr_in)); 6947fd7af143SMichael Tuexen src.sin_family = AF_INET; 6948fd7af143SMichael Tuexen src.sin_len = sizeof(struct sockaddr_in); 6949fd7af143SMichael Tuexen src.sin_port = sh->src_port; 6950fd7af143SMichael Tuexen src.sin_addr = inner_ip->ip_src; 6951fd7af143SMichael Tuexen memset(&dst, 0, sizeof(struct sockaddr_in)); 6952fd7af143SMichael Tuexen dst.sin_family = AF_INET; 6953fd7af143SMichael Tuexen dst.sin_len = sizeof(struct sockaddr_in); 6954fd7af143SMichael Tuexen dst.sin_port = sh->dest_port; 6955fd7af143SMichael Tuexen dst.sin_addr = inner_ip->ip_dst; 6956fd7af143SMichael Tuexen /* 6957fd7af143SMichael Tuexen * 'dst' holds the dest of the packet that failed to be sent. 'src' 6958fd7af143SMichael Tuexen * holds our local endpoint address. Thus we reverse the dst and the 6959fd7af143SMichael Tuexen * src in the lookup. 6960fd7af143SMichael Tuexen */ 6961fd7af143SMichael Tuexen inp = NULL; 6962fd7af143SMichael Tuexen net = NULL; 6963fd7af143SMichael Tuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, 6964fd7af143SMichael Tuexen (struct sockaddr *)&src, 6965fd7af143SMichael Tuexen &inp, &net, 1, 6966fd7af143SMichael Tuexen SCTP_DEFAULT_VRFID); 6967fd7af143SMichael Tuexen if ((stcb != NULL) && 6968fd7af143SMichael Tuexen (net != NULL) && 696955b8cd93SMichael Tuexen (inp != NULL)) { 6970fd7af143SMichael Tuexen /* Check the UDP port numbers */ 6971fd7af143SMichael Tuexen if ((udp->uh_dport != net->port) || 6972fd7af143SMichael Tuexen (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { 6973fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 6974fd7af143SMichael Tuexen return; 6975fd7af143SMichael Tuexen } 6976fd7af143SMichael Tuexen /* Check the verification tag */ 6977fd7af143SMichael Tuexen if (ntohl(sh->v_tag) != 0) { 6978fd7af143SMichael Tuexen /* 6979fd7af143SMichael Tuexen * This must be the verification tag used for 6980fd7af143SMichael Tuexen * sending out packets. We don't consider packets 6981fd7af143SMichael Tuexen * reflecting the verification tag. 6982fd7af143SMichael Tuexen */ 6983fd7af143SMichael Tuexen if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { 6984fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 6985fd7af143SMichael Tuexen return; 6986fd7af143SMichael Tuexen } 6987fd7af143SMichael Tuexen } else { 6988fd7af143SMichael Tuexen if (ntohs(outer_ip->ip_len) >= 6989fd7af143SMichael Tuexen sizeof(struct ip) + 6990fd7af143SMichael Tuexen 8 + (inner_ip->ip_hl << 2) + 8 + 20) { 6991fd7af143SMichael Tuexen /* 6992fd7af143SMichael Tuexen * In this case we can check if we got an 6993fd7af143SMichael Tuexen * INIT chunk and if the initiate tag 6994fd7af143SMichael Tuexen * matches. 6995fd7af143SMichael Tuexen */ 6996fd7af143SMichael Tuexen ch = (struct sctp_init_chunk *)(sh + 1); 6997fd7af143SMichael Tuexen if ((ch->ch.chunk_type != SCTP_INITIATION) || 6998fd7af143SMichael Tuexen (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { 6999fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7000fd7af143SMichael Tuexen return; 7001fd7af143SMichael Tuexen } 7002fd7af143SMichael Tuexen } else { 7003fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7004fd7af143SMichael Tuexen return; 7005fd7af143SMichael Tuexen } 7006fd7af143SMichael Tuexen } 7007fd7af143SMichael Tuexen type = icmp->icmp_type; 7008fd7af143SMichael Tuexen code = icmp->icmp_code; 70093c3f9e2aSMichael Tuexen if ((type == ICMP_UNREACH) && 70103c3f9e2aSMichael Tuexen (code == ICMP_UNREACH_PORT)) { 7011fd7af143SMichael Tuexen code = ICMP_UNREACH_PROTOCOL; 7012fd7af143SMichael Tuexen } 7013fd7af143SMichael Tuexen sctp_notify(inp, stcb, net, type, code, 7014fd7af143SMichael Tuexen ntohs(inner_ip->ip_len), 70156ebfa5eeSMichael Tuexen (uint32_t)ntohs(icmp->icmp_nextmtu)); 7016fd7af143SMichael Tuexen } else { 7017fd7af143SMichael Tuexen if ((stcb == NULL) && (inp != NULL)) { 7018fd7af143SMichael Tuexen /* reduce ref-count */ 7019fd7af143SMichael Tuexen SCTP_INP_WLOCK(inp); 7020fd7af143SMichael Tuexen SCTP_INP_DECR_REF(inp); 7021fd7af143SMichael Tuexen SCTP_INP_WUNLOCK(inp); 7022fd7af143SMichael Tuexen } 7023fd7af143SMichael Tuexen if (stcb) { 7024fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7025fd7af143SMichael Tuexen } 7026fd7af143SMichael Tuexen } 7027fd7af143SMichael Tuexen return; 7028fd7af143SMichael Tuexen } 7029fd7af143SMichael Tuexen #endif 7030fd7af143SMichael Tuexen 7031fd7af143SMichael Tuexen #ifdef INET6 7032fd7af143SMichael Tuexen static void 7033fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED) 7034fd7af143SMichael Tuexen { 7035fd7af143SMichael Tuexen struct ip6ctlparam *ip6cp; 7036fd7af143SMichael Tuexen struct sctp_inpcb *inp; 7037fd7af143SMichael Tuexen struct sctp_tcb *stcb; 7038fd7af143SMichael Tuexen struct sctp_nets *net; 7039fd7af143SMichael Tuexen struct sctphdr sh; 7040fd7af143SMichael Tuexen struct udphdr udp; 7041fd7af143SMichael Tuexen struct sockaddr_in6 src, dst; 7042fd7af143SMichael Tuexen uint8_t type, code; 7043fd7af143SMichael Tuexen 7044fd7af143SMichael Tuexen ip6cp = (struct ip6ctlparam *)d; 7045fd7af143SMichael Tuexen /* 7046fd7af143SMichael Tuexen * XXX: We assume that when IPV6 is non NULL, M and OFF are valid. 7047fd7af143SMichael Tuexen */ 7048fd7af143SMichael Tuexen if (ip6cp->ip6c_m == NULL) { 7049fd7af143SMichael Tuexen return; 7050fd7af143SMichael Tuexen } 7051fd7af143SMichael Tuexen /* 7052fd7af143SMichael Tuexen * Check if we can safely examine the ports and the verification tag 7053fd7af143SMichael Tuexen * of the SCTP common header. 7054fd7af143SMichael Tuexen */ 7055fd7af143SMichael Tuexen if (ip6cp->ip6c_m->m_pkthdr.len < 7056fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr) + offsetof(struct sctphdr, checksum)) { 7057fd7af143SMichael Tuexen return; 7058fd7af143SMichael Tuexen } 7059fd7af143SMichael Tuexen /* Copy out the UDP header. */ 7060fd7af143SMichael Tuexen memset(&udp, 0, sizeof(struct udphdr)); 7061fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7062fd7af143SMichael Tuexen ip6cp->ip6c_off, 7063fd7af143SMichael Tuexen sizeof(struct udphdr), 7064fd7af143SMichael Tuexen (caddr_t)&udp); 7065fd7af143SMichael Tuexen /* Copy out the port numbers and the verification tag. */ 7066fd7af143SMichael Tuexen memset(&sh, 0, sizeof(struct sctphdr)); 7067fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7068fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr), 7069fd7af143SMichael Tuexen sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), 7070fd7af143SMichael Tuexen (caddr_t)&sh); 7071fd7af143SMichael Tuexen memset(&src, 0, sizeof(struct sockaddr_in6)); 7072fd7af143SMichael Tuexen src.sin6_family = AF_INET6; 7073fd7af143SMichael Tuexen src.sin6_len = sizeof(struct sockaddr_in6); 7074fd7af143SMichael Tuexen src.sin6_port = sh.src_port; 7075fd7af143SMichael Tuexen src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; 7076fd7af143SMichael Tuexen if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { 7077fd7af143SMichael Tuexen return; 7078fd7af143SMichael Tuexen } 7079fd7af143SMichael Tuexen memset(&dst, 0, sizeof(struct sockaddr_in6)); 7080fd7af143SMichael Tuexen dst.sin6_family = AF_INET6; 7081fd7af143SMichael Tuexen dst.sin6_len = sizeof(struct sockaddr_in6); 7082fd7af143SMichael Tuexen dst.sin6_port = sh.dest_port; 7083fd7af143SMichael Tuexen dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; 7084fd7af143SMichael Tuexen if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { 7085fd7af143SMichael Tuexen return; 7086fd7af143SMichael Tuexen } 7087fd7af143SMichael Tuexen inp = NULL; 7088fd7af143SMichael Tuexen net = NULL; 7089fd7af143SMichael Tuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, 7090fd7af143SMichael Tuexen (struct sockaddr *)&src, 7091fd7af143SMichael Tuexen &inp, &net, 1, SCTP_DEFAULT_VRFID); 7092fd7af143SMichael Tuexen if ((stcb != NULL) && 7093fd7af143SMichael Tuexen (net != NULL) && 709455b8cd93SMichael Tuexen (inp != NULL)) { 7095fd7af143SMichael Tuexen /* Check the UDP port numbers */ 7096fd7af143SMichael Tuexen if ((udp.uh_dport != net->port) || 7097fd7af143SMichael Tuexen (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { 7098fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7099fd7af143SMichael Tuexen return; 7100fd7af143SMichael Tuexen } 7101fd7af143SMichael Tuexen /* Check the verification tag */ 7102fd7af143SMichael Tuexen if (ntohl(sh.v_tag) != 0) { 7103fd7af143SMichael Tuexen /* 7104fd7af143SMichael Tuexen * This must be the verification tag used for 7105fd7af143SMichael Tuexen * sending out packets. We don't consider packets 7106fd7af143SMichael Tuexen * reflecting the verification tag. 7107fd7af143SMichael Tuexen */ 7108fd7af143SMichael Tuexen if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { 7109fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7110fd7af143SMichael Tuexen return; 7111fd7af143SMichael Tuexen } 7112fd7af143SMichael Tuexen } else { 7113fd7af143SMichael Tuexen if (ip6cp->ip6c_m->m_pkthdr.len >= 7114fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr) + 7115fd7af143SMichael Tuexen sizeof(struct sctphdr) + 7116fd7af143SMichael Tuexen sizeof(struct sctp_chunkhdr) + 7117fd7af143SMichael Tuexen offsetof(struct sctp_init, a_rwnd)) { 7118fd7af143SMichael Tuexen /* 7119fd7af143SMichael Tuexen * In this case we can check if we got an 7120fd7af143SMichael Tuexen * INIT chunk and if the initiate tag 7121fd7af143SMichael Tuexen * matches. 7122fd7af143SMichael Tuexen */ 7123fd7af143SMichael Tuexen uint32_t initiate_tag; 7124fd7af143SMichael Tuexen uint8_t chunk_type; 7125fd7af143SMichael Tuexen 7126fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7127fd7af143SMichael Tuexen ip6cp->ip6c_off + 7128fd7af143SMichael Tuexen sizeof(struct udphdr) + 7129fd7af143SMichael Tuexen sizeof(struct sctphdr), 7130fd7af143SMichael Tuexen sizeof(uint8_t), 7131fd7af143SMichael Tuexen (caddr_t)&chunk_type); 7132fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7133fd7af143SMichael Tuexen ip6cp->ip6c_off + 7134fd7af143SMichael Tuexen sizeof(struct udphdr) + 7135fd7af143SMichael Tuexen sizeof(struct sctphdr) + 7136fd7af143SMichael Tuexen sizeof(struct sctp_chunkhdr), 7137fd7af143SMichael Tuexen sizeof(uint32_t), 7138fd7af143SMichael Tuexen (caddr_t)&initiate_tag); 7139fd7af143SMichael Tuexen if ((chunk_type != SCTP_INITIATION) || 7140fd7af143SMichael Tuexen (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { 7141fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7142fd7af143SMichael Tuexen return; 7143fd7af143SMichael Tuexen } 7144fd7af143SMichael Tuexen } else { 7145fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7146fd7af143SMichael Tuexen return; 7147fd7af143SMichael Tuexen } 7148fd7af143SMichael Tuexen } 7149fd7af143SMichael Tuexen type = ip6cp->ip6c_icmp6->icmp6_type; 7150fd7af143SMichael Tuexen code = ip6cp->ip6c_icmp6->icmp6_code; 7151fd7af143SMichael Tuexen if ((type == ICMP6_DST_UNREACH) && 7152fd7af143SMichael Tuexen (code == ICMP6_DST_UNREACH_NOPORT)) { 7153fd7af143SMichael Tuexen type = ICMP6_PARAM_PROB; 7154fd7af143SMichael Tuexen code = ICMP6_PARAMPROB_NEXTHEADER; 7155fd7af143SMichael Tuexen } 7156fd7af143SMichael Tuexen sctp6_notify(inp, stcb, net, type, code, 71576ebfa5eeSMichael Tuexen ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); 7158fd7af143SMichael Tuexen } else { 7159fd7af143SMichael Tuexen if ((stcb == NULL) && (inp != NULL)) { 7160fd7af143SMichael Tuexen /* reduce inp's ref-count */ 7161fd7af143SMichael Tuexen SCTP_INP_WLOCK(inp); 7162fd7af143SMichael Tuexen SCTP_INP_DECR_REF(inp); 7163fd7af143SMichael Tuexen SCTP_INP_WUNLOCK(inp); 7164fd7af143SMichael Tuexen } 7165fd7af143SMichael Tuexen if (stcb) { 7166fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7167fd7af143SMichael Tuexen } 7168fd7af143SMichael Tuexen } 7169fd7af143SMichael Tuexen } 7170fd7af143SMichael Tuexen #endif 7171fd7af143SMichael Tuexen 7172c54a18d2SRandall Stewart void 7173c54a18d2SRandall Stewart sctp_over_udp_stop(void) 7174c54a18d2SRandall Stewart { 7175a99b6783SRandall Stewart /* 7176a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 7177a99b6783SRandall Stewart * for writting! 7178a99b6783SRandall Stewart */ 71793a51a264SMichael Tuexen #ifdef INET 71803a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { 71813a51a264SMichael Tuexen soclose(SCTP_BASE_INFO(udp4_tun_socket)); 71823a51a264SMichael Tuexen SCTP_BASE_INFO(udp4_tun_socket) = NULL; 7183c54a18d2SRandall Stewart } 71843a51a264SMichael Tuexen #endif 71853a51a264SMichael Tuexen #ifdef INET6 71863a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { 71873a51a264SMichael Tuexen soclose(SCTP_BASE_INFO(udp6_tun_socket)); 71883a51a264SMichael Tuexen SCTP_BASE_INFO(udp6_tun_socket) = NULL; 71893a51a264SMichael Tuexen } 71903a51a264SMichael Tuexen #endif 7191a99b6783SRandall Stewart } 7192ea5eba11SMichael Tuexen 7193c54a18d2SRandall Stewart int 7194c54a18d2SRandall Stewart sctp_over_udp_start(void) 7195c54a18d2SRandall Stewart { 7196a99b6783SRandall Stewart uint16_t port; 7197a99b6783SRandall Stewart int ret; 71983a51a264SMichael Tuexen #ifdef INET 71993a51a264SMichael Tuexen struct sockaddr_in sin; 72003a51a264SMichael Tuexen #endif 72013a51a264SMichael Tuexen #ifdef INET6 72023a51a264SMichael Tuexen struct sockaddr_in6 sin6; 72033a51a264SMichael Tuexen #endif 7204a99b6783SRandall Stewart /* 7205a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 7206a99b6783SRandall Stewart * for writting! 7207a99b6783SRandall Stewart */ 7208a99b6783SRandall Stewart port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); 72093a51a264SMichael Tuexen if (ntohs(port) == 0) { 7210a99b6783SRandall Stewart /* Must have a port set */ 7211a99b6783SRandall Stewart return (EINVAL); 7212a99b6783SRandall Stewart } 72133a51a264SMichael Tuexen #ifdef INET 72143a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { 7215a99b6783SRandall Stewart /* Already running -- must stop first */ 7216a99b6783SRandall Stewart return (EALREADY); 7217a99b6783SRandall Stewart } 72183a51a264SMichael Tuexen #endif 72193a51a264SMichael Tuexen #ifdef INET6 72203a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { 72213a51a264SMichael Tuexen /* Already running -- must stop first */ 72223a51a264SMichael Tuexen return (EALREADY); 7223a99b6783SRandall Stewart } 72243a51a264SMichael Tuexen #endif 72253a51a264SMichael Tuexen #ifdef INET 72263a51a264SMichael Tuexen if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket), 72273a51a264SMichael Tuexen SOCK_DGRAM, IPPROTO_UDP, 72283a51a264SMichael Tuexen curthread->td_ucred, curthread))) { 7229a99b6783SRandall Stewart sctp_over_udp_stop(); 7230a99b6783SRandall Stewart return (ret); 7231a99b6783SRandall Stewart } 72323a51a264SMichael Tuexen /* Call the special UDP hook. */ 72333a51a264SMichael Tuexen if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket), 7234fd7af143SMichael Tuexen sctp_recv_udp_tunneled_packet, 7235fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet, 7236fd7af143SMichael Tuexen NULL))) { 72373a51a264SMichael Tuexen sctp_over_udp_stop(); 72383a51a264SMichael Tuexen return (ret); 72393a51a264SMichael Tuexen } 72403a51a264SMichael Tuexen /* Ok, we have a socket, bind it to the port. */ 72413a51a264SMichael Tuexen memset(&sin, 0, sizeof(struct sockaddr_in)); 72423a51a264SMichael Tuexen sin.sin_len = sizeof(struct sockaddr_in); 72433a51a264SMichael Tuexen sin.sin_family = AF_INET; 72443a51a264SMichael Tuexen sin.sin_port = htons(port); 72453a51a264SMichael Tuexen if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket), 72463a51a264SMichael Tuexen (struct sockaddr *)&sin, curthread))) { 72473a51a264SMichael Tuexen sctp_over_udp_stop(); 72483a51a264SMichael Tuexen return (ret); 72493a51a264SMichael Tuexen } 72503a51a264SMichael Tuexen #endif 72513a51a264SMichael Tuexen #ifdef INET6 72523a51a264SMichael Tuexen if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket), 72533a51a264SMichael Tuexen SOCK_DGRAM, IPPROTO_UDP, 72543a51a264SMichael Tuexen curthread->td_ucred, curthread))) { 72553a51a264SMichael Tuexen sctp_over_udp_stop(); 72563a51a264SMichael Tuexen return (ret); 72573a51a264SMichael Tuexen } 72583a51a264SMichael Tuexen /* Call the special UDP hook. */ 72593a51a264SMichael Tuexen if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket), 7260fd7af143SMichael Tuexen sctp_recv_udp_tunneled_packet, 7261fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet, 7262fd7af143SMichael Tuexen NULL))) { 72633a51a264SMichael Tuexen sctp_over_udp_stop(); 72643a51a264SMichael Tuexen return (ret); 72653a51a264SMichael Tuexen } 72663a51a264SMichael Tuexen /* Ok, we have a socket, bind it to the port. */ 72673a51a264SMichael Tuexen memset(&sin6, 0, sizeof(struct sockaddr_in6)); 72683a51a264SMichael Tuexen sin6.sin6_len = sizeof(struct sockaddr_in6); 72693a51a264SMichael Tuexen sin6.sin6_family = AF_INET6; 72703a51a264SMichael Tuexen sin6.sin6_port = htons(port); 72713a51a264SMichael Tuexen if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket), 72723a51a264SMichael Tuexen (struct sockaddr *)&sin6, curthread))) { 72733a51a264SMichael Tuexen sctp_over_udp_stop(); 72743a51a264SMichael Tuexen return (ret); 72753a51a264SMichael Tuexen } 72763a51a264SMichael Tuexen #endif 7277a99b6783SRandall Stewart return (0); 7278c54a18d2SRandall Stewart } 727910e0318aSMichael Tuexen 728010e0318aSMichael Tuexen /* 728110e0318aSMichael Tuexen * sctp_min_mtu ()returns the minimum of all non-zero arguments. 728210e0318aSMichael Tuexen * If all arguments are zero, zero is returned. 728310e0318aSMichael Tuexen */ 728410e0318aSMichael Tuexen uint32_t 7285*b0471b4bSMichael Tuexen sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3) 7286*b0471b4bSMichael Tuexen { 728710e0318aSMichael Tuexen if (mtu1 > 0) { 728810e0318aSMichael Tuexen if (mtu2 > 0) { 728910e0318aSMichael Tuexen if (mtu3 > 0) { 729010e0318aSMichael Tuexen return (min(mtu1, min(mtu2, mtu3))); 729110e0318aSMichael Tuexen } else { 729210e0318aSMichael Tuexen return (min(mtu1, mtu2)); 729310e0318aSMichael Tuexen } 729410e0318aSMichael Tuexen } else { 729510e0318aSMichael Tuexen if (mtu3 > 0) { 729610e0318aSMichael Tuexen return (min(mtu1, mtu3)); 729710e0318aSMichael Tuexen } else { 729810e0318aSMichael Tuexen return (mtu1); 729910e0318aSMichael Tuexen } 730010e0318aSMichael Tuexen } 730110e0318aSMichael Tuexen } else { 730210e0318aSMichael Tuexen if (mtu2 > 0) { 730310e0318aSMichael Tuexen if (mtu3 > 0) { 730410e0318aSMichael Tuexen return (min(mtu2, mtu3)); 730510e0318aSMichael Tuexen } else { 730610e0318aSMichael Tuexen return (mtu2); 730710e0318aSMichael Tuexen } 730810e0318aSMichael Tuexen } else { 730910e0318aSMichael Tuexen return (mtu3); 731010e0318aSMichael Tuexen } 731110e0318aSMichael Tuexen } 731210e0318aSMichael Tuexen } 731310e0318aSMichael Tuexen 731410e0318aSMichael Tuexen void 731510e0318aSMichael Tuexen sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu) 731610e0318aSMichael Tuexen { 731710e0318aSMichael Tuexen struct in_conninfo inc; 731810e0318aSMichael Tuexen 731910e0318aSMichael Tuexen memset(&inc, 0, sizeof(struct in_conninfo)); 732010e0318aSMichael Tuexen inc.inc_fibnum = fibnum; 732110e0318aSMichael Tuexen switch (addr->sa.sa_family) { 732210e0318aSMichael Tuexen #ifdef INET 732310e0318aSMichael Tuexen case AF_INET: 732410e0318aSMichael Tuexen inc.inc_faddr = addr->sin.sin_addr; 732510e0318aSMichael Tuexen break; 732610e0318aSMichael Tuexen #endif 732710e0318aSMichael Tuexen #ifdef INET6 732810e0318aSMichael Tuexen case AF_INET6: 732910e0318aSMichael Tuexen inc.inc_flags |= INC_ISIPV6; 733010e0318aSMichael Tuexen inc.inc6_faddr = addr->sin6.sin6_addr; 733110e0318aSMichael Tuexen break; 733210e0318aSMichael Tuexen #endif 733310e0318aSMichael Tuexen default: 733410e0318aSMichael Tuexen return; 733510e0318aSMichael Tuexen } 733610e0318aSMichael Tuexen tcp_hc_updatemtu(&inc, (u_long)mtu); 733710e0318aSMichael Tuexen } 733810e0318aSMichael Tuexen 733910e0318aSMichael Tuexen uint32_t 7340*b0471b4bSMichael Tuexen sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum) 7341*b0471b4bSMichael Tuexen { 734210e0318aSMichael Tuexen struct in_conninfo inc; 734310e0318aSMichael Tuexen 734410e0318aSMichael Tuexen memset(&inc, 0, sizeof(struct in_conninfo)); 734510e0318aSMichael Tuexen inc.inc_fibnum = fibnum; 734610e0318aSMichael Tuexen switch (addr->sa.sa_family) { 734710e0318aSMichael Tuexen #ifdef INET 734810e0318aSMichael Tuexen case AF_INET: 734910e0318aSMichael Tuexen inc.inc_faddr = addr->sin.sin_addr; 735010e0318aSMichael Tuexen break; 735110e0318aSMichael Tuexen #endif 735210e0318aSMichael Tuexen #ifdef INET6 735310e0318aSMichael Tuexen case AF_INET6: 735410e0318aSMichael Tuexen inc.inc_flags |= INC_ISIPV6; 735510e0318aSMichael Tuexen inc.inc6_faddr = addr->sin6.sin6_addr; 735610e0318aSMichael Tuexen break; 735710e0318aSMichael Tuexen #endif 735810e0318aSMichael Tuexen default: 735910e0318aSMichael Tuexen return (0); 736010e0318aSMichael Tuexen } 736110e0318aSMichael Tuexen return ((uint32_t)tcp_hc_getmtu(&inc)); 736210e0318aSMichael Tuexen } 7363