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> 54776cd558SMichael Tuexen #include <netinet/sctp_kdtrace.h> 5510e0318aSMichael Tuexen #if defined(INET6) || defined(INET) 5610e0318aSMichael Tuexen #include <netinet/tcp_var.h> 5710e0318aSMichael Tuexen #endif 583a51a264SMichael Tuexen #include <netinet/udp.h> 593a51a264SMichael Tuexen #include <netinet/udp_var.h> 603a51a264SMichael Tuexen #include <sys/proc.h> 61fd7af143SMichael Tuexen #ifdef INET6 62fd7af143SMichael Tuexen #include <netinet/icmp6.h> 63fd7af143SMichael Tuexen #endif 64f8829a4aSRandall Stewart 65f8829a4aSRandall Stewart 66b9e7085aSRandall Stewart #ifndef KTR_SCTP 67b9e7085aSRandall Stewart #define KTR_SCTP KTR_SUBSYS 6880fefe0aSRandall Stewart #endif 69f8829a4aSRandall Stewart 70ed654363SMichael Tuexen extern const struct sctp_cc_functions sctp_cc_functions[]; 71ed654363SMichael Tuexen extern const struct sctp_ss_functions sctp_ss_functions[]; 720e9a9c10SMichael Tuexen 73f8829a4aSRandall Stewart void 74dcb68fbaSMichael Tuexen sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) 75f8829a4aSRandall Stewart { 76c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 77c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 78f8829a4aSRandall Stewart 7980fefe0aSRandall Stewart sctp_clog.x.sb.stcb = stcb; 804e88d37aSMichael Tuexen sctp_clog.x.sb.so_sbcc = sb->sb_cc; 81f8829a4aSRandall Stewart if (stcb) 824e88d37aSMichael Tuexen sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc; 83f8829a4aSRandall Stewart else 8480fefe0aSRandall Stewart sctp_clog.x.sb.stcb_sbcc = 0; 8580fefe0aSRandall Stewart sctp_clog.x.sb.incr = incr; 86c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 8780fefe0aSRandall Stewart SCTP_LOG_EVENT_SB, 8880fefe0aSRandall Stewart from, 8980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 9080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 9180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 9280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 93c692df45SMichael Tuexen #endif 94f8829a4aSRandall Stewart } 95f8829a4aSRandall Stewart 96f8829a4aSRandall Stewart void 97f8829a4aSRandall Stewart sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) 98f8829a4aSRandall Stewart { 99c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 100c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 101f8829a4aSRandall Stewart 10280fefe0aSRandall Stewart sctp_clog.x.close.inp = (void *)inp; 10380fefe0aSRandall Stewart sctp_clog.x.close.sctp_flags = inp->sctp_flags; 104f8829a4aSRandall Stewart if (stcb) { 10580fefe0aSRandall Stewart sctp_clog.x.close.stcb = (void *)stcb; 10680fefe0aSRandall Stewart sctp_clog.x.close.state = (uint16_t)stcb->asoc.state; 107f8829a4aSRandall Stewart } else { 10880fefe0aSRandall Stewart sctp_clog.x.close.stcb = 0; 10980fefe0aSRandall Stewart sctp_clog.x.close.state = 0; 110f8829a4aSRandall Stewart } 11180fefe0aSRandall Stewart sctp_clog.x.close.loc = loc; 112c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 11380fefe0aSRandall Stewart SCTP_LOG_EVENT_CLOSE, 11480fefe0aSRandall Stewart 0, 11580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 11680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 11780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 11880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 119c692df45SMichael Tuexen #endif 120f8829a4aSRandall Stewart } 121f8829a4aSRandall Stewart 122f8829a4aSRandall Stewart void 123f8829a4aSRandall Stewart rto_logging(struct sctp_nets *net, int from) 124f8829a4aSRandall Stewart { 125c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 126c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 127f8829a4aSRandall Stewart 128bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 12980fefe0aSRandall Stewart sctp_clog.x.rto.net = (void *)net; 130be1d9176SMichael Tuexen sctp_clog.x.rto.rtt = net->rtt / 1000; 131c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 13280fefe0aSRandall Stewart SCTP_LOG_EVENT_RTT, 13380fefe0aSRandall Stewart from, 13480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 13580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 13680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 13780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 138c692df45SMichael Tuexen #endif 139f8829a4aSRandall Stewart } 140f8829a4aSRandall Stewart 141f8829a4aSRandall Stewart void 1426a91f103SRandall Stewart sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from) 143f8829a4aSRandall Stewart { 144c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 145c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 146f8829a4aSRandall Stewart 14780fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = stcb; 14880fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = tsn; 14980fefe0aSRandall Stewart sctp_clog.x.strlog.n_sseq = sseq; 15080fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 15180fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 15280fefe0aSRandall Stewart sctp_clog.x.strlog.strm = stream; 153c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 15480fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 15580fefe0aSRandall Stewart from, 15680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 15780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 15880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 15980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 160c692df45SMichael Tuexen #endif 161f8829a4aSRandall Stewart } 162f8829a4aSRandall Stewart 163f8829a4aSRandall Stewart void 164f8829a4aSRandall Stewart sctp_log_nagle_event(struct sctp_tcb *stcb, int action) 165f8829a4aSRandall Stewart { 166c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 167c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 168f8829a4aSRandall Stewart 16980fefe0aSRandall Stewart sctp_clog.x.nagle.stcb = (void *)stcb; 17080fefe0aSRandall Stewart sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight; 17180fefe0aSRandall Stewart sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size; 17280fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue; 17380fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count; 174c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 17580fefe0aSRandall Stewart SCTP_LOG_EVENT_NAGLE, 17680fefe0aSRandall Stewart action, 17780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 17880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 17980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 18080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 181c692df45SMichael Tuexen #endif 182f8829a4aSRandall Stewart } 183f8829a4aSRandall Stewart 184f8829a4aSRandall Stewart void 185f8829a4aSRandall Stewart sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from) 186f8829a4aSRandall Stewart { 187c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 188c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 189f8829a4aSRandall Stewart 19080fefe0aSRandall Stewart sctp_clog.x.sack.cumack = cumack; 19180fefe0aSRandall Stewart sctp_clog.x.sack.oldcumack = old_cumack; 19280fefe0aSRandall Stewart sctp_clog.x.sack.tsn = tsn; 19380fefe0aSRandall Stewart sctp_clog.x.sack.numGaps = gaps; 19480fefe0aSRandall Stewart sctp_clog.x.sack.numDups = dups; 195c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 19680fefe0aSRandall Stewart SCTP_LOG_EVENT_SACK, 19780fefe0aSRandall Stewart from, 19880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 19980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 20080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 20180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 202c692df45SMichael Tuexen #endif 203f8829a4aSRandall Stewart } 204f8829a4aSRandall Stewart 205f8829a4aSRandall Stewart void 206f8829a4aSRandall Stewart sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) 207f8829a4aSRandall Stewart { 208c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 209c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 210f8829a4aSRandall Stewart 211bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 21280fefe0aSRandall Stewart sctp_clog.x.map.base = map; 21380fefe0aSRandall Stewart sctp_clog.x.map.cum = cum; 21480fefe0aSRandall Stewart sctp_clog.x.map.high = high; 215c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 21680fefe0aSRandall Stewart SCTP_LOG_EVENT_MAP, 21780fefe0aSRandall Stewart from, 21880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 21980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 22080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 22180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 222c692df45SMichael Tuexen #endif 223f8829a4aSRandall Stewart } 224f8829a4aSRandall Stewart 225f8829a4aSRandall Stewart void 226dcb68fbaSMichael Tuexen sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from) 227f8829a4aSRandall Stewart { 228c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 229c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 230f8829a4aSRandall Stewart 231bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 23280fefe0aSRandall Stewart sctp_clog.x.fr.largest_tsn = biggest_tsn; 23380fefe0aSRandall Stewart sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn; 23480fefe0aSRandall Stewart sctp_clog.x.fr.tsn = tsn; 235c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 23680fefe0aSRandall Stewart SCTP_LOG_EVENT_FR, 23780fefe0aSRandall Stewart from, 23880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 23980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 24080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 24180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 242c692df45SMichael Tuexen #endif 243f8829a4aSRandall Stewart } 244f8829a4aSRandall Stewart 2454be807c4SMichael Tuexen #ifdef SCTP_MBUF_LOGGING 246f8829a4aSRandall Stewart void 247f8829a4aSRandall Stewart sctp_log_mb(struct mbuf *m, int from) 248f8829a4aSRandall Stewart { 249c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 250c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 251f8829a4aSRandall Stewart 25280fefe0aSRandall Stewart sctp_clog.x.mb.mp = m; 25380fefe0aSRandall Stewart sctp_clog.x.mb.mbuf_flags = (uint8_t)(SCTP_BUF_GET_FLAGS(m)); 25480fefe0aSRandall Stewart sctp_clog.x.mb.size = (uint16_t)(SCTP_BUF_LEN(m)); 25580fefe0aSRandall Stewart sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0); 256139bc87fSRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 25780fefe0aSRandall Stewart sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m); 25880fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m)); 259f8829a4aSRandall Stewart } else { 26080fefe0aSRandall Stewart sctp_clog.x.mb.ext = 0; 26180fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = 0; 262f8829a4aSRandall Stewart } 263c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 26480fefe0aSRandall Stewart SCTP_LOG_EVENT_MBUF, 26580fefe0aSRandall Stewart from, 26680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 26780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 26880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 26980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 270c692df45SMichael Tuexen #endif 271f8829a4aSRandall Stewart } 272f8829a4aSRandall Stewart 273f8829a4aSRandall Stewart void 2744be807c4SMichael Tuexen sctp_log_mbc(struct mbuf *m, int from) 2754be807c4SMichael Tuexen { 2764be807c4SMichael Tuexen struct mbuf *mat; 2774be807c4SMichael Tuexen 2784be807c4SMichael Tuexen for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) { 2794be807c4SMichael Tuexen sctp_log_mb(mat, from); 2804be807c4SMichael Tuexen } 2814be807c4SMichael Tuexen } 2824be807c4SMichael Tuexen #endif 2834be807c4SMichael Tuexen 2844be807c4SMichael Tuexen void 285dcb68fbaSMichael Tuexen sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from) 286f8829a4aSRandall Stewart { 287c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 288c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 289f8829a4aSRandall Stewart 290f8829a4aSRandall Stewart if (control == NULL) { 291ad81507eSRandall Stewart SCTP_PRINTF("Gak log of NULL?\n"); 292f8829a4aSRandall Stewart return; 293f8829a4aSRandall Stewart } 29480fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = control->stcb; 29580fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = control->sinfo_tsn; 29649656eefSMichael Tuexen sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid; 29780fefe0aSRandall Stewart sctp_clog.x.strlog.strm = control->sinfo_stream; 298f8829a4aSRandall Stewart if (poschk != NULL) { 29980fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn; 30049656eefSMichael Tuexen sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid; 301f8829a4aSRandall Stewart } else { 30280fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 30380fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 304f8829a4aSRandall Stewart } 305c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 30680fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 30780fefe0aSRandall Stewart from, 30880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 30980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 31080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 31180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 312c692df45SMichael Tuexen #endif 313f8829a4aSRandall Stewart } 314f8829a4aSRandall Stewart 315f8829a4aSRandall Stewart void 316f8829a4aSRandall Stewart sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from) 317f8829a4aSRandall Stewart { 318c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 319c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 320f8829a4aSRandall Stewart 32180fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 322f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 32380fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 324f8829a4aSRandall Stewart else 32580fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 326f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 32780fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 328f8829a4aSRandall Stewart else 32980fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 330f8829a4aSRandall Stewart 331f8829a4aSRandall Stewart if (net) { 33280fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = net->cwnd; 33380fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 33480fefe0aSRandall Stewart sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack; 33580fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack; 33680fefe0aSRandall Stewart sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack; 337f8829a4aSRandall Stewart } 338f8829a4aSRandall Stewart if (SCTP_CWNDLOG_PRESEND == from) { 33980fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd; 340f8829a4aSRandall Stewart } 34180fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = augment; 342c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 34380fefe0aSRandall Stewart SCTP_LOG_EVENT_CWND, 34480fefe0aSRandall Stewart from, 34580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 34680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 34780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 34880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 349c692df45SMichael Tuexen #endif 350f8829a4aSRandall Stewart } 351f8829a4aSRandall Stewart 352f8829a4aSRandall Stewart void 353f8829a4aSRandall Stewart sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) 354f8829a4aSRandall Stewart { 355c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 356c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 357f8829a4aSRandall Stewart 358bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 35903b0b021SRandall Stewart if (inp) { 36080fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)inp->sctp_socket; 36103b0b021SRandall Stewart 36203b0b021SRandall Stewart } else { 36380fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)NULL; 36403b0b021SRandall Stewart } 36580fefe0aSRandall Stewart sctp_clog.x.lock.inp = (void *)inp; 366f8829a4aSRandall Stewart if (stcb) { 36780fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx); 368f8829a4aSRandall Stewart } else { 36980fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN; 370f8829a4aSRandall Stewart } 371f8829a4aSRandall Stewart if (inp) { 37280fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx); 37380fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx); 374f8829a4aSRandall Stewart } else { 37580fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN; 37680fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN; 377f8829a4aSRandall Stewart } 378b3f1ea41SRandall Stewart sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); 37952129fcdSRandall Stewart if (inp && (inp->sctp_socket)) { 38080fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 38180fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 38280fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx)); 383f8829a4aSRandall Stewart } else { 38480fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN; 38580fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; 38680fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN; 387f8829a4aSRandall Stewart } 388c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 38980fefe0aSRandall Stewart SCTP_LOG_LOCK_EVENT, 39080fefe0aSRandall Stewart from, 39180fefe0aSRandall Stewart sctp_clog.x.misc.log1, 39280fefe0aSRandall Stewart sctp_clog.x.misc.log2, 39380fefe0aSRandall Stewart sctp_clog.x.misc.log3, 39480fefe0aSRandall Stewart sctp_clog.x.misc.log4); 395c692df45SMichael Tuexen #endif 396f8829a4aSRandall Stewart } 397f8829a4aSRandall Stewart 398f8829a4aSRandall Stewart void 399f8829a4aSRandall Stewart sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from) 400f8829a4aSRandall Stewart { 401c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 402c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 403f8829a4aSRandall Stewart 404bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 40580fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 40680fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = error; 40780fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 40880fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = burst; 409f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 41080fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 411f8829a4aSRandall Stewart else 41280fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 413f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 41480fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 415f8829a4aSRandall Stewart else 41680fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 417c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 41880fefe0aSRandall Stewart SCTP_LOG_EVENT_MAXBURST, 41980fefe0aSRandall Stewart from, 42080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 42180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 42280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 42380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 424c692df45SMichael Tuexen #endif 425f8829a4aSRandall Stewart } 426f8829a4aSRandall Stewart 427f8829a4aSRandall Stewart void 428f8829a4aSRandall Stewart sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead) 429f8829a4aSRandall Stewart { 430c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 431c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 432f8829a4aSRandall Stewart 43380fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 43480fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = snd_size; 43580fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 43680fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = 0; 437c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 43880fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 43980fefe0aSRandall Stewart from, 44080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 44180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 44280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 44380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 444c692df45SMichael Tuexen #endif 445f8829a4aSRandall Stewart } 446f8829a4aSRandall Stewart 447f8829a4aSRandall Stewart void 448f8829a4aSRandall Stewart sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval) 449f8829a4aSRandall Stewart { 450c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 451c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 452f8829a4aSRandall Stewart 45380fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 45480fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = flight_size; 45580fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 45680fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = a_rwndval; 457c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 45880fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 45980fefe0aSRandall Stewart from, 46080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 46180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 46280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 46380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 464c692df45SMichael Tuexen #endif 465f8829a4aSRandall Stewart } 466f8829a4aSRandall Stewart 4674be807c4SMichael Tuexen #ifdef SCTP_MBCNT_LOGGING 4684be807c4SMichael Tuexen static void 469f8829a4aSRandall Stewart sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt) 470f8829a4aSRandall Stewart { 471c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 472c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 473f8829a4aSRandall Stewart 47480fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_size = total_oq; 47580fefe0aSRandall Stewart sctp_clog.x.mbcnt.size_change = book; 47680fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q; 47780fefe0aSRandall Stewart sctp_clog.x.mbcnt.mbcnt_change = mbcnt; 478c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 47980fefe0aSRandall Stewart SCTP_LOG_EVENT_MBCNT, 48080fefe0aSRandall Stewart from, 48180fefe0aSRandall Stewart sctp_clog.x.misc.log1, 48280fefe0aSRandall Stewart sctp_clog.x.misc.log2, 48380fefe0aSRandall Stewart sctp_clog.x.misc.log3, 48480fefe0aSRandall Stewart sctp_clog.x.misc.log4); 485c692df45SMichael Tuexen #endif 486f8829a4aSRandall Stewart } 4874be807c4SMichael Tuexen #endif 4884be807c4SMichael Tuexen 489f8829a4aSRandall Stewart void 490f8829a4aSRandall Stewart sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) 491f8829a4aSRandall Stewart { 492c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 493c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 49480fefe0aSRandall Stewart SCTP_LOG_MISC_EVENT, 49580fefe0aSRandall Stewart from, 49680fefe0aSRandall Stewart a, b, c, d); 497c692df45SMichael Tuexen #endif 498f8829a4aSRandall Stewart } 499f8829a4aSRandall Stewart 500f8829a4aSRandall Stewart void 5017215cc1bSMichael Tuexen sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) 502f8829a4aSRandall Stewart { 503c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 504c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 505f8829a4aSRandall Stewart 50680fefe0aSRandall Stewart sctp_clog.x.wake.stcb = (void *)stcb; 50780fefe0aSRandall Stewart sctp_clog.x.wake.wake_cnt = wake_cnt; 50880fefe0aSRandall Stewart sctp_clog.x.wake.flight = stcb->asoc.total_flight_count; 50980fefe0aSRandall Stewart sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt; 51080fefe0aSRandall Stewart sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt; 511f8829a4aSRandall Stewart 512f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt < 0xff) 51380fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = (uint8_t)stcb->asoc.stream_queue_cnt; 514f8829a4aSRandall Stewart else 51580fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = 0xff; 516f8829a4aSRandall Stewart 517f8829a4aSRandall Stewart if (stcb->asoc.chunks_on_out_queue < 0xff) 51880fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = (uint8_t)stcb->asoc.chunks_on_out_queue; 519f8829a4aSRandall Stewart else 52080fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = 0xff; 521f8829a4aSRandall Stewart 52280fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags = 0; 523f8829a4aSRandall Stewart /* set in the defered mode stuff */ 524f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) 52580fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 1; 526f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) 52780fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 2; 528f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) 52980fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 4; 530f8829a4aSRandall Stewart /* what about the sb */ 531f8829a4aSRandall Stewart if (stcb->sctp_socket) { 532f8829a4aSRandall Stewart struct socket *so = stcb->sctp_socket; 533f8829a4aSRandall Stewart 53480fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = (uint8_t)((so->so_snd.sb_flags & 0x00ff)); 535f8829a4aSRandall Stewart } else { 53680fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = 0xff; 537f8829a4aSRandall Stewart } 538c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 53980fefe0aSRandall Stewart SCTP_LOG_EVENT_WAKE, 54080fefe0aSRandall Stewart from, 54180fefe0aSRandall Stewart sctp_clog.x.misc.log1, 54280fefe0aSRandall Stewart sctp_clog.x.misc.log2, 54380fefe0aSRandall Stewart sctp_clog.x.misc.log3, 54480fefe0aSRandall Stewart sctp_clog.x.misc.log4); 545c692df45SMichael Tuexen #endif 546f8829a4aSRandall Stewart } 547f8829a4aSRandall Stewart 548f8829a4aSRandall Stewart void 54958e6eeefSMichael Tuexen sctp_log_block(uint8_t from, struct sctp_association *asoc, ssize_t sendlen) 550f8829a4aSRandall Stewart { 551c692df45SMichael Tuexen #if defined(SCTP_LOCAL_TRACE_BUF) 552c692df45SMichael Tuexen struct sctp_cwnd_log sctp_clog; 553f8829a4aSRandall Stewart 55480fefe0aSRandall Stewart sctp_clog.x.blk.onsb = asoc->total_output_queue_size; 55580fefe0aSRandall Stewart sctp_clog.x.blk.send_sent_qcnt = (uint16_t)(asoc->send_queue_cnt + asoc->sent_queue_cnt); 55680fefe0aSRandall Stewart sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd; 55780fefe0aSRandall Stewart sctp_clog.x.blk.stream_qcnt = (uint16_t)asoc->stream_queue_cnt; 55880fefe0aSRandall Stewart sctp_clog.x.blk.chunks_on_oque = (uint16_t)asoc->chunks_on_out_queue; 55980fefe0aSRandall Stewart sctp_clog.x.blk.flight_size = (uint16_t)(asoc->total_flight / 1024); 5609a8e3088SMichael Tuexen sctp_clog.x.blk.sndlen = (uint32_t)sendlen; 561c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 56280fefe0aSRandall Stewart SCTP_LOG_EVENT_BLOCK, 56380fefe0aSRandall Stewart from, 56480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 56580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 56680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 56780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 568c692df45SMichael Tuexen #endif 569f8829a4aSRandall Stewart } 570f8829a4aSRandall Stewart 571f8829a4aSRandall Stewart int 5727215cc1bSMichael Tuexen sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED) 573f8829a4aSRandall Stewart { 57480fefe0aSRandall Stewart /* May need to fix this if ktrdump does not work */ 575f8829a4aSRandall Stewart return (0); 576f8829a4aSRandall Stewart } 577f8829a4aSRandall Stewart 578f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 579f8829a4aSRandall Stewart uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2]; 580f8829a4aSRandall Stewart static int sctp_audit_indx = 0; 581f8829a4aSRandall Stewart 582f8829a4aSRandall Stewart static 583f8829a4aSRandall Stewart void 584f8829a4aSRandall Stewart sctp_print_audit_report(void) 585f8829a4aSRandall Stewart { 586f8829a4aSRandall Stewart int i; 587f8829a4aSRandall Stewart int cnt; 588f8829a4aSRandall Stewart 589f8829a4aSRandall Stewart cnt = 0; 590f8829a4aSRandall Stewart for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) { 591f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 592f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 593f8829a4aSRandall Stewart cnt = 0; 594ad81507eSRandall Stewart SCTP_PRINTF("\n"); 595f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 596f8829a4aSRandall Stewart cnt = 0; 597ad81507eSRandall Stewart SCTP_PRINTF("\n"); 598f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 599f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 600ad81507eSRandall Stewart SCTP_PRINTF("\n"); 601f8829a4aSRandall Stewart cnt = 0; 602f8829a4aSRandall Stewart } 603ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0], 604f8829a4aSRandall Stewart (uint32_t)sctp_audit_data[i][1]); 605f8829a4aSRandall Stewart cnt++; 606f8829a4aSRandall Stewart if ((cnt % 14) == 0) 607ad81507eSRandall Stewart SCTP_PRINTF("\n"); 608f8829a4aSRandall Stewart } 609f8829a4aSRandall Stewart for (i = 0; i < sctp_audit_indx; i++) { 610f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 611f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 612f8829a4aSRandall Stewart cnt = 0; 613ad81507eSRandall Stewart SCTP_PRINTF("\n"); 614f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 615f8829a4aSRandall Stewart cnt = 0; 616ad81507eSRandall Stewart SCTP_PRINTF("\n"); 617f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 618f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 619ad81507eSRandall Stewart SCTP_PRINTF("\n"); 620f8829a4aSRandall Stewart cnt = 0; 621f8829a4aSRandall Stewart } 622ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t)sctp_audit_data[i][0], 623f8829a4aSRandall Stewart (uint32_t)sctp_audit_data[i][1]); 624f8829a4aSRandall Stewart cnt++; 625f8829a4aSRandall Stewart if ((cnt % 14) == 0) 626ad81507eSRandall Stewart SCTP_PRINTF("\n"); 627f8829a4aSRandall Stewart } 628ad81507eSRandall Stewart SCTP_PRINTF("\n"); 629f8829a4aSRandall Stewart } 630f8829a4aSRandall Stewart 631f8829a4aSRandall Stewart void 632f8829a4aSRandall Stewart sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 633f8829a4aSRandall Stewart struct sctp_nets *net) 634f8829a4aSRandall Stewart { 635f8829a4aSRandall Stewart int resend_cnt, tot_out, rep, tot_book_cnt; 636f8829a4aSRandall Stewart struct sctp_nets *lnet; 637f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 638f8829a4aSRandall Stewart 639f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAA; 640f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from; 641f8829a4aSRandall Stewart sctp_audit_indx++; 642f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 643f8829a4aSRandall Stewart sctp_audit_indx = 0; 644f8829a4aSRandall Stewart } 645f8829a4aSRandall Stewart if (inp == NULL) { 646f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 647f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x01; 648f8829a4aSRandall Stewart sctp_audit_indx++; 649f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 650f8829a4aSRandall Stewart sctp_audit_indx = 0; 651f8829a4aSRandall Stewart } 652f8829a4aSRandall Stewart return; 653f8829a4aSRandall Stewart } 654f8829a4aSRandall Stewart if (stcb == NULL) { 655f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 656f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x02; 657f8829a4aSRandall Stewart sctp_audit_indx++; 658f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 659f8829a4aSRandall Stewart sctp_audit_indx = 0; 660f8829a4aSRandall Stewart } 661f8829a4aSRandall Stewart return; 662f8829a4aSRandall Stewart } 663f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA1; 664f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 665f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 666f8829a4aSRandall Stewart sctp_audit_indx++; 667f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 668f8829a4aSRandall Stewart sctp_audit_indx = 0; 669f8829a4aSRandall Stewart } 670f8829a4aSRandall Stewart rep = 0; 671f8829a4aSRandall Stewart tot_book_cnt = 0; 672f8829a4aSRandall Stewart resend_cnt = tot_out = 0; 673f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 674f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 675f8829a4aSRandall Stewart resend_cnt++; 676f8829a4aSRandall Stewart } else if (chk->sent < SCTP_DATAGRAM_RESEND) { 677f8829a4aSRandall Stewart tot_out += chk->book_size; 678f8829a4aSRandall Stewart tot_book_cnt++; 679f8829a4aSRandall Stewart } 680f8829a4aSRandall Stewart } 681f8829a4aSRandall Stewart if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) { 682f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 683f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA1; 684f8829a4aSRandall Stewart sctp_audit_indx++; 685f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 686f8829a4aSRandall Stewart sctp_audit_indx = 0; 687f8829a4aSRandall Stewart } 688ad81507eSRandall Stewart SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n", 689f8829a4aSRandall Stewart resend_cnt, stcb->asoc.sent_queue_retran_cnt); 690f8829a4aSRandall Stewart rep = 1; 691f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = resend_cnt; 692f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA2; 693f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 694f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 695f8829a4aSRandall Stewart sctp_audit_indx++; 696f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 697f8829a4aSRandall Stewart sctp_audit_indx = 0; 698f8829a4aSRandall Stewart } 699f8829a4aSRandall Stewart } 700f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 701f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 702f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA2; 703f8829a4aSRandall Stewart sctp_audit_indx++; 704f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 705f8829a4aSRandall Stewart sctp_audit_indx = 0; 706f8829a4aSRandall Stewart } 707f8829a4aSRandall Stewart rep = 1; 708ad81507eSRandall Stewart SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out, 709f8829a4aSRandall Stewart (int)stcb->asoc.total_flight); 710f8829a4aSRandall Stewart stcb->asoc.total_flight = tot_out; 711f8829a4aSRandall Stewart } 712f8829a4aSRandall Stewart if (tot_book_cnt != stcb->asoc.total_flight_count) { 713f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 714f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA5; 715f8829a4aSRandall Stewart sctp_audit_indx++; 716f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 717f8829a4aSRandall Stewart sctp_audit_indx = 0; 718f8829a4aSRandall Stewart } 719f8829a4aSRandall Stewart rep = 1; 720f31e6c7fSMichael Tuexen SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt); 721f8829a4aSRandall Stewart 722f8829a4aSRandall Stewart stcb->asoc.total_flight_count = tot_book_cnt; 723f8829a4aSRandall Stewart } 724f8829a4aSRandall Stewart tot_out = 0; 725f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 726f8829a4aSRandall Stewart tot_out += lnet->flight_size; 727f8829a4aSRandall Stewart } 728f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 729f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 730f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA3; 731f8829a4aSRandall Stewart sctp_audit_indx++; 732f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 733f8829a4aSRandall Stewart sctp_audit_indx = 0; 734f8829a4aSRandall Stewart } 735f8829a4aSRandall Stewart rep = 1; 736ad81507eSRandall Stewart SCTP_PRINTF("real flight:%d net total was %d\n", 737f8829a4aSRandall Stewart stcb->asoc.total_flight, tot_out); 738f8829a4aSRandall Stewart /* now corrective action */ 739f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 740f8829a4aSRandall Stewart 741f8829a4aSRandall Stewart tot_out = 0; 742f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 743f8829a4aSRandall Stewart if ((chk->whoTo == lnet) && 744f8829a4aSRandall Stewart (chk->sent < SCTP_DATAGRAM_RESEND)) { 745f8829a4aSRandall Stewart tot_out += chk->book_size; 746f8829a4aSRandall Stewart } 747f8829a4aSRandall Stewart } 748f8829a4aSRandall Stewart if (lnet->flight_size != tot_out) { 749f31e6c7fSMichael Tuexen SCTP_PRINTF("net:%p flight was %d corrected to %d\n", 750dd294dceSMichael Tuexen (void *)lnet, lnet->flight_size, 751ad81507eSRandall Stewart tot_out); 752f8829a4aSRandall Stewart lnet->flight_size = tot_out; 753f8829a4aSRandall Stewart } 754f8829a4aSRandall Stewart } 755f8829a4aSRandall Stewart } 756f8829a4aSRandall Stewart if (rep) { 757f8829a4aSRandall Stewart sctp_print_audit_report(); 758f8829a4aSRandall Stewart } 759f8829a4aSRandall Stewart } 760f8829a4aSRandall Stewart 761f8829a4aSRandall Stewart void 762f8829a4aSRandall Stewart sctp_audit_log(uint8_t ev, uint8_t fd) 763f8829a4aSRandall Stewart { 764f8829a4aSRandall Stewart 765f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = ev; 766f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = fd; 767f8829a4aSRandall Stewart sctp_audit_indx++; 768f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 769f8829a4aSRandall Stewart sctp_audit_indx = 0; 770f8829a4aSRandall Stewart } 771f8829a4aSRandall Stewart } 772f8829a4aSRandall Stewart 773f8829a4aSRandall Stewart #endif 774f8829a4aSRandall Stewart 775f8829a4aSRandall Stewart /* 77612af6654SMichael Tuexen * sctp_stop_timers_for_shutdown() should be called 77712af6654SMichael Tuexen * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT 77812af6654SMichael Tuexen * state to make sure that all timers are stopped. 77912af6654SMichael Tuexen */ 78012af6654SMichael Tuexen void 78112af6654SMichael Tuexen sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) 78212af6654SMichael Tuexen { 7835555400aSMichael Tuexen struct sctp_inpcb *inp; 78412af6654SMichael Tuexen struct sctp_nets *net; 78512af6654SMichael Tuexen 7865555400aSMichael Tuexen inp = stcb->sctp_ep; 78712af6654SMichael Tuexen 7885555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL, 7895555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_12); 7905555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL, 7915555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_13); 7925555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL, 7935555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_14); 7945555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL, 7955555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_15); 7965555400aSMichael Tuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 7975555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 7985555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_16); 7995555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 8005555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_17); 8015555400aSMichael Tuexen } 8025555400aSMichael Tuexen } 8035555400aSMichael Tuexen 8045555400aSMichael Tuexen void 8058803350dSMichael Tuexen sctp_stop_association_timers(struct sctp_tcb *stcb, bool stop_assoc_kill_timer) 8065555400aSMichael Tuexen { 8075555400aSMichael Tuexen struct sctp_inpcb *inp; 8085555400aSMichael Tuexen struct sctp_nets *net; 8095555400aSMichael Tuexen 8105555400aSMichael Tuexen inp = stcb->sctp_ep; 8115555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL, 8125555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_18); 8135555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL, 8145555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_19); 8158803350dSMichael Tuexen if (stop_assoc_kill_timer) { 8165555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, 8175555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_20); 8185555400aSMichael Tuexen } 8195555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL, 8205555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_21); 8215555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL, 8225555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_22); 8235555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNGUARD, inp, stcb, NULL, 8245555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_23); 8255555400aSMichael Tuexen /* Mobility adaptation */ 8265555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, inp, stcb, NULL, 8275555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_24); 8285555400aSMichael Tuexen TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { 8295555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net, 8305555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_25); 8315555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, 8325555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_26); 8335555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, net, 8345555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_27); 8355555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net, 8365555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_28); 8375555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, net, 8385555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_29); 8395555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, 8405555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_30); 8415555400aSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, 8425555400aSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_31); 84312af6654SMichael Tuexen } 84412af6654SMichael Tuexen } 84512af6654SMichael Tuexen 84612af6654SMichael Tuexen /* 847589c42c2SMichael Tuexen * A list of sizes based on typical mtu's, used only if next hop size not 848589c42c2SMichael Tuexen * returned. These values MUST be multiples of 4 and MUST be ordered. 849f8829a4aSRandall Stewart */ 850437fc91aSMichael Tuexen static uint32_t sctp_mtu_sizes[] = { 851f8829a4aSRandall Stewart 68, 852f8829a4aSRandall Stewart 296, 853f8829a4aSRandall Stewart 508, 854f8829a4aSRandall Stewart 512, 855f8829a4aSRandall Stewart 544, 856f8829a4aSRandall Stewart 576, 857589c42c2SMichael Tuexen 1004, 858f8829a4aSRandall Stewart 1492, 859f8829a4aSRandall Stewart 1500, 860f8829a4aSRandall Stewart 1536, 861589c42c2SMichael Tuexen 2000, 862f8829a4aSRandall Stewart 2048, 863f8829a4aSRandall Stewart 4352, 864f8829a4aSRandall Stewart 4464, 86542078d5aSMichael Tuexen 8168, 866589c42c2SMichael Tuexen 17912, 867f8829a4aSRandall Stewart 32000, 868589c42c2SMichael Tuexen 65532 869f8829a4aSRandall Stewart }; 870f8829a4aSRandall Stewart 871f8829a4aSRandall Stewart /* 872589c42c2SMichael Tuexen * Return the largest MTU in sctp_mtu_sizes smaller than val. 873589c42c2SMichael Tuexen * If val is smaller than the minimum, just return the largest 874589c42c2SMichael Tuexen * multiple of 4 smaller or equal to val. 875589c42c2SMichael Tuexen * Ensure that the result is a multiple of 4. 876f8829a4aSRandall Stewart */ 877437fc91aSMichael Tuexen uint32_t 878b0471b4bSMichael Tuexen sctp_get_prev_mtu(uint32_t val) 879b0471b4bSMichael Tuexen { 880437fc91aSMichael Tuexen uint32_t i; 881437fc91aSMichael Tuexen 882eef8d4a9SMichael Tuexen val &= 0xfffffffc; 883437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[0]) { 884437fc91aSMichael Tuexen return (val); 885437fc91aSMichael Tuexen } 886437fc91aSMichael Tuexen for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 887437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[i]) { 888f8829a4aSRandall Stewart break; 889f8829a4aSRandall Stewart } 890f8829a4aSRandall Stewart } 891589c42c2SMichael Tuexen KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0, 892589c42c2SMichael Tuexen ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1)); 893437fc91aSMichael Tuexen return (sctp_mtu_sizes[i - 1]); 894437fc91aSMichael Tuexen } 895437fc91aSMichael Tuexen 896437fc91aSMichael Tuexen /* 897589c42c2SMichael Tuexen * Return the smallest MTU in sctp_mtu_sizes larger than val. 898589c42c2SMichael Tuexen * If val is larger than the maximum, just return the largest multiple of 4 smaller 899589c42c2SMichael Tuexen * or equal to val. 900589c42c2SMichael Tuexen * Ensure that the result is a multiple of 4. 901437fc91aSMichael Tuexen */ 902437fc91aSMichael Tuexen uint32_t 903b0471b4bSMichael Tuexen sctp_get_next_mtu(uint32_t val) 904b0471b4bSMichael Tuexen { 905437fc91aSMichael Tuexen /* select another MTU that is just bigger than this one */ 906437fc91aSMichael Tuexen uint32_t i; 907437fc91aSMichael Tuexen 908eef8d4a9SMichael Tuexen val &= 0xfffffffc; 909437fc91aSMichael Tuexen for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 910437fc91aSMichael Tuexen if (val < sctp_mtu_sizes[i]) { 911589c42c2SMichael Tuexen KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0, 912589c42c2SMichael Tuexen ("sctp_mtu_sizes[%u] not a multiple of 4", i)); 913437fc91aSMichael Tuexen return (sctp_mtu_sizes[i]); 914437fc91aSMichael Tuexen } 915437fc91aSMichael Tuexen } 916437fc91aSMichael Tuexen return (val); 917f8829a4aSRandall Stewart } 918f8829a4aSRandall Stewart 919f8829a4aSRandall Stewart void 920f8829a4aSRandall Stewart sctp_fill_random_store(struct sctp_pcb *m) 921f8829a4aSRandall Stewart { 922f8829a4aSRandall Stewart /* 923f8829a4aSRandall Stewart * Here we use the MD5/SHA-1 to hash with our good randomNumbers and 924f8829a4aSRandall Stewart * our counter. The result becomes our good random numbers and we 925f8829a4aSRandall Stewart * then setup to give these out. Note that we do no locking to 926f8829a4aSRandall Stewart * protect this. This is ok, since if competing folks call this we 92717205eccSRandall Stewart * will get more gobbled gook in the random store which is what we 928f8829a4aSRandall Stewart * want. There is a danger that two guys will use the same random 929f8829a4aSRandall Stewart * numbers, but thats ok too since that is random as well :-> 930f8829a4aSRandall Stewart */ 931f8829a4aSRandall Stewart m->store_at = 0; 932ad81507eSRandall Stewart (void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers, 933f8829a4aSRandall Stewart sizeof(m->random_numbers), (uint8_t *)&m->random_counter, 934f8829a4aSRandall Stewart sizeof(m->random_counter), (uint8_t *)m->random_store); 935f8829a4aSRandall Stewart m->random_counter++; 936f8829a4aSRandall Stewart } 937f8829a4aSRandall Stewart 938f8829a4aSRandall Stewart uint32_t 939b0471b4bSMichael Tuexen sctp_select_initial_TSN(struct sctp_pcb *inp) 940b0471b4bSMichael Tuexen { 941f8829a4aSRandall Stewart /* 942f8829a4aSRandall Stewart * A true implementation should use random selection process to get 943f8829a4aSRandall Stewart * the initial stream sequence number, using RFC1750 as a good 944f8829a4aSRandall Stewart * guideline 945f8829a4aSRandall Stewart */ 946139bc87fSRandall Stewart uint32_t x, *xp; 947f8829a4aSRandall Stewart uint8_t *p; 948851b7298SRandall Stewart int store_at, new_store; 949f8829a4aSRandall Stewart 950851b7298SRandall Stewart if (inp->initial_sequence_debug != 0) { 951f8829a4aSRandall Stewart uint32_t ret; 952f8829a4aSRandall Stewart 953851b7298SRandall Stewart ret = inp->initial_sequence_debug; 954851b7298SRandall Stewart inp->initial_sequence_debug++; 955f8829a4aSRandall Stewart return (ret); 956f8829a4aSRandall Stewart } 957851b7298SRandall Stewart retry: 958851b7298SRandall Stewart store_at = inp->store_at; 959851b7298SRandall Stewart new_store = store_at + sizeof(uint32_t); 960851b7298SRandall Stewart if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) { 961851b7298SRandall Stewart new_store = 0; 962f8829a4aSRandall Stewart } 963851b7298SRandall Stewart if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) { 964851b7298SRandall Stewart goto retry; 965851b7298SRandall Stewart } 966851b7298SRandall Stewart if (new_store == 0) { 967851b7298SRandall Stewart /* Refill the random store */ 968851b7298SRandall Stewart sctp_fill_random_store(inp); 969851b7298SRandall Stewart } 970851b7298SRandall Stewart p = &inp->random_store[store_at]; 971139bc87fSRandall Stewart xp = (uint32_t *)p; 972f8829a4aSRandall Stewart x = *xp; 973f8829a4aSRandall Stewart return (x); 974f8829a4aSRandall Stewart } 975f8829a4aSRandall Stewart 976f8829a4aSRandall Stewart uint32_t 977b0471b4bSMichael Tuexen sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check) 978b0471b4bSMichael Tuexen { 9797215cc1bSMichael Tuexen uint32_t x; 980f8829a4aSRandall Stewart struct timeval now; 981f8829a4aSRandall Stewart 9827215cc1bSMichael Tuexen if (check) { 9836e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 9847215cc1bSMichael Tuexen } 9857215cc1bSMichael Tuexen for (;;) { 986851b7298SRandall Stewart x = sctp_select_initial_TSN(&inp->sctp_ep); 987f8829a4aSRandall Stewart if (x == 0) { 988f8829a4aSRandall Stewart /* we never use 0 */ 989f8829a4aSRandall Stewart continue; 990f8829a4aSRandall Stewart } 9917215cc1bSMichael Tuexen if (!check || sctp_is_vtag_good(x, lport, rport, &now)) { 9927215cc1bSMichael Tuexen break; 993f8829a4aSRandall Stewart } 994f8829a4aSRandall Stewart } 995f8829a4aSRandall Stewart return (x); 996f8829a4aSRandall Stewart } 997f8829a4aSRandall Stewart 998e92c2a8dSMichael Tuexen int32_t 999b0471b4bSMichael Tuexen sctp_map_assoc_state(int kernel_state) 1000b0471b4bSMichael Tuexen { 1001e92c2a8dSMichael Tuexen int32_t user_state; 1002e92c2a8dSMichael Tuexen 1003e92c2a8dSMichael Tuexen if (kernel_state & SCTP_STATE_WAS_ABORTED) { 1004e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 1005e92c2a8dSMichael Tuexen } else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) { 1006e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_PENDING; 1007e92c2a8dSMichael Tuexen } else { 1008e92c2a8dSMichael Tuexen switch (kernel_state & SCTP_STATE_MASK) { 1009e92c2a8dSMichael Tuexen case SCTP_STATE_EMPTY: 1010e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 1011e92c2a8dSMichael Tuexen break; 1012e92c2a8dSMichael Tuexen case SCTP_STATE_INUSE: 1013e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 1014e92c2a8dSMichael Tuexen break; 1015e92c2a8dSMichael Tuexen case SCTP_STATE_COOKIE_WAIT: 1016e92c2a8dSMichael Tuexen user_state = SCTP_COOKIE_WAIT; 1017e92c2a8dSMichael Tuexen break; 1018e92c2a8dSMichael Tuexen case SCTP_STATE_COOKIE_ECHOED: 1019e92c2a8dSMichael Tuexen user_state = SCTP_COOKIE_ECHOED; 1020e92c2a8dSMichael Tuexen break; 1021e92c2a8dSMichael Tuexen case SCTP_STATE_OPEN: 1022e92c2a8dSMichael Tuexen user_state = SCTP_ESTABLISHED; 1023e92c2a8dSMichael Tuexen break; 1024e92c2a8dSMichael Tuexen case SCTP_STATE_SHUTDOWN_SENT: 1025e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_SENT; 1026e92c2a8dSMichael Tuexen break; 1027e92c2a8dSMichael Tuexen case SCTP_STATE_SHUTDOWN_RECEIVED: 1028e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_RECEIVED; 1029e92c2a8dSMichael Tuexen break; 1030e92c2a8dSMichael Tuexen case SCTP_STATE_SHUTDOWN_ACK_SENT: 1031e92c2a8dSMichael Tuexen user_state = SCTP_SHUTDOWN_ACK_SENT; 1032e92c2a8dSMichael Tuexen break; 1033e92c2a8dSMichael Tuexen default: 1034e92c2a8dSMichael Tuexen user_state = SCTP_CLOSED; 1035e92c2a8dSMichael Tuexen break; 1036e92c2a8dSMichael Tuexen } 1037e92c2a8dSMichael Tuexen } 1038e92c2a8dSMichael Tuexen return (user_state); 1039e92c2a8dSMichael Tuexen } 1040e92c2a8dSMichael Tuexen 1041f8829a4aSRandall Stewart int 1042a1cb341bSMichael Tuexen sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1043c979034bSMichael Tuexen uint32_t override_tag, uint32_t vrf_id, uint16_t o_strms) 1044f8829a4aSRandall Stewart { 10450696e120SRandall Stewart struct sctp_association *asoc; 10460696e120SRandall Stewart 1047f8829a4aSRandall Stewart /* 1048f8829a4aSRandall Stewart * Anything set to zero is taken care of by the allocation routine's 1049f8829a4aSRandall Stewart * bzero 1050f8829a4aSRandall Stewart */ 1051f8829a4aSRandall Stewart 1052f8829a4aSRandall Stewart /* 1053f8829a4aSRandall Stewart * Up front select what scoping to apply on addresses I tell my peer 1054f8829a4aSRandall Stewart * Not sure what to do with these right now, we will need to come up 1055f8829a4aSRandall Stewart * with a way to set them. We may need to pass them through from the 1056f8829a4aSRandall Stewart * caller in the sctp_aloc_assoc() function. 1057f8829a4aSRandall Stewart */ 1058f8829a4aSRandall Stewart int i; 1059f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 1060f0396ad1SMichael Tuexen int j; 1061f0396ad1SMichael Tuexen #endif 1062f0396ad1SMichael Tuexen 10630696e120SRandall Stewart asoc = &stcb->asoc; 1064f8829a4aSRandall Stewart /* init all variables to a known value. */ 1065839d21d6SMichael Tuexen SCTP_SET_STATE(stcb, SCTP_STATE_INUSE); 1066a1cb341bSMichael Tuexen asoc->max_burst = inp->sctp_ep.max_burst; 1067a1cb341bSMichael Tuexen asoc->fr_max_burst = inp->sctp_ep.fr_max_burst; 1068a1cb341bSMichael Tuexen asoc->heart_beat_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 1069a1cb341bSMichael Tuexen asoc->cookie_life = inp->sctp_ep.def_cookie_life; 1070a1cb341bSMichael Tuexen asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off; 1071f342355aSMichael Tuexen asoc->ecn_supported = inp->ecn_supported; 1072dd973b0eSMichael Tuexen asoc->prsctp_supported = inp->prsctp_supported; 107344249214SRandall Stewart asoc->idata_supported = inp->idata_supported; 1074c79bec9cSMichael Tuexen asoc->auth_supported = inp->auth_supported; 1075c79bec9cSMichael Tuexen asoc->asconf_supported = inp->asconf_supported; 1076317e00efSMichael Tuexen asoc->reconfig_supported = inp->reconfig_supported; 1077caea9879SMichael Tuexen asoc->nrsack_supported = inp->nrsack_supported; 1078cb9b8e6fSMichael Tuexen asoc->pktdrop_supported = inp->pktdrop_supported; 107944249214SRandall Stewart asoc->idata_supported = inp->idata_supported; 1080ca85e948SMichael Tuexen asoc->sctp_cmt_pf = (uint8_t)0; 1081a1cb341bSMichael Tuexen asoc->sctp_frag_point = inp->sctp_frag_point; 1082a1cb341bSMichael Tuexen asoc->sctp_features = inp->sctp_features; 1083a1cb341bSMichael Tuexen asoc->default_dscp = inp->sctp_ep.default_dscp; 108459b6d5beSMichael Tuexen asoc->max_cwnd = inp->max_cwnd; 108542551e99SRandall Stewart #ifdef INET6 1086a1cb341bSMichael Tuexen if (inp->sctp_ep.default_flowlabel) { 1087a1cb341bSMichael Tuexen asoc->default_flowlabel = inp->sctp_ep.default_flowlabel; 108858bdb691SMichael Tuexen } else { 1089a1cb341bSMichael Tuexen if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) { 1090a1cb341bSMichael Tuexen asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep); 109158bdb691SMichael Tuexen asoc->default_flowlabel &= 0x000fffff; 109258bdb691SMichael Tuexen asoc->default_flowlabel |= 0x80000000; 109358bdb691SMichael Tuexen } else { 1094f8829a4aSRandall Stewart asoc->default_flowlabel = 0; 109558bdb691SMichael Tuexen } 109658bdb691SMichael Tuexen } 1097f8829a4aSRandall Stewart #endif 10989f22f500SRandall Stewart asoc->sb_send_resv = 0; 1099f8829a4aSRandall Stewart if (override_tag) { 1100f8829a4aSRandall Stewart asoc->my_vtag = override_tag; 1101f8829a4aSRandall Stewart } else { 1102a1cb341bSMichael Tuexen asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 1); 1103f8829a4aSRandall Stewart } 1104de0e935bSRandall Stewart /* Get the nonce tags */ 1105a1cb341bSMichael Tuexen asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 1106a1cb341bSMichael Tuexen asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 110742551e99SRandall Stewart asoc->vrf_id = vrf_id; 1108de0e935bSRandall Stewart 110918e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 111018e198d3SRandall Stewart asoc->tsn_in_at = 0; 111118e198d3SRandall Stewart asoc->tsn_out_at = 0; 111218e198d3SRandall Stewart asoc->tsn_in_wrapped = 0; 111318e198d3SRandall Stewart asoc->tsn_out_wrapped = 0; 111418e198d3SRandall Stewart asoc->cumack_log_at = 0; 1115b201f536SRandall Stewart asoc->cumack_log_atsnt = 0; 111618e198d3SRandall Stewart #endif 111718e198d3SRandall Stewart #ifdef SCTP_FS_SPEC_LOG 111818e198d3SRandall Stewart asoc->fs_index = 0; 111918e198d3SRandall Stewart #endif 1120f8829a4aSRandall Stewart asoc->refcnt = 0; 1121f8829a4aSRandall Stewart asoc->assoc_up_sent = 0; 1122f8829a4aSRandall Stewart asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq = 1123a1cb341bSMichael Tuexen sctp_select_initial_TSN(&inp->sctp_ep); 1124c54a18d2SRandall Stewart asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; 1125f8829a4aSRandall Stewart /* we are optimisitic here */ 1126830d754dSRandall Stewart asoc->peer_supports_nat = 0; 1127f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 1128f8829a4aSRandall Stewart 1129f8829a4aSRandall Stewart /* for CMT */ 11308933fa13SRandall Stewart asoc->last_net_cmt_send_started = NULL; 1131f8829a4aSRandall Stewart 1132f8829a4aSRandall Stewart /* This will need to be adjusted */ 1133f8829a4aSRandall Stewart asoc->last_acked_seq = asoc->init_seq_number - 1; 1134f8829a4aSRandall Stewart asoc->advanced_peer_ack_point = asoc->last_acked_seq; 1135f8829a4aSRandall Stewart asoc->asconf_seq_in = asoc->last_acked_seq; 1136f8829a4aSRandall Stewart 1137f8829a4aSRandall Stewart /* here we are different, we hold the next one we expect */ 1138f8829a4aSRandall Stewart asoc->str_reset_seq_in = asoc->last_acked_seq + 1; 1139f8829a4aSRandall Stewart 1140a1cb341bSMichael Tuexen asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max; 1141a1cb341bSMichael Tuexen asoc->initial_rto = inp->sctp_ep.initial_rto; 1142f8829a4aSRandall Stewart 114328a6addeSMichael Tuexen asoc->default_mtu = inp->sctp_ep.default_mtu; 1144a1cb341bSMichael Tuexen asoc->max_init_times = inp->sctp_ep.max_init_times; 1145a1cb341bSMichael Tuexen asoc->max_send_times = inp->sctp_ep.max_send_times; 1146a1cb341bSMichael Tuexen asoc->def_net_failure = inp->sctp_ep.def_net_failure; 1147a1cb341bSMichael Tuexen asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold; 1148f8829a4aSRandall Stewart asoc->free_chunk_cnt = 0; 1149f8829a4aSRandall Stewart 1150f8829a4aSRandall Stewart asoc->iam_blocking = 0; 1151a1cb341bSMichael Tuexen asoc->context = inp->sctp_context; 1152a1cb341bSMichael Tuexen asoc->local_strreset_support = inp->local_strreset_support; 1153a1cb341bSMichael Tuexen asoc->def_send = inp->def_send; 1154a1cb341bSMichael Tuexen asoc->delayed_ack = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 1155a1cb341bSMichael Tuexen asoc->sack_freq = inp->sctp_ep.sctp_sack_freq; 1156f8829a4aSRandall Stewart asoc->pr_sctp_cnt = 0; 1157f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 1158f8829a4aSRandall Stewart 1159a1cb341bSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 1160a1cb341bSMichael Tuexen asoc->scope.ipv6_addr_legal = 1; 1161a1cb341bSMichael Tuexen if (SCTP_IPV6_V6ONLY(inp) == 0) { 1162a1cb341bSMichael Tuexen asoc->scope.ipv4_addr_legal = 1; 1163f8829a4aSRandall Stewart } else { 1164a1cb341bSMichael Tuexen asoc->scope.ipv4_addr_legal = 0; 1165f8829a4aSRandall Stewart } 1166f8829a4aSRandall Stewart } else { 1167a1cb341bSMichael Tuexen asoc->scope.ipv6_addr_legal = 0; 1168a1cb341bSMichael Tuexen asoc->scope.ipv4_addr_legal = 1; 1169f8829a4aSRandall Stewart } 1170f8829a4aSRandall Stewart 1171a1cb341bSMichael Tuexen asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND); 1172a1cb341bSMichael Tuexen asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket); 1173f8829a4aSRandall Stewart 1174a1cb341bSMichael Tuexen asoc->smallest_mtu = inp->sctp_frag_point; 1175a1cb341bSMichael Tuexen asoc->minrto = inp->sctp_ep.sctp_minrto; 1176a1cb341bSMichael Tuexen asoc->maxrto = inp->sctp_ep.sctp_maxrto; 1177f8829a4aSRandall Stewart 1178f8829a4aSRandall Stewart asoc->stream_locked_on = 0; 1179f8829a4aSRandall Stewart asoc->ecn_echo_cnt_onq = 0; 1180f8829a4aSRandall Stewart asoc->stream_locked = 0; 1181f8829a4aSRandall Stewart 118242551e99SRandall Stewart asoc->send_sack = 1; 118342551e99SRandall Stewart 118442551e99SRandall Stewart LIST_INIT(&asoc->sctp_restricted_addrs); 118542551e99SRandall Stewart 1186f8829a4aSRandall Stewart TAILQ_INIT(&asoc->nets); 1187f8829a4aSRandall Stewart TAILQ_INIT(&asoc->pending_reply_queue); 11882afb3e84SRandall Stewart TAILQ_INIT(&asoc->asconf_ack_sent); 1189f8829a4aSRandall Stewart /* Setup to fill the hb random cache at first HB */ 1190f8829a4aSRandall Stewart asoc->hb_random_idx = 4; 1191f8829a4aSRandall Stewart 1192a1cb341bSMichael Tuexen asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time; 1193f8829a4aSRandall Stewart 1194a1cb341bSMichael Tuexen stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module; 1195a1cb341bSMichael Tuexen stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module]; 1196b54d3a6cSRandall Stewart 1197a1cb341bSMichael Tuexen stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module; 1198a1cb341bSMichael Tuexen stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module]; 1199f7a77f6fSMichael Tuexen 1200b54d3a6cSRandall Stewart /* 1201f8829a4aSRandall Stewart * Now the stream parameters, here we allocate space for all streams 1202f8829a4aSRandall Stewart * that we request by default. 1203f8829a4aSRandall Stewart */ 1204ea44232bSRandall Stewart asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams = 1205c979034bSMichael Tuexen o_strms; 1206f8829a4aSRandall Stewart SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *, 1207f8829a4aSRandall Stewart asoc->streamoutcnt * sizeof(struct sctp_stream_out), 1208207304d4SRandall Stewart SCTP_M_STRMO); 1209f8829a4aSRandall Stewart if (asoc->strmout == NULL) { 1210f8829a4aSRandall Stewart /* big trouble no memory */ 1211c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1212f8829a4aSRandall Stewart return (ENOMEM); 1213f8829a4aSRandall Stewart } 1214f8829a4aSRandall Stewart for (i = 0; i < asoc->streamoutcnt; i++) { 1215f8829a4aSRandall Stewart /* 1216f8829a4aSRandall Stewart * inbound side must be set to 0xffff, also NOTE when we get 1217f8829a4aSRandall Stewart * the INIT-ACK back (for INIT sender) we MUST reduce the 1218f8829a4aSRandall Stewart * count (streamoutcnt) but first check if we sent to any of 1219f8829a4aSRandall Stewart * the upper streams that were dropped (if some were). Those 1220f8829a4aSRandall Stewart * that were dropped must be notified to the upper layer as 1221f8829a4aSRandall Stewart * failed to send. 1222f8829a4aSRandall Stewart */ 122363d5b568SMichael Tuexen asoc->strmout[i].next_mid_ordered = 0; 122463d5b568SMichael Tuexen asoc->strmout[i].next_mid_unordered = 0; 1225f8829a4aSRandall Stewart TAILQ_INIT(&asoc->strmout[i].outqueue); 1226325c8c46SMichael Tuexen asoc->strmout[i].chunks_on_queues = 0; 1227f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 1228f0396ad1SMichael Tuexen for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) { 1229f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_sent[j] = 0; 1230f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_unsent[j] = 0; 1231f0396ad1SMichael Tuexen } 1232f0396ad1SMichael Tuexen #else 1233f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_sent[0] = 0; 1234f0396ad1SMichael Tuexen asoc->strmout[i].abandoned_unsent[0] = 0; 1235f0396ad1SMichael Tuexen #endif 123649656eefSMichael Tuexen asoc->strmout[i].sid = i; 1237f8829a4aSRandall Stewart asoc->strmout[i].last_msg_incomplete = 0; 12387cca1775SRandall Stewart asoc->strmout[i].state = SCTP_STREAM_OPENING; 1239d1ea5fa9SMichael Tuexen asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL); 1240f8829a4aSRandall Stewart } 1241f7a77f6fSMichael Tuexen asoc->ss_functions.sctp_ss_init(stcb, asoc, 0); 1242f7a77f6fSMichael Tuexen 1243f8829a4aSRandall Stewart /* Now the mapping array */ 1244f8829a4aSRandall Stewart asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; 1245f8829a4aSRandall Stewart SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size, 1246207304d4SRandall Stewart SCTP_M_MAP); 1247f8829a4aSRandall Stewart if (asoc->mapping_array == NULL) { 1248207304d4SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1249c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1250f8829a4aSRandall Stewart return (ENOMEM); 1251f8829a4aSRandall Stewart } 1252f8829a4aSRandall Stewart memset(asoc->mapping_array, 0, asoc->mapping_array_size); 1253b5c16493SMichael Tuexen SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size, 1254830d754dSRandall Stewart SCTP_M_MAP); 1255bf1be571SRandall Stewart if (asoc->nr_mapping_array == NULL) { 1256bf1be571SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1257bf1be571SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1258bf1be571SRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1259bf1be571SRandall Stewart return (ENOMEM); 1260bf1be571SRandall Stewart } 1261b5c16493SMichael Tuexen memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); 1262830d754dSRandall Stewart 1263f8829a4aSRandall Stewart /* Now the init of the other outqueues */ 1264f8829a4aSRandall Stewart TAILQ_INIT(&asoc->free_chunks); 1265f8829a4aSRandall Stewart TAILQ_INIT(&asoc->control_send_queue); 1266c54a18d2SRandall Stewart TAILQ_INIT(&asoc->asconf_send_queue); 1267f8829a4aSRandall Stewart TAILQ_INIT(&asoc->send_queue); 1268f8829a4aSRandall Stewart TAILQ_INIT(&asoc->sent_queue); 1269f8829a4aSRandall Stewart TAILQ_INIT(&asoc->resetHead); 1270a1cb341bSMichael Tuexen asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome; 1271f8829a4aSRandall Stewart TAILQ_INIT(&asoc->asconf_queue); 1272f8829a4aSRandall Stewart /* authentication fields */ 1273f8829a4aSRandall Stewart asoc->authinfo.random = NULL; 1274830d754dSRandall Stewart asoc->authinfo.active_keyid = 0; 1275f8829a4aSRandall Stewart asoc->authinfo.assoc_key = NULL; 1276f8829a4aSRandall Stewart asoc->authinfo.assoc_keyid = 0; 1277f8829a4aSRandall Stewart asoc->authinfo.recv_key = NULL; 1278f8829a4aSRandall Stewart asoc->authinfo.recv_keyid = 0; 1279f8829a4aSRandall Stewart LIST_INIT(&asoc->shared_keys); 1280f42a358aSRandall Stewart asoc->marked_retrans = 0; 1281a1cb341bSMichael Tuexen asoc->port = inp->sctp_ep.port; 1282f42a358aSRandall Stewart asoc->timoinit = 0; 1283f42a358aSRandall Stewart asoc->timodata = 0; 1284f42a358aSRandall Stewart asoc->timosack = 0; 1285f42a358aSRandall Stewart asoc->timoshutdown = 0; 1286f42a358aSRandall Stewart asoc->timoheartbeat = 0; 1287f42a358aSRandall Stewart asoc->timocookie = 0; 1288f42a358aSRandall Stewart asoc->timoshutdownack = 0; 12896e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&asoc->start_time); 12906e55db54SRandall Stewart asoc->discontinuity_time = asoc->start_time; 1291f0396ad1SMichael Tuexen for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) { 1292f0396ad1SMichael Tuexen asoc->abandoned_unsent[i] = 0; 1293f0396ad1SMichael Tuexen asoc->abandoned_sent[i] = 0; 1294f0396ad1SMichael Tuexen } 1295eacc51c5SRandall Stewart /* 1296eacc51c5SRandall Stewart * sa_ignore MEMLEAK {memory is put in the assoc mapping array and 129777acdc25SRandall Stewart * freed later when the association is freed. 1298eacc51c5SRandall Stewart */ 1299f8829a4aSRandall Stewart return (0); 1300f8829a4aSRandall Stewart } 1301f8829a4aSRandall Stewart 13020e13104dSRandall Stewart void 13030e13104dSRandall Stewart sctp_print_mapping_array(struct sctp_association *asoc) 13040e13104dSRandall Stewart { 1305aed5947cSMichael Tuexen unsigned int i, limit; 13060e13104dSRandall Stewart 1307cd3fd531SMichael Tuexen SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n", 13080e13104dSRandall Stewart asoc->mapping_array_size, 13090e13104dSRandall Stewart asoc->mapping_array_base_tsn, 13100e13104dSRandall Stewart asoc->cumulative_tsn, 1311aed5947cSMichael Tuexen asoc->highest_tsn_inside_map, 1312aed5947cSMichael Tuexen asoc->highest_tsn_inside_nr_map); 1313aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 131460990c0cSMichael Tuexen if (asoc->mapping_array[limit - 1] != 0) { 131577acdc25SRandall Stewart break; 131677acdc25SRandall Stewart } 131777acdc25SRandall Stewart } 1318cd3fd531SMichael Tuexen SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 131977acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1320cd3fd531SMichael Tuexen SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 132177acdc25SRandall Stewart } 1322aed5947cSMichael Tuexen if (limit % 16) 1323cd3fd531SMichael Tuexen SCTP_PRINTF("\n"); 1324aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 1325aed5947cSMichael Tuexen if (asoc->nr_mapping_array[limit - 1]) { 132677acdc25SRandall Stewart break; 132777acdc25SRandall Stewart } 132877acdc25SRandall Stewart } 1329cd3fd531SMichael Tuexen SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 133077acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1331cd3fd531SMichael Tuexen SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 13320e13104dSRandall Stewart } 1333aed5947cSMichael Tuexen if (limit % 16) 1334cd3fd531SMichael Tuexen SCTP_PRINTF("\n"); 13350e13104dSRandall Stewart } 13360e13104dSRandall Stewart 1337f8829a4aSRandall Stewart int 13380696e120SRandall Stewart sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed) 1339f8829a4aSRandall Stewart { 1340f8829a4aSRandall Stewart /* mapping array needs to grow */ 1341b5c16493SMichael Tuexen uint8_t *new_array1, *new_array2; 13420696e120SRandall Stewart uint32_t new_size; 1343f8829a4aSRandall Stewart 13440696e120SRandall Stewart new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR); 1345b5c16493SMichael Tuexen SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP); 1346b5c16493SMichael Tuexen SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP); 1347b5c16493SMichael Tuexen if ((new_array1 == NULL) || (new_array2 == NULL)) { 1348f8829a4aSRandall Stewart /* can't get more, forget it */ 1349b5c16493SMichael Tuexen SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size); 1350b5c16493SMichael Tuexen if (new_array1) { 1351b5c16493SMichael Tuexen SCTP_FREE(new_array1, SCTP_M_MAP); 1352b5c16493SMichael Tuexen } 1353b5c16493SMichael Tuexen if (new_array2) { 1354b5c16493SMichael Tuexen SCTP_FREE(new_array2, SCTP_M_MAP); 1355b5c16493SMichael Tuexen } 1356f8829a4aSRandall Stewart return (-1); 1357f8829a4aSRandall Stewart } 1358b5c16493SMichael Tuexen memset(new_array1, 0, new_size); 1359b5c16493SMichael Tuexen memset(new_array2, 0, new_size); 1360b5c16493SMichael Tuexen memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size); 1361b5c16493SMichael Tuexen memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size); 1362207304d4SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1363830d754dSRandall Stewart SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); 1364b5c16493SMichael Tuexen asoc->mapping_array = new_array1; 1365b5c16493SMichael Tuexen asoc->nr_mapping_array = new_array2; 1366b5c16493SMichael Tuexen asoc->mapping_array_size = new_size; 1367830d754dSRandall Stewart return (0); 1368830d754dSRandall Stewart } 1369830d754dSRandall Stewart 13708933fa13SRandall Stewart 137142551e99SRandall Stewart static void 137242551e99SRandall Stewart sctp_iterator_work(struct sctp_iterator *it) 137342551e99SRandall Stewart { 1374868b51f2SMichael Tuexen struct epoch_tracker et; 1375868b51f2SMichael Tuexen struct sctp_inpcb *tinp; 137642551e99SRandall Stewart int iteration_count = 0; 137742551e99SRandall Stewart int inp_skip = 0; 1378ec4c19fcSRandall Stewart int first_in = 1; 137942551e99SRandall Stewart 1380868b51f2SMichael Tuexen NET_EPOCH_ENTER(et); 1381ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 138242551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1383dcb436c9SMichael Tuexen sctp_it_ctl.cur_it = it; 1384ad81507eSRandall Stewart if (it->inp) { 1385ec4c19fcSRandall Stewart SCTP_INP_RLOCK(it->inp); 138642551e99SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1387ad81507eSRandall Stewart } 138842551e99SRandall Stewart if (it->inp == NULL) { 138942551e99SRandall Stewart /* iterator is complete */ 139042551e99SRandall Stewart done_with_iterator: 1391dcb436c9SMichael Tuexen sctp_it_ctl.cur_it = NULL; 139242551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1393ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 139442551e99SRandall Stewart if (it->function_atend != NULL) { 139542551e99SRandall Stewart (*it->function_atend) (it->pointer, it->val); 139642551e99SRandall Stewart } 1397207304d4SRandall Stewart SCTP_FREE(it, SCTP_M_ITER); 1398868b51f2SMichael Tuexen NET_EPOCH_EXIT(et); 139942551e99SRandall Stewart return; 140042551e99SRandall Stewart } 140142551e99SRandall Stewart select_a_new_ep: 1402ec4c19fcSRandall Stewart if (first_in) { 1403ec4c19fcSRandall Stewart first_in = 0; 1404ec4c19fcSRandall Stewart } else { 1405f7517433SRandall Stewart SCTP_INP_RLOCK(it->inp); 1406ec4c19fcSRandall Stewart } 140742551e99SRandall Stewart while (((it->pcb_flags) && 140842551e99SRandall Stewart ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || 140942551e99SRandall Stewart ((it->pcb_features) && 141042551e99SRandall Stewart ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { 141142551e99SRandall Stewart /* endpoint flags or features don't match, so keep looking */ 141242551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1413f7517433SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 141442551e99SRandall Stewart goto done_with_iterator; 141542551e99SRandall Stewart } 1416ec4c19fcSRandall Stewart tinp = it->inp; 141742551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1418ec4c19fcSRandall Stewart SCTP_INP_RUNLOCK(tinp); 141942551e99SRandall Stewart if (it->inp == NULL) { 142042551e99SRandall Stewart goto done_with_iterator; 142142551e99SRandall Stewart } 142242551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1423f7517433SRandall Stewart } 142442551e99SRandall Stewart /* now go through each assoc which is in the desired state */ 142542551e99SRandall Stewart if (it->done_current_ep == 0) { 142642551e99SRandall Stewart if (it->function_inp != NULL) 142742551e99SRandall Stewart inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val); 142842551e99SRandall Stewart it->done_current_ep = 1; 142942551e99SRandall Stewart } 143042551e99SRandall Stewart if (it->stcb == NULL) { 143142551e99SRandall Stewart /* run the per instance function */ 143242551e99SRandall Stewart it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); 143342551e99SRandall Stewart } 143442551e99SRandall Stewart if ((inp_skip) || it->stcb == NULL) { 143542551e99SRandall Stewart if (it->function_inp_end != NULL) { 143642551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 143742551e99SRandall Stewart it->pointer, 143842551e99SRandall Stewart it->val); 143942551e99SRandall Stewart } 144042551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 144142551e99SRandall Stewart goto no_stcb; 144242551e99SRandall Stewart } 144342551e99SRandall Stewart while (it->stcb) { 144442551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 144542551e99SRandall Stewart if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { 144642551e99SRandall Stewart /* not in the right state... keep looking */ 144742551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 144842551e99SRandall Stewart goto next_assoc; 144942551e99SRandall Stewart } 145042551e99SRandall Stewart /* see if we have limited out the iterator loop */ 145142551e99SRandall Stewart iteration_count++; 145242551e99SRandall Stewart if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { 145342551e99SRandall Stewart /* Pause to let others grab the lock */ 145442551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, 1); 145542551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1456c4739e2fSRandall Stewart SCTP_INP_INCR_REF(it->inp); 145742551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 145842551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1459ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 1460ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 146142551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1462f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags) { 1463f7517433SRandall Stewart /* We won't be staying here */ 1464f7517433SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1465f7517433SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 1466f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1467f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_IT) { 1468f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT; 1469f7517433SRandall Stewart goto done_with_iterator; 1470f7517433SRandall Stewart } 1471f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1472f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_INP) { 1473f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP; 1474f7517433SRandall Stewart goto no_stcb; 1475f7517433SRandall Stewart } 1476f7517433SRandall Stewart /* If we reach here huh? */ 1477cd3fd531SMichael Tuexen SCTP_PRINTF("Unknown it ctl flag %x\n", 1478f7517433SRandall Stewart sctp_it_ctl.iterator_flags); 1479f7517433SRandall Stewart sctp_it_ctl.iterator_flags = 0; 1480f7517433SRandall Stewart } 148142551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1482c4739e2fSRandall Stewart SCTP_INP_DECR_REF(it->inp); 148342551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 148442551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 148542551e99SRandall Stewart iteration_count = 0; 148642551e99SRandall Stewart } 14870053ed28SMichael Tuexen 148842551e99SRandall Stewart /* run function on this one */ 148942551e99SRandall Stewart (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val); 149042551e99SRandall Stewart 149142551e99SRandall Stewart /* 149242551e99SRandall Stewart * we lie here, it really needs to have its own type but 149342551e99SRandall Stewart * first I must verify that this won't effect things :-0 149442551e99SRandall Stewart */ 149542551e99SRandall Stewart if (it->no_chunk_output == 0) 1496ceaad40aSRandall Stewart sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 149742551e99SRandall Stewart 149842551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 149942551e99SRandall Stewart next_assoc: 150042551e99SRandall Stewart it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); 150142551e99SRandall Stewart if (it->stcb == NULL) { 150242551e99SRandall Stewart /* Run last function */ 150342551e99SRandall Stewart if (it->function_inp_end != NULL) { 150442551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 150542551e99SRandall Stewart it->pointer, 150642551e99SRandall Stewart it->val); 150742551e99SRandall Stewart } 150842551e99SRandall Stewart } 150942551e99SRandall Stewart } 151042551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 151142551e99SRandall Stewart no_stcb: 151242551e99SRandall Stewart /* done with all assocs on this endpoint, move on to next endpoint */ 151342551e99SRandall Stewart it->done_current_ep = 0; 151442551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 151542551e99SRandall Stewart it->inp = NULL; 151642551e99SRandall Stewart } else { 151742551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 151842551e99SRandall Stewart } 151942551e99SRandall Stewart if (it->inp == NULL) { 152042551e99SRandall Stewart goto done_with_iterator; 152142551e99SRandall Stewart } 152242551e99SRandall Stewart goto select_a_new_ep; 152342551e99SRandall Stewart } 152442551e99SRandall Stewart 152542551e99SRandall Stewart void 152642551e99SRandall Stewart sctp_iterator_worker(void) 152742551e99SRandall Stewart { 1528397b1c94SMichael Tuexen struct sctp_iterator *it; 152942551e99SRandall Stewart 153042551e99SRandall Stewart /* This function is called with the WQ lock in place */ 1531f7517433SRandall Stewart sctp_it_ctl.iterator_running = 1; 1532397b1c94SMichael Tuexen while ((it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead)) != NULL) { 153342551e99SRandall Stewart /* now lets work on this one */ 1534f7517433SRandall Stewart TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); 153542551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_UNLOCK(); 1536f7517433SRandall Stewart CURVNET_SET(it->vn); 153742551e99SRandall Stewart sctp_iterator_work(it); 1538f7517433SRandall Stewart CURVNET_RESTORE(); 153942551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_LOCK(); 15403c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 154142551e99SRandall Stewart } 1542f7517433SRandall Stewart sctp_it_ctl.iterator_running = 0; 154342551e99SRandall Stewart return; 154442551e99SRandall Stewart } 154542551e99SRandall Stewart 1546f8829a4aSRandall Stewart 1547f8829a4aSRandall Stewart static void 1548f8829a4aSRandall Stewart sctp_handle_addr_wq(void) 1549f8829a4aSRandall Stewart { 1550f8829a4aSRandall Stewart /* deal with the ADDR wq from the rtsock calls */ 15514a9ef3f8SMichael Tuexen struct sctp_laddr *wi, *nwi; 155242551e99SRandall Stewart struct sctp_asconf_iterator *asc; 1553f8829a4aSRandall Stewart 155442551e99SRandall Stewart SCTP_MALLOC(asc, struct sctp_asconf_iterator *, 1555207304d4SRandall Stewart sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT); 155642551e99SRandall Stewart if (asc == NULL) { 155742551e99SRandall Stewart /* Try later, no memory */ 1558f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 1559f8829a4aSRandall Stewart (struct sctp_inpcb *)NULL, 1560f8829a4aSRandall Stewart (struct sctp_tcb *)NULL, 1561f8829a4aSRandall Stewart (struct sctp_nets *)NULL); 156242551e99SRandall Stewart return; 1563f8829a4aSRandall Stewart } 156442551e99SRandall Stewart LIST_INIT(&asc->list_of_work); 156542551e99SRandall Stewart asc->cnt = 0; 1566f7517433SRandall Stewart 15674a9ef3f8SMichael Tuexen LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { 156842551e99SRandall Stewart LIST_REMOVE(wi, sctp_nxt_addr); 156942551e99SRandall Stewart LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); 157042551e99SRandall Stewart asc->cnt++; 1571f8829a4aSRandall Stewart } 1572f7517433SRandall Stewart 157342551e99SRandall Stewart if (asc->cnt == 0) { 1574207304d4SRandall Stewart SCTP_FREE(asc, SCTP_M_ASC_IT); 157542551e99SRandall Stewart } else { 15762b1c7de4SMichael Tuexen int ret; 15772b1c7de4SMichael Tuexen 15782b1c7de4SMichael Tuexen ret = sctp_initiate_iterator(sctp_asconf_iterator_ep, 15791b649582SRandall Stewart sctp_asconf_iterator_stcb, 158042551e99SRandall Stewart NULL, /* No ep end for boundall */ 158142551e99SRandall Stewart SCTP_PCB_FLAGS_BOUNDALL, 158242551e99SRandall Stewart SCTP_PCB_ANY_FEATURES, 15831b649582SRandall Stewart SCTP_ASOC_ANY_STATE, 15841b649582SRandall Stewart (void *)asc, 0, 15851b649582SRandall Stewart sctp_asconf_iterator_end, NULL, 0); 15862b1c7de4SMichael Tuexen if (ret) { 15872b1c7de4SMichael Tuexen SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n"); 1588b7b84c0eSMichael Tuexen /* 1589b7b84c0eSMichael Tuexen * Freeing if we are stopping or put back on the 1590b7b84c0eSMichael Tuexen * addr_wq. 1591b7b84c0eSMichael Tuexen */ 15922b1c7de4SMichael Tuexen if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) { 15932b1c7de4SMichael Tuexen sctp_asconf_iterator_end(asc, 0); 15942b1c7de4SMichael Tuexen } else { 15952b1c7de4SMichael Tuexen LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) { 15962b1c7de4SMichael Tuexen LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 15972b1c7de4SMichael Tuexen } 15982b1c7de4SMichael Tuexen SCTP_FREE(asc, SCTP_M_ASC_IT); 15992b1c7de4SMichael Tuexen } 16002b1c7de4SMichael Tuexen } 160142551e99SRandall Stewart } 1602f8829a4aSRandall Stewart } 1603f8829a4aSRandall Stewart 1604*a412576eSMichael Tuexen /*- 1605*a412576eSMichael Tuexen * The following table shows which pointers for the inp, stcb, or net are 1606*a412576eSMichael Tuexen * stored for each timer after it was started. 1607*a412576eSMichael Tuexen * 1608*a412576eSMichael Tuexen *|Name |Timer |inp |stcb|net | 1609*a412576eSMichael Tuexen *|-----------------------------|-----------------------------|----|----|----| 1610*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SEND |net->rxt_timer |Yes |Yes |Yes | 1611*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_INIT |net->rxt_timer |Yes |Yes |Yes | 1612*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_RECV |stcb->asoc.dack_timer |Yes |Yes |No | 1613*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SHUTDOWN |net->rxt_timer |Yes |Yes |Yes | 1614*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_HEARTBEAT |net->hb_timer |Yes |Yes |Yes | 1615*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_COOKIE |net->rxt_timer |Yes |Yes |Yes | 1616*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_NEWCOOKIE |inp->sctp_ep.signature_change|Yes |No |No | 1617*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_PATHMTURAISE |net->pmtu_timer |Yes |Yes |Yes | 1618*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SHUTDOWNACK |net->rxt_timer |Yes |Yes |Yes | 1619*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_ASCONF |stcb->asoc.asconf_timer |Yes |Yes |Yes | 1620*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SHUTDOWNGUARD|stcb->asoc.shut_guard_timer |Yes |Yes |No | 1621*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_AUTOCLOSE |stcb->asoc.autoclose_timer |Yes |Yes |No | 1622*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_STRRESET |stcb->asoc.strreset_timer |Yes |Yes |No | 1623*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_INPKILL |inp->sctp_ep.signature_change|Yes |No |No | 1624*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_ASOCKILL |stcb->asoc.strreset_timer |Yes |Yes |No | 1625*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_ADDR_WQ |SCTP_BASE_INFO(addr_wq_timer)|No |No |No | 1626*a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_PRIM_DELETED |stcb->asoc.delete_prim_timer |Yes |Yes |No | 1627*a412576eSMichael Tuexen */ 1628*a412576eSMichael Tuexen 1629f8829a4aSRandall Stewart void 1630f8829a4aSRandall Stewart sctp_timeout_handler(void *t) 1631f8829a4aSRandall Stewart { 1632868b51f2SMichael Tuexen struct epoch_tracker et; 1633*a412576eSMichael Tuexen struct timeval tv; 1634f8829a4aSRandall Stewart struct sctp_inpcb *inp; 1635f8829a4aSRandall Stewart struct sctp_tcb *stcb; 1636f8829a4aSRandall Stewart struct sctp_nets *net; 1637f8829a4aSRandall Stewart struct sctp_timer *tmr; 1638267dbe63SMichael Tuexen struct mbuf *op_err; 1639ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1640ceaad40aSRandall Stewart struct socket *so; 1641ceaad40aSRandall Stewart #endif 1642548f47a8SMichael Tuexen int did_output; 1643fa89f692SMichael Tuexen int type; 1644*a412576eSMichael Tuexen int i, secret; 1645f8829a4aSRandall Stewart 1646f8829a4aSRandall Stewart tmr = (struct sctp_timer *)t; 1647f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)tmr->ep; 1648f8829a4aSRandall Stewart stcb = (struct sctp_tcb *)tmr->tcb; 1649f8829a4aSRandall Stewart net = (struct sctp_nets *)tmr->net; 16508518270eSMichael Tuexen CURVNET_SET((struct vnet *)tmr->vnet); 1651f8829a4aSRandall Stewart did_output = 1; 1652f8829a4aSRandall Stewart 1653f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1654f8829a4aSRandall Stewart sctp_audit_log(0xF0, (uint8_t)tmr->type); 1655f8829a4aSRandall Stewart sctp_auditing(3, inp, stcb, net); 1656f8829a4aSRandall Stewart #endif 1657f8829a4aSRandall Stewart 1658f8829a4aSRandall Stewart /* sanity checks... */ 1659*a412576eSMichael Tuexen KASSERT(tmr->self == tmr, ("tmr->self corrupted")); 1660*a412576eSMichael Tuexen KASSERT(SCTP_IS_TIMER_TYPE_VALID(tmr->type), ("Invalid timer type %d", tmr->type)); 1661*a412576eSMichael Tuexen type = tmr->type; 1662a5d547adSRandall Stewart tmr->stopped_from = 0xa001; 1663f8829a4aSRandall Stewart if (inp) { 1664f8829a4aSRandall Stewart SCTP_INP_INCR_REF(inp); 1665aa1808b7SMichael Tuexen if ((inp->sctp_socket == NULL) && 1666*a412576eSMichael Tuexen ((type != SCTP_TIMER_TYPE_INPKILL) && 1667*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_INIT) && 1668*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SEND) && 1669*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_RECV) && 1670*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_HEARTBEAT) && 1671*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SHUTDOWN) && 1672*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SHUTDOWNACK) && 1673*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) && 1674*a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_ASOCKILL))) { 1675f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 16768518270eSMichael Tuexen CURVNET_RESTORE(); 1677*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 1678*a412576eSMichael Tuexen "Timer type = %d handler exiting due to closed socket\n", 1679*a412576eSMichael Tuexen type); 1680f8829a4aSRandall Stewart return; 1681f8829a4aSRandall Stewart } 1682f8829a4aSRandall Stewart } 1683*a412576eSMichael Tuexen tmr->stopped_from = 0xa002; 1684f8829a4aSRandall Stewart if (stcb) { 1685c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1686f8829a4aSRandall Stewart if (stcb->asoc.state == 0) { 1687c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1688f8829a4aSRandall Stewart if (inp) { 1689f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1690f8829a4aSRandall Stewart } 16918518270eSMichael Tuexen CURVNET_RESTORE(); 1692*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 1693*a412576eSMichael Tuexen "Timer type = %d handler exiting due to CLOSED association\n", 1694*a412576eSMichael Tuexen type); 1695f8829a4aSRandall Stewart return; 1696f8829a4aSRandall Stewart } 1697f8829a4aSRandall Stewart } 1698*a412576eSMichael Tuexen tmr->stopped_from = 0xa003; 1699fa89f692SMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", type); 1700139bc87fSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 1701f8829a4aSRandall Stewart if (inp) { 1702f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1703f8829a4aSRandall Stewart } 1704207304d4SRandall Stewart if (stcb) { 1705207304d4SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1706207304d4SRandall Stewart } 17078518270eSMichael Tuexen CURVNET_RESTORE(); 1708*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 1709*a412576eSMichael Tuexen "Timer type = %d handler exiting due to not being active\n", 1710*a412576eSMichael Tuexen type); 1711f8829a4aSRandall Stewart return; 1712f8829a4aSRandall Stewart } 1713*a412576eSMichael Tuexen tmr->stopped_from = 0xa004; 1714a5d547adSRandall Stewart 1715f8829a4aSRandall Stewart if (stcb) { 1716f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 171750cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1718fa89f692SMichael Tuexen if ((type != SCTP_TIMER_TYPE_ASOCKILL) && 1719b54d3a6cSRandall Stewart ((stcb->asoc.state == 0) || 1720b54d3a6cSRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { 1721b54d3a6cSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1722b54d3a6cSRandall Stewart if (inp) { 1723b54d3a6cSRandall Stewart SCTP_INP_DECR_REF(inp); 1724b54d3a6cSRandall Stewart } 17258518270eSMichael Tuexen CURVNET_RESTORE(); 1726*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 1727*a412576eSMichael Tuexen "Timer type = %d handler exiting due to CLOSED association\n", 1728*a412576eSMichael Tuexen type); 1729b54d3a6cSRandall Stewart return; 1730b54d3a6cSRandall Stewart } 17312c62ba73SMichael Tuexen } else if (inp != NULL) { 17322c62ba73SMichael Tuexen SCTP_INP_WLOCK(inp); 17332c62ba73SMichael Tuexen } else { 17342c62ba73SMichael Tuexen SCTP_WQ_ADDR_LOCK(); 1735f8829a4aSRandall Stewart } 1736cd0a4ff6SPedro F. Giffuni /* record in stopped what t-o occurred */ 1737fa89f692SMichael Tuexen tmr->stopped_from = type; 173844b7479bSRandall Stewart 1739868b51f2SMichael Tuexen NET_EPOCH_ENTER(et); 1740f8829a4aSRandall Stewart /* mark as being serviced now */ 174144b7479bSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 174244b7479bSRandall Stewart /* 174344b7479bSRandall Stewart * Callout has been rescheduled. 174444b7479bSRandall Stewart */ 174544b7479bSRandall Stewart goto get_out; 174644b7479bSRandall Stewart } 174744b7479bSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 174844b7479bSRandall Stewart /* 174944b7479bSRandall Stewart * Not active, so no action. 175044b7479bSRandall Stewart */ 175144b7479bSRandall Stewart goto get_out; 175244b7479bSRandall Stewart } 1753139bc87fSRandall Stewart SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); 1754f8829a4aSRandall Stewart 1755f8829a4aSRandall Stewart /* call the handler for the appropriate timer type */ 1756fa89f692SMichael Tuexen switch (type) { 1757f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 1758*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1759*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1760*a412576eSMichael Tuexen type, inp, stcb, net)); 1761f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timodata); 1762f42a358aSRandall Stewart stcb->asoc.timodata++; 1763f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 1764f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 1765f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 1766f8829a4aSRandall Stewart } 1767b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 176860990c0cSMichael Tuexen if (sctp_t3rxt_timer(inp, stcb, net)) { 1769f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1770f8829a4aSRandall Stewart 1771f8829a4aSRandall Stewart goto out_decr; 1772f8829a4aSRandall Stewart } 1773b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1774f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1775f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1776f8829a4aSRandall Stewart #endif 1777ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1778f8829a4aSRandall Stewart if ((stcb->asoc.num_send_timers_up == 0) && 17794a9ef3f8SMichael Tuexen (stcb->asoc.sent_queue_cnt > 0)) { 1780f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 1781f8829a4aSRandall Stewart 1782f8829a4aSRandall Stewart /* 1783f8829a4aSRandall Stewart * safeguard. If there on some on the sent queue 1784f8829a4aSRandall Stewart * somewhere but no timers running something is 1785f8829a4aSRandall Stewart * wrong... so we start a timer on the first chunk 1786f8829a4aSRandall Stewart * on the send queue on whatever net it is sent to. 1787f8829a4aSRandall Stewart */ 1788f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 1789f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, 1790f8829a4aSRandall Stewart chk->whoTo); 1791f8829a4aSRandall Stewart } 1792f8829a4aSRandall Stewart break; 1793f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 1794*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1795*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1796*a412576eSMichael Tuexen type, inp, stcb, net)); 1797f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinit); 1798f42a358aSRandall Stewart stcb->asoc.timoinit++; 1799f8829a4aSRandall Stewart if (sctp_t1init_timer(inp, stcb, net)) { 1800f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1801f8829a4aSRandall Stewart goto out_decr; 1802f8829a4aSRandall Stewart } 1803f8829a4aSRandall Stewart /* We do output but not here */ 1804f8829a4aSRandall Stewart did_output = 0; 1805f8829a4aSRandall Stewart break; 1806f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 1807*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1808*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1809*a412576eSMichael Tuexen type, inp, stcb, net)); 1810f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosack); 1811f42a358aSRandall Stewart stcb->asoc.timosack++; 1812689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); 1813f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1814*a412576eSMichael Tuexen sctp_auditing(4, inp, stcb, NULL); 1815f8829a4aSRandall Stewart #endif 1816ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED); 1817f8829a4aSRandall Stewart break; 1818f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 1819*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1820*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1821*a412576eSMichael Tuexen type, inp, stcb, net)); 1822*a412576eSMichael Tuexen SCTP_STAT_INCR(sctps_timoshutdown); 1823*a412576eSMichael Tuexen stcb->asoc.timoshutdown++; 1824f8829a4aSRandall Stewart if (sctp_shutdown_timer(inp, stcb, net)) { 1825f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1826f8829a4aSRandall Stewart goto out_decr; 1827f8829a4aSRandall Stewart } 1828f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1829f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1830f8829a4aSRandall Stewart #endif 1831ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); 1832f8829a4aSRandall Stewart break; 1833f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 1834*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1835*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1836*a412576eSMichael Tuexen type, inp, stcb, net)); 1837f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoheartbeat); 1838f42a358aSRandall Stewart stcb->asoc.timoheartbeat++; 1839ca85e948SMichael Tuexen if (sctp_heartbeat_timer(inp, stcb, net)) { 1840f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1841f8829a4aSRandall Stewart goto out_decr; 1842f8829a4aSRandall Stewart } 1843f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1844ca85e948SMichael Tuexen sctp_auditing(4, inp, stcb, net); 1845f8829a4aSRandall Stewart #endif 1846ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 1847629749b6SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 1848ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); 1849f8829a4aSRandall Stewart } 1850f8829a4aSRandall Stewart break; 1851f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 1852*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1853*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1854*a412576eSMichael Tuexen type, inp, stcb, net)); 1855*a412576eSMichael Tuexen SCTP_STAT_INCR(sctps_timocookie); 1856*a412576eSMichael Tuexen stcb->asoc.timocookie++; 1857f8829a4aSRandall Stewart if (sctp_cookie_timer(inp, stcb, net)) { 1858f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1859f8829a4aSRandall Stewart goto out_decr; 1860f8829a4aSRandall Stewart } 1861f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1862f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1863f8829a4aSRandall Stewart #endif 1864f8829a4aSRandall Stewart /* 1865f8829a4aSRandall Stewart * We consider T3 and Cookie timer pretty much the same with 1866f8829a4aSRandall Stewart * respect to where from in chunk_output. 1867f8829a4aSRandall Stewart */ 1868ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1869f8829a4aSRandall Stewart break; 1870f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 1871*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb == NULL && net == NULL, 1872*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1873*a412576eSMichael Tuexen type, inp, stcb, net)); 1874f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosecret); 18756e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tv); 1876f8829a4aSRandall Stewart inp->sctp_ep.time_of_secret_change = tv.tv_sec; 1877f8829a4aSRandall Stewart inp->sctp_ep.last_secret_number = 1878f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number; 1879f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number++; 1880f8829a4aSRandall Stewart if (inp->sctp_ep.current_secret_number >= 1881f8829a4aSRandall Stewart SCTP_HOW_MANY_SECRETS) { 1882f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number = 0; 1883f8829a4aSRandall Stewart } 1884f8829a4aSRandall Stewart secret = (int)inp->sctp_ep.current_secret_number; 1885f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) { 1886f8829a4aSRandall Stewart inp->sctp_ep.secret_key[secret][i] = 1887f8829a4aSRandall Stewart sctp_select_initial_TSN(&inp->sctp_ep); 1888f8829a4aSRandall Stewart } 18896fb7b4fbSMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL); 1890f8829a4aSRandall Stewart did_output = 0; 1891f8829a4aSRandall Stewart break; 1892f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 1893*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1894*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1895*a412576eSMichael Tuexen type, inp, stcb, net)); 1896f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timopathmtu); 1897f8829a4aSRandall Stewart sctp_pathmtu_timer(inp, stcb, net); 1898f8829a4aSRandall Stewart did_output = 0; 1899f8829a4aSRandall Stewart break; 1900f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 1901*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1902*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1903*a412576eSMichael Tuexen type, inp, stcb, net)); 1904f8829a4aSRandall Stewart if (sctp_shutdownack_timer(inp, stcb, net)) { 1905f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1906f8829a4aSRandall Stewart goto out_decr; 1907f8829a4aSRandall Stewart } 1908f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownack); 1909f42a358aSRandall Stewart stcb->asoc.timoshutdownack++; 1910f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1911f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1912f8829a4aSRandall Stewart #endif 1913ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED); 1914f8829a4aSRandall Stewart break; 1915f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 1916*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1917*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1918*a412576eSMichael Tuexen type, inp, stcb, net)); 1919*a412576eSMichael Tuexen SCTP_STAT_INCR(sctps_timoasconf); 1920f8829a4aSRandall Stewart if (sctp_asconf_timer(inp, stcb, net)) { 1921f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1922f8829a4aSRandall Stewart goto out_decr; 1923f8829a4aSRandall Stewart } 1924f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1925f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1926f8829a4aSRandall Stewart #endif 1927ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); 1928f8829a4aSRandall Stewart break; 19290554e01dSMichael Tuexen case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 1930*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1931*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1932*a412576eSMichael Tuexen type, inp, stcb, net)); 19330554e01dSMichael Tuexen SCTP_STAT_INCR(sctps_timoshutdownguard); 19340554e01dSMichael Tuexen op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), 19350554e01dSMichael Tuexen "Shutdown guard timer expired"); 19360554e01dSMichael Tuexen sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); 19370554e01dSMichael Tuexen /* no need to unlock on tcb its gone */ 19380554e01dSMichael Tuexen goto out_decr; 1939f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 1940*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1941*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1942*a412576eSMichael Tuexen type, inp, stcb, net)); 1943f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoautoclose); 1944a57fb68bSMichael Tuexen sctp_autoclose_timer(inp, stcb); 1945ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); 1946f8829a4aSRandall Stewart did_output = 0; 1947f8829a4aSRandall Stewart break; 19480554e01dSMichael Tuexen case SCTP_TIMER_TYPE_STRRESET: 1949*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1950*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1951*a412576eSMichael Tuexen type, inp, stcb, net)); 1952*a412576eSMichael Tuexen SCTP_STAT_INCR(sctps_timostrmrst); 1953e95b3d7fSMichael Tuexen if (sctp_strreset_timer(inp, stcb)) { 19540554e01dSMichael Tuexen /* no need to unlock on tcb its gone */ 19550554e01dSMichael Tuexen goto out_decr; 19560554e01dSMichael Tuexen } 19570554e01dSMichael Tuexen sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); 19580554e01dSMichael Tuexen break; 19590554e01dSMichael Tuexen case SCTP_TIMER_TYPE_INPKILL: 1960*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb == NULL && net == NULL, 1961*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1962*a412576eSMichael Tuexen type, inp, stcb, net)); 19630554e01dSMichael Tuexen SCTP_STAT_INCR(sctps_timoinpkill); 19640554e01dSMichael Tuexen /* 19650554e01dSMichael Tuexen * special case, take away our increment since WE are the 19660554e01dSMichael Tuexen * killer 19670554e01dSMichael Tuexen */ 19680554e01dSMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, 19690554e01dSMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_3); 1970*a412576eSMichael Tuexen SCTP_INP_DECR_REF(inp); 1971*a412576eSMichael Tuexen SCTP_INP_WUNLOCK(inp); 19720554e01dSMichael Tuexen sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 19730554e01dSMichael Tuexen SCTP_CALLED_FROM_INPKILL_TIMER); 19740554e01dSMichael Tuexen inp = NULL; 19750554e01dSMichael Tuexen goto out_no_decr; 1976f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 1977*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1978*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1979*a412576eSMichael Tuexen type, inp, stcb, net)); 1980f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoassockill); 1981f8829a4aSRandall Stewart /* Can we free it yet? */ 1982f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1983ba785902SMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, 1984ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_1); 1985ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1986ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 1987ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1988ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1989ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 1990ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 1991ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 1992ceaad40aSRandall Stewart #endif 1993ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 1994ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_2); 1995ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1996ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 1997ceaad40aSRandall Stewart #endif 1998f8829a4aSRandall Stewart /* 1999f8829a4aSRandall Stewart * free asoc, always unlocks (or destroy's) so prevent 2000f8829a4aSRandall Stewart * duplicate unlock or unlock of a free mtx :-0 2001f8829a4aSRandall Stewart */ 2002f8829a4aSRandall Stewart stcb = NULL; 2003f8829a4aSRandall Stewart goto out_no_decr; 20040554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ADDR_WQ: 2005*a412576eSMichael Tuexen KASSERT(inp == NULL && stcb == NULL && net == NULL, 2006*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 2007*a412576eSMichael Tuexen type, inp, stcb, net)); 20080554e01dSMichael Tuexen sctp_handle_addr_wq(); 20090554e01dSMichael Tuexen break; 20100554e01dSMichael Tuexen case SCTP_TIMER_TYPE_PRIM_DELETED: 2011*a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 2012*a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 2013*a412576eSMichael Tuexen type, inp, stcb, net)); 20140554e01dSMichael Tuexen SCTP_STAT_INCR(sctps_timodelprim); 2015*a412576eSMichael Tuexen sctp_delete_prim_timer(inp, stcb); 20160554e01dSMichael Tuexen break; 2017f8829a4aSRandall Stewart default: 2018*a412576eSMichael Tuexen panic("Unknown timer type %d", type); 201960990c0cSMichael Tuexen } 2020f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 2021fa89f692SMichael Tuexen sctp_audit_log(0xF1, (uint8_t)type); 2022f8829a4aSRandall Stewart if (inp) 2023f8829a4aSRandall Stewart sctp_auditing(5, inp, stcb, net); 2024f8829a4aSRandall Stewart #endif 2025f8829a4aSRandall Stewart if ((did_output) && stcb) { 2026f8829a4aSRandall Stewart /* 2027f8829a4aSRandall Stewart * Now we need to clean up the control chunk chain if an 2028f8829a4aSRandall Stewart * ECNE is on it. It must be marked as UNSENT again so next 2029f8829a4aSRandall Stewart * call will continue to send it until such time that we get 2030f8829a4aSRandall Stewart * a CWR, to remove it. It is, however, less likely that we 2031f8829a4aSRandall Stewart * will find a ecn echo on the chain though. 2032f8829a4aSRandall Stewart */ 2033f8829a4aSRandall Stewart sctp_fix_ecn_echo(&stcb->asoc); 2034f8829a4aSRandall Stewart } 203544b7479bSRandall Stewart get_out: 2036f8829a4aSRandall Stewart if (stcb) { 2037f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 20382c62ba73SMichael Tuexen } else if (inp != NULL) { 20392c62ba73SMichael Tuexen SCTP_INP_WUNLOCK(inp); 20402c62ba73SMichael Tuexen } else { 20412c62ba73SMichael Tuexen SCTP_WQ_ADDR_UNLOCK(); 2042f8829a4aSRandall Stewart } 20432c62ba73SMichael Tuexen 2044f8829a4aSRandall Stewart out_decr: 2045f8829a4aSRandall Stewart if (inp) { 2046f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 2047f8829a4aSRandall Stewart } 20480053ed28SMichael Tuexen 2049f8829a4aSRandall Stewart out_no_decr: 2050*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type = %d handler finished\n", type); 20518518270eSMichael Tuexen CURVNET_RESTORE(); 2052868b51f2SMichael Tuexen NET_EPOCH_EXIT(et); 2053f8829a4aSRandall Stewart } 2054f8829a4aSRandall Stewart 2055*a412576eSMichael Tuexen /*- 2056*a412576eSMichael Tuexen * The following table shows which parameters must be provided 2057*a412576eSMichael Tuexen * when calling sctp_timer_start(). For parameters not being 2058*a412576eSMichael Tuexen * provided, NULL must be used. 2059*a412576eSMichael Tuexen * 2060*a412576eSMichael Tuexen * |Name |inp |stcb|net | 2061*a412576eSMichael Tuexen * |-----------------------------|----|----|----| 2062*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes | 2063*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes | 2064*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No | 2065*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes | 2066*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes | 2067*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes | 2068*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No | 2069*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes | 2070*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes | 2071*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |Yes | 2072*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No | 2073*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No | 2074*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |Yes | 2075*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No | 2076*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No | 2077*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No | 2078*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No | 2079*a412576eSMichael Tuexen * 2080*a412576eSMichael Tuexen */ 2081*a412576eSMichael Tuexen 2082ad81507eSRandall Stewart void 2083f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2084f8829a4aSRandall Stewart struct sctp_nets *net) 2085f8829a4aSRandall Stewart { 2086f8829a4aSRandall Stewart struct sctp_timer *tmr; 2087*a412576eSMichael Tuexen uint32_t to_ticks; 2088*a412576eSMichael Tuexen uint32_t rndval, jitter; 2089f8829a4aSRandall Stewart 2090f8829a4aSRandall Stewart tmr = NULL; 2091*a412576eSMichael Tuexen to_ticks = 0; 2092*a412576eSMichael Tuexen if (stcb != NULL) { 2093f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2094*a412576eSMichael Tuexen } else if (inp != NULL) { 2095*a412576eSMichael Tuexen SCTP_INP_WLOCK_ASSERT(inp); 2096*a412576eSMichael Tuexen } else { 2097*a412576eSMichael Tuexen SCTP_WQ_ADDR_LOCK_ASSERT(); 2098*a412576eSMichael Tuexen } 2099*a412576eSMichael Tuexen if (stcb != NULL) { 2100*a412576eSMichael Tuexen /* 2101*a412576eSMichael Tuexen * Don't restart timer on association that's about to be 2102*a412576eSMichael Tuexen * killed. 2103*a412576eSMichael Tuexen */ 2104*a412576eSMichael Tuexen if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) && 2105*a412576eSMichael Tuexen (t_type != SCTP_TIMER_TYPE_ASOCKILL)) { 2106*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2107*a412576eSMichael Tuexen "timer type %d not started: inp=%p, stcb=%p, net=%p (stcb deleted).\n", 2108*a412576eSMichael Tuexen t_type, inp, stcb, net); 2109*a412576eSMichael Tuexen return; 2110f8829a4aSRandall Stewart } 21119803f01cSMichael Tuexen /* Don't restart timer on net that's been removed. */ 21129803f01cSMichael Tuexen if (net != NULL && (net->dest_state & SCTP_ADDR_BEING_DELETED)) { 2113*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2114*a412576eSMichael Tuexen "timer type %d not started: inp=%p, stcb=%p, net=%p (net deleted).\n", 2115*a412576eSMichael Tuexen t_type, inp, stcb, net); 21169803f01cSMichael Tuexen return; 21179803f01cSMichael Tuexen } 2118*a412576eSMichael Tuexen } 2119f8829a4aSRandall Stewart switch (t_type) { 2120f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2121*a412576eSMichael Tuexen /* Here we use the RTO timer. */ 2122*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2123*a412576eSMichael Tuexen #ifdef INVARIANTS 2124*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2125*a412576eSMichael Tuexen t_type, inp, stcb, net); 2126*a412576eSMichael Tuexen #else 2127ad81507eSRandall Stewart return; 2128*a412576eSMichael Tuexen #endif 2129f8829a4aSRandall Stewart } 2130f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2131f8829a4aSRandall Stewart if (net->RTO == 0) { 2132*a412576eSMichael Tuexen to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2133f8829a4aSRandall Stewart } else { 2134*a412576eSMichael Tuexen to_ticks = MSEC_TO_TICKS(net->RTO); 2135f8829a4aSRandall Stewart } 2136f8829a4aSRandall Stewart break; 2137f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2138f8829a4aSRandall Stewart /* 2139f8829a4aSRandall Stewart * Here we use the INIT timer default usually about 1 2140*a412576eSMichael Tuexen * second. 2141f8829a4aSRandall Stewart */ 2142*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2143*a412576eSMichael Tuexen #ifdef INVARIANTS 2144*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2145*a412576eSMichael Tuexen t_type, inp, stcb, net); 2146*a412576eSMichael Tuexen #else 2147ad81507eSRandall Stewart return; 2148*a412576eSMichael Tuexen #endif 2149f8829a4aSRandall Stewart } 2150f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2151f8829a4aSRandall Stewart if (net->RTO == 0) { 2152f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2153f8829a4aSRandall Stewart } else { 2154f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2155f8829a4aSRandall Stewart } 2156f8829a4aSRandall Stewart break; 2157f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2158f8829a4aSRandall Stewart /* 2159*a412576eSMichael Tuexen * Here we use the Delayed-Ack timer value from the inp, 2160f8829a4aSRandall Stewart * ususually about 200ms. 2161f8829a4aSRandall Stewart */ 2162*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2163*a412576eSMichael Tuexen #ifdef INVARIANTS 2164*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2165*a412576eSMichael Tuexen t_type, inp, stcb, net); 2166*a412576eSMichael Tuexen #else 2167ad81507eSRandall Stewart return; 2168*a412576eSMichael Tuexen #endif 2169f8829a4aSRandall Stewart } 2170f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2171f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack); 2172f8829a4aSRandall Stewart break; 2173f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2174f8829a4aSRandall Stewart /* Here we use the RTO of the destination. */ 2175*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2176*a412576eSMichael Tuexen #ifdef INVARIANTS 2177*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2178*a412576eSMichael Tuexen t_type, inp, stcb, net); 2179*a412576eSMichael Tuexen #else 2180ad81507eSRandall Stewart return; 2181*a412576eSMichael Tuexen #endif 2182f8829a4aSRandall Stewart } 2183*a412576eSMichael Tuexen tmr = &net->rxt_timer; 2184f8829a4aSRandall Stewart if (net->RTO == 0) { 2185f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2186f8829a4aSRandall Stewart } else { 2187f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2188f8829a4aSRandall Stewart } 2189f8829a4aSRandall Stewart break; 2190f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2191f8829a4aSRandall Stewart /* 2192*a412576eSMichael Tuexen * The net is used here so that we can add in the RTO. Even 2193f8829a4aSRandall Stewart * though we use a different timer. We also add the HB timer 2194f8829a4aSRandall Stewart * PLUS a random jitter. 2195f8829a4aSRandall Stewart */ 2196*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2197*a412576eSMichael Tuexen #ifdef INVARIANTS 2198*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2199*a412576eSMichael Tuexen t_type, inp, stcb, net); 2200*a412576eSMichael Tuexen #else 2201ad81507eSRandall Stewart return; 2202*a412576eSMichael Tuexen #endif 2203*a412576eSMichael Tuexen } 2204ca85e948SMichael Tuexen if ((net->dest_state & SCTP_ADDR_NOHB) && 2205ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 2206*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2207*a412576eSMichael Tuexen "timer type %d not started: inp=%p, stcb=%p, net=%p.\n", 2208*a412576eSMichael Tuexen t_type, inp, stcb, net); 2209ad81507eSRandall Stewart return; 2210f8829a4aSRandall Stewart } 2211*a412576eSMichael Tuexen tmr = &net->hb_timer; 2212f8829a4aSRandall Stewart if (net->RTO == 0) { 2213ca85e948SMichael Tuexen to_ticks = stcb->asoc.initial_rto; 2214f8829a4aSRandall Stewart } else { 2215ca85e948SMichael Tuexen to_ticks = net->RTO; 2216f8829a4aSRandall Stewart } 2217ca85e948SMichael Tuexen rndval = sctp_select_initial_TSN(&inp->sctp_ep); 2218ca85e948SMichael Tuexen jitter = rndval % to_ticks; 2219ca85e948SMichael Tuexen if (jitter >= (to_ticks >> 1)) { 2220ca85e948SMichael Tuexen to_ticks = to_ticks + (jitter - (to_ticks >> 1)); 2221f8829a4aSRandall Stewart } else { 2222ca85e948SMichael Tuexen to_ticks = to_ticks - jitter; 2223f8829a4aSRandall Stewart } 2224ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 2225ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_PF)) { 2226ca85e948SMichael Tuexen to_ticks += net->heart_beat_delay; 2227f8829a4aSRandall Stewart } 2228f8829a4aSRandall Stewart /* 2229*a412576eSMichael Tuexen * Now we must convert the to_ticks that are now in ms to 2230*a412576eSMichael Tuexen * ticks. 2231f8829a4aSRandall Stewart */ 2232f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(to_ticks); 2233f8829a4aSRandall Stewart break; 2234f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2235f8829a4aSRandall Stewart /* 2236f8829a4aSRandall Stewart * Here we can use the RTO timer from the network since one 2237*a412576eSMichael Tuexen * RTT was complete. If a retransmission happened then we 2238*a412576eSMichael Tuexen * will be using the RTO initial value. 2239f8829a4aSRandall Stewart */ 2240*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2241*a412576eSMichael Tuexen #ifdef INVARIANTS 2242*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2243*a412576eSMichael Tuexen t_type, inp, stcb, net); 2244*a412576eSMichael Tuexen #else 2245ad81507eSRandall Stewart return; 2246*a412576eSMichael Tuexen #endif 2247f8829a4aSRandall Stewart } 2248*a412576eSMichael Tuexen tmr = &net->rxt_timer; 2249f8829a4aSRandall Stewart if (net->RTO == 0) { 2250f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2251f8829a4aSRandall Stewart } else { 2252f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2253f8829a4aSRandall Stewart } 2254f8829a4aSRandall Stewart break; 2255f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2256f8829a4aSRandall Stewart /* 2257*a412576eSMichael Tuexen * Nothing needed but the endpoint here ususually about 60 2258f8829a4aSRandall Stewart * minutes. 2259f8829a4aSRandall Stewart */ 2260*a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2261*a412576eSMichael Tuexen #ifdef INVARIANTS 2262*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2263*a412576eSMichael Tuexen t_type, inp, stcb, net); 2264*a412576eSMichael Tuexen #else 2265*a412576eSMichael Tuexen return; 2266*a412576eSMichael Tuexen #endif 2267*a412576eSMichael Tuexen } 2268f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2269f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE]; 2270f8829a4aSRandall Stewart break; 2271f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2272f8829a4aSRandall Stewart /* 2273*a412576eSMichael Tuexen * Here we use the value found in the EP for PMTUD, 2274*a412576eSMichael Tuexen * ususually about 10 minutes. 2275f8829a4aSRandall Stewart */ 2276*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2277*a412576eSMichael Tuexen #ifdef INVARIANTS 2278*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2279*a412576eSMichael Tuexen t_type, inp, stcb, net); 2280*a412576eSMichael Tuexen #else 2281ad81507eSRandall Stewart return; 2282*a412576eSMichael Tuexen #endif 2283f8829a4aSRandall Stewart } 228480c79bbeSMichael Tuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2285*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2286*a412576eSMichael Tuexen "timer type %d not started: inp=%p, stcb=%p, net=%p.\n", 2287*a412576eSMichael Tuexen t_type, inp, stcb, net); 228880c79bbeSMichael Tuexen return; 228980c79bbeSMichael Tuexen } 2290f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2291*a412576eSMichael Tuexen to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU]; 2292f8829a4aSRandall Stewart break; 2293f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2294*a412576eSMichael Tuexen /* Here we use the RTO of the destination. */ 2295*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2296*a412576eSMichael Tuexen #ifdef INVARIANTS 2297*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2298*a412576eSMichael Tuexen t_type, inp, stcb, net); 2299*a412576eSMichael Tuexen #else 2300ad81507eSRandall Stewart return; 2301*a412576eSMichael Tuexen #endif 2302f8829a4aSRandall Stewart } 2303*a412576eSMichael Tuexen tmr = &net->rxt_timer; 2304f8829a4aSRandall Stewart if (net->RTO == 0) { 2305f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2306f8829a4aSRandall Stewart } else { 2307f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2308f8829a4aSRandall Stewart } 2309f8829a4aSRandall Stewart break; 23100554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASCONF: 23110554e01dSMichael Tuexen /* 23120554e01dSMichael Tuexen * Here the timer comes from the stcb but its value is from 23130554e01dSMichael Tuexen * the net's RTO. 23140554e01dSMichael Tuexen */ 2315*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2316*a412576eSMichael Tuexen #ifdef INVARIANTS 2317*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2318*a412576eSMichael Tuexen t_type, inp, stcb, net); 2319*a412576eSMichael Tuexen #else 23200554e01dSMichael Tuexen return; 2321*a412576eSMichael Tuexen #endif 23220554e01dSMichael Tuexen } 2323*a412576eSMichael Tuexen tmr = &stcb->asoc.asconf_timer; 23240554e01dSMichael Tuexen if (net->RTO == 0) { 23250554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 23260554e01dSMichael Tuexen } else { 23270554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(net->RTO); 23280554e01dSMichael Tuexen } 23290554e01dSMichael Tuexen break; 2330f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2331f8829a4aSRandall Stewart /* 2332f8829a4aSRandall Stewart * Here we use the endpoints shutdown guard timer usually 2333f8829a4aSRandall Stewart * about 3 minutes. 2334f8829a4aSRandall Stewart */ 2335*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2336*a412576eSMichael Tuexen #ifdef INVARIANTS 2337*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2338*a412576eSMichael Tuexen t_type, inp, stcb, net); 2339*a412576eSMichael Tuexen #else 2340ad81507eSRandall Stewart return; 2341*a412576eSMichael Tuexen #endif 2342f8829a4aSRandall Stewart } 2343*a412576eSMichael Tuexen tmr = &stcb->asoc.shut_guard_timer; 23442e2d6794SMichael Tuexen if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) { 23452e2d6794SMichael Tuexen to_ticks = 5 * MSEC_TO_TICKS(stcb->asoc.maxrto); 23462e2d6794SMichael Tuexen } else { 2347f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN]; 23482e2d6794SMichael Tuexen } 2349f8829a4aSRandall Stewart break; 23500554e01dSMichael Tuexen case SCTP_TIMER_TYPE_AUTOCLOSE: 2351*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2352*a412576eSMichael Tuexen #ifdef INVARIANTS 2353*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2354*a412576eSMichael Tuexen t_type, inp, stcb, net); 2355*a412576eSMichael Tuexen #else 23560554e01dSMichael Tuexen return; 2357*a412576eSMichael Tuexen #endif 23580554e01dSMichael Tuexen } 23590554e01dSMichael Tuexen tmr = &stcb->asoc.autoclose_timer; 2360*a412576eSMichael Tuexen to_ticks = stcb->asoc.sctp_autoclose_ticks; 23610554e01dSMichael Tuexen break; 2362f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2363f8829a4aSRandall Stewart /* 23641b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 23651b649582SRandall Stewart * the net's RTO. 2366f8829a4aSRandall Stewart */ 2367*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2368*a412576eSMichael Tuexen #ifdef INVARIANTS 2369*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2370*a412576eSMichael Tuexen t_type, inp, stcb, net); 2371*a412576eSMichael Tuexen #else 2372ad81507eSRandall Stewart return; 2373*a412576eSMichael Tuexen #endif 2374f8829a4aSRandall Stewart } 2375*a412576eSMichael Tuexen tmr = &stcb->asoc.strreset_timer; 2376f8829a4aSRandall Stewart if (net->RTO == 0) { 2377f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2378f8829a4aSRandall Stewart } else { 2379f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2380f8829a4aSRandall Stewart } 2381f8829a4aSRandall Stewart break; 23820554e01dSMichael Tuexen case SCTP_TIMER_TYPE_INPKILL: 2383f8829a4aSRandall Stewart /* 23840554e01dSMichael Tuexen * The inp is setup to die. We re-use the signature_chage 23850554e01dSMichael Tuexen * timer since that has stopped and we are in the GONE 23860554e01dSMichael Tuexen * state. 2387f8829a4aSRandall Stewart */ 2388*a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2389*a412576eSMichael Tuexen #ifdef INVARIANTS 2390*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2391*a412576eSMichael Tuexen t_type, inp, stcb, net); 2392*a412576eSMichael Tuexen #else 2393*a412576eSMichael Tuexen return; 2394*a412576eSMichael Tuexen #endif 2395*a412576eSMichael Tuexen } 23960554e01dSMichael Tuexen tmr = &inp->sctp_ep.signature_change; 23970554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT); 23980554e01dSMichael Tuexen break; 23990554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASOCKILL: 2400*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2401*a412576eSMichael Tuexen #ifdef INVARIANTS 2402*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2403*a412576eSMichael Tuexen t_type, inp, stcb, net); 2404*a412576eSMichael Tuexen #else 2405ad81507eSRandall Stewart return; 2406*a412576eSMichael Tuexen #endif 2407f8829a4aSRandall Stewart } 24080554e01dSMichael Tuexen tmr = &stcb->asoc.strreset_timer; 24090554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT); 24100554e01dSMichael Tuexen break; 24110554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ADDR_WQ: 2412*a412576eSMichael Tuexen if ((inp != NULL) || (stcb != NULL) || (net != NULL)) { 2413*a412576eSMichael Tuexen #ifdef INVARIANTS 2414*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2415*a412576eSMichael Tuexen t_type, inp, stcb, net); 2416*a412576eSMichael Tuexen #else 2417*a412576eSMichael Tuexen return; 2418*a412576eSMichael Tuexen #endif 2419*a412576eSMichael Tuexen } 24200554e01dSMichael Tuexen /* Only 1 tick away :-) */ 24210554e01dSMichael Tuexen tmr = &SCTP_BASE_INFO(addr_wq_timer); 24220554e01dSMichael Tuexen to_ticks = SCTP_ADDRESS_TICK_DELAY; 2423f8829a4aSRandall Stewart break; 2424851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2425*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2426*a412576eSMichael Tuexen #ifdef INVARIANTS 2427*a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2428*a412576eSMichael Tuexen t_type, inp, stcb, net); 2429*a412576eSMichael Tuexen #else 2430851b7298SRandall Stewart return; 2431*a412576eSMichael Tuexen #endif 2432851b7298SRandall Stewart } 2433851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2434*a412576eSMichael Tuexen to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2435851b7298SRandall Stewart break; 2436f8829a4aSRandall Stewart default: 2437*a412576eSMichael Tuexen panic("Unknown timer type %d", t_type); 243860990c0cSMichael Tuexen } 2439*a412576eSMichael Tuexen KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type)); 2440*a412576eSMichael Tuexen KASSERT(to_ticks > 0, ("to_ticks == 0 for timer type %d", t_type)); 2441139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 2442f8829a4aSRandall Stewart /* 2443*a412576eSMichael Tuexen * We do NOT allow you to have it already running. If it is, 2444*a412576eSMichael Tuexen * we leave the current one up unchanged. 2445f8829a4aSRandall Stewart */ 2446*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2447*a412576eSMichael Tuexen "timer type %d already running: inp=%p, stcb=%p, net=%p.\n", 2448*a412576eSMichael Tuexen t_type, inp, stcb, net); 2449ad81507eSRandall Stewart return; 2450f8829a4aSRandall Stewart } 2451*a412576eSMichael Tuexen /* At this point we can proceed. */ 2452f8829a4aSRandall Stewart if (t_type == SCTP_TIMER_TYPE_SEND) { 2453f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up++; 2454f8829a4aSRandall Stewart } 2455a5d547adSRandall Stewart tmr->stopped_from = 0; 2456f8829a4aSRandall Stewart tmr->type = t_type; 2457f8829a4aSRandall Stewart tmr->ep = (void *)inp; 2458f8829a4aSRandall Stewart tmr->tcb = (void *)stcb; 2459*a412576eSMichael Tuexen if (t_type == SCTP_TIMER_TYPE_STRRESET) { 2460*a412576eSMichael Tuexen tmr->net = NULL; 2461*a412576eSMichael Tuexen } else { 2462f8829a4aSRandall Stewart tmr->net = (void *)net; 2463*a412576eSMichael Tuexen } 2464f8829a4aSRandall Stewart tmr->self = (void *)tmr; 24658518270eSMichael Tuexen tmr->vnet = (void *)curvnet; 2466c4739e2fSRandall Stewart tmr->ticks = sctp_get_tick_count(); 2467*a412576eSMichael Tuexen if (SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr) == 0) { 2468*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2469*a412576eSMichael Tuexen "timer type %d started: ticks=%u, inp=%p, stcb=%p, net=%p.\n", 2470*a412576eSMichael Tuexen t_type, to_ticks, inp, stcb, net); 2471*a412576eSMichael Tuexen } else { 2472*a412576eSMichael Tuexen /* 2473*a412576eSMichael Tuexen * This should not happen, since we checked for pending 2474*a412576eSMichael Tuexen * above. 2475*a412576eSMichael Tuexen */ 2476*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2477*a412576eSMichael Tuexen "timer type %d restarted: ticks=%u, inp=%p, stcb=%p, net=%p.\n", 2478*a412576eSMichael Tuexen t_type, to_ticks, inp, stcb, net); 2479*a412576eSMichael Tuexen } 2480ad81507eSRandall Stewart return; 2481f8829a4aSRandall Stewart } 2482f8829a4aSRandall Stewart 2483*a412576eSMichael Tuexen /*- 2484*a412576eSMichael Tuexen * The following table shows which parameters must be provided 2485*a412576eSMichael Tuexen * when calling sctp_timer_stop(). For parameters not being 2486*a412576eSMichael Tuexen * provided, NULL must be used. 2487*a412576eSMichael Tuexen * 2488*a412576eSMichael Tuexen * |Name |inp |stcb|net | 2489*a412576eSMichael Tuexen * |-----------------------------|----|----|----| 2490*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes | 2491*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes | 2492*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No | 2493*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes | 2494*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes | 2495*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes | 2496*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No | 2497*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes | 2498*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes | 2499*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |No | 2500*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No | 2501*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No | 2502*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |No | 2503*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No | 2504*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No | 2505*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No | 2506*a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No | 2507*a412576eSMichael Tuexen * 2508*a412576eSMichael Tuexen */ 2509*a412576eSMichael Tuexen 25106e55db54SRandall Stewart void 2511f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2512a5d547adSRandall Stewart struct sctp_nets *net, uint32_t from) 2513f8829a4aSRandall Stewart { 2514f8829a4aSRandall Stewart struct sctp_timer *tmr; 2515f8829a4aSRandall Stewart 2516*a412576eSMichael Tuexen if (stcb != NULL) { 2517f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2518*a412576eSMichael Tuexen } else if (inp != NULL) { 2519*a412576eSMichael Tuexen SCTP_INP_WLOCK_ASSERT(inp); 2520*a412576eSMichael Tuexen } else { 2521*a412576eSMichael Tuexen SCTP_WQ_ADDR_LOCK_ASSERT(); 2522f8829a4aSRandall Stewart } 2523*a412576eSMichael Tuexen tmr = NULL; 2524f8829a4aSRandall Stewart switch (t_type) { 2525f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2526*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2527*a412576eSMichael Tuexen #ifdef INVARIANTS 2528*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2529*a412576eSMichael Tuexen t_type, inp, stcb, net); 2530*a412576eSMichael Tuexen #else 25316e55db54SRandall Stewart return; 2532*a412576eSMichael Tuexen #endif 2533f8829a4aSRandall Stewart } 2534f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2535f8829a4aSRandall Stewart break; 2536f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2537*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2538*a412576eSMichael Tuexen #ifdef INVARIANTS 2539*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2540*a412576eSMichael Tuexen t_type, inp, stcb, net); 2541*a412576eSMichael Tuexen #else 25426e55db54SRandall Stewart return; 2543*a412576eSMichael Tuexen #endif 2544f8829a4aSRandall Stewart } 2545f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2546f8829a4aSRandall Stewart break; 2547f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2548*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2549*a412576eSMichael Tuexen #ifdef INVARIANTS 2550*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2551*a412576eSMichael Tuexen t_type, inp, stcb, net); 2552*a412576eSMichael Tuexen #else 25536e55db54SRandall Stewart return; 2554*a412576eSMichael Tuexen #endif 2555f8829a4aSRandall Stewart } 2556f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2557f8829a4aSRandall Stewart break; 2558f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2559*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2560*a412576eSMichael Tuexen #ifdef INVARIANTS 2561*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2562*a412576eSMichael Tuexen t_type, inp, stcb, net); 2563*a412576eSMichael Tuexen #else 25646e55db54SRandall Stewart return; 2565*a412576eSMichael Tuexen #endif 2566f8829a4aSRandall Stewart } 2567f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2568f8829a4aSRandall Stewart break; 2569f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2570*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2571*a412576eSMichael Tuexen #ifdef INVARIANTS 2572*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2573*a412576eSMichael Tuexen t_type, inp, stcb, net); 2574*a412576eSMichael Tuexen #else 25756e55db54SRandall Stewart return; 2576*a412576eSMichael Tuexen #endif 2577f8829a4aSRandall Stewart } 2578ca85e948SMichael Tuexen tmr = &net->hb_timer; 2579f8829a4aSRandall Stewart break; 2580f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2581*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2582*a412576eSMichael Tuexen #ifdef INVARIANTS 2583*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2584*a412576eSMichael Tuexen t_type, inp, stcb, net); 2585*a412576eSMichael Tuexen #else 25866e55db54SRandall Stewart return; 2587*a412576eSMichael Tuexen #endif 2588f8829a4aSRandall Stewart } 2589f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2590f8829a4aSRandall Stewart break; 2591f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2592*a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2593*a412576eSMichael Tuexen #ifdef INVARIANTS 2594*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2595*a412576eSMichael Tuexen t_type, inp, stcb, net); 2596*a412576eSMichael Tuexen #else 2597*a412576eSMichael Tuexen return; 2598*a412576eSMichael Tuexen #endif 2599*a412576eSMichael Tuexen } 2600f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2601f8829a4aSRandall Stewart break; 2602f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2603*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2604*a412576eSMichael Tuexen #ifdef INVARIANTS 2605*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2606*a412576eSMichael Tuexen t_type, inp, stcb, net); 2607*a412576eSMichael Tuexen #else 26086e55db54SRandall Stewart return; 2609*a412576eSMichael Tuexen #endif 2610f8829a4aSRandall Stewart } 2611f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2612f8829a4aSRandall Stewart break; 2613f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2614*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2615*a412576eSMichael Tuexen #ifdef INVARIANTS 2616*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2617*a412576eSMichael Tuexen t_type, inp, stcb, net); 2618*a412576eSMichael Tuexen #else 26196e55db54SRandall Stewart return; 2620*a412576eSMichael Tuexen #endif 2621f8829a4aSRandall Stewart } 2622f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2623f8829a4aSRandall Stewart break; 26240554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASCONF: 2625*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2626*a412576eSMichael Tuexen #ifdef INVARIANTS 2627*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2628*a412576eSMichael Tuexen t_type, inp, stcb, net); 2629*a412576eSMichael Tuexen #else 26300554e01dSMichael Tuexen return; 2631*a412576eSMichael Tuexen #endif 26320554e01dSMichael Tuexen } 26330554e01dSMichael Tuexen tmr = &stcb->asoc.asconf_timer; 26340554e01dSMichael Tuexen break; 2635f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2636*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2637*a412576eSMichael Tuexen #ifdef INVARIANTS 2638*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2639*a412576eSMichael Tuexen t_type, inp, stcb, net); 2640*a412576eSMichael Tuexen #else 26416e55db54SRandall Stewart return; 2642*a412576eSMichael Tuexen #endif 2643f8829a4aSRandall Stewart } 2644f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2645f8829a4aSRandall Stewart break; 26460554e01dSMichael Tuexen case SCTP_TIMER_TYPE_AUTOCLOSE: 2647*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2648*a412576eSMichael Tuexen #ifdef INVARIANTS 2649*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2650*a412576eSMichael Tuexen t_type, inp, stcb, net); 2651*a412576eSMichael Tuexen #else 26520554e01dSMichael Tuexen return; 2653*a412576eSMichael Tuexen #endif 26540554e01dSMichael Tuexen } 26550554e01dSMichael Tuexen tmr = &stcb->asoc.autoclose_timer; 26560554e01dSMichael Tuexen break; 2657f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2658*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2659*a412576eSMichael Tuexen #ifdef INVARIANTS 2660*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2661*a412576eSMichael Tuexen t_type, inp, stcb, net); 2662*a412576eSMichael Tuexen #else 26636e55db54SRandall Stewart return; 2664*a412576eSMichael Tuexen #endif 2665f8829a4aSRandall Stewart } 2666f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2667f8829a4aSRandall Stewart break; 26680554e01dSMichael Tuexen case SCTP_TIMER_TYPE_INPKILL: 26690554e01dSMichael Tuexen /* 26700554e01dSMichael Tuexen * The inp is setup to die. We re-use the signature_chage 26710554e01dSMichael Tuexen * timer since that has stopped and we are in the GONE 26720554e01dSMichael Tuexen * state. 26730554e01dSMichael Tuexen */ 2674*a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2675*a412576eSMichael Tuexen #ifdef INVARIANTS 2676*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2677*a412576eSMichael Tuexen t_type, inp, stcb, net); 2678*a412576eSMichael Tuexen #else 2679*a412576eSMichael Tuexen return; 2680*a412576eSMichael Tuexen #endif 2681*a412576eSMichael Tuexen } 26820554e01dSMichael Tuexen tmr = &inp->sctp_ep.signature_change; 26830554e01dSMichael Tuexen break; 26840554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASOCKILL: 2685*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2686*a412576eSMichael Tuexen #ifdef INVARIANTS 2687*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2688*a412576eSMichael Tuexen t_type, inp, stcb, net); 2689*a412576eSMichael Tuexen #else 26906e55db54SRandall Stewart return; 2691*a412576eSMichael Tuexen #endif 2692f8829a4aSRandall Stewart } 26930554e01dSMichael Tuexen tmr = &stcb->asoc.strreset_timer; 26940554e01dSMichael Tuexen break; 26950554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ADDR_WQ: 2696*a412576eSMichael Tuexen if ((inp != NULL) || (stcb != NULL) || (net != NULL)) { 2697*a412576eSMichael Tuexen #ifdef INVARIANTS 2698*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2699*a412576eSMichael Tuexen t_type, inp, stcb, net); 2700*a412576eSMichael Tuexen #else 2701*a412576eSMichael Tuexen return; 2702*a412576eSMichael Tuexen #endif 2703*a412576eSMichael Tuexen } 27040554e01dSMichael Tuexen tmr = &SCTP_BASE_INFO(addr_wq_timer); 2705f8829a4aSRandall Stewart break; 2706851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2707*a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2708*a412576eSMichael Tuexen #ifdef INVARIANTS 2709*a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2710*a412576eSMichael Tuexen t_type, inp, stcb, net); 2711*a412576eSMichael Tuexen #else 2712851b7298SRandall Stewart return; 2713*a412576eSMichael Tuexen #endif 2714851b7298SRandall Stewart } 2715851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2716851b7298SRandall Stewart break; 2717f8829a4aSRandall Stewart default: 2718*a412576eSMichael Tuexen panic("Unknown timer type %d", t_type); 271960990c0cSMichael Tuexen } 2720*a412576eSMichael Tuexen KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type)); 2721*a412576eSMichael Tuexen if ((tmr->type != SCTP_TIMER_TYPE_NONE) && 2722*a412576eSMichael Tuexen (tmr->type != t_type)) { 2723f8829a4aSRandall Stewart /* 2724f8829a4aSRandall Stewart * Ok we have a timer that is under joint use. Cookie timer 2725f8829a4aSRandall Stewart * per chance with the SEND timer. We therefore are NOT 2726f8829a4aSRandall Stewart * running the timer that the caller wants stopped. So just 2727f8829a4aSRandall Stewart * return. 2728f8829a4aSRandall Stewart */ 2729*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2730*a412576eSMichael Tuexen "shared timer type %d not running: inp=%p, stcb=%p, net=%p.\n", 2731*a412576eSMichael Tuexen t_type, inp, stcb, net); 27326e55db54SRandall Stewart return; 2733f8829a4aSRandall Stewart } 2734ad81507eSRandall Stewart if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) { 2735f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 2736f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 2737f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 2738f8829a4aSRandall Stewart } 2739f8829a4aSRandall Stewart } 2740f8829a4aSRandall Stewart tmr->self = NULL; 2741a5d547adSRandall Stewart tmr->stopped_from = from; 2742*a412576eSMichael Tuexen if (SCTP_OS_TIMER_STOP(&tmr->timer) == 1) { 2743*a412576eSMichael Tuexen KASSERT(tmr->ep == inp, 2744*a412576eSMichael Tuexen ("sctp_timer_stop of type %d: inp = %p, tmr->inp = %p", 2745*a412576eSMichael Tuexen t_type, inp, tmr->ep)); 2746*a412576eSMichael Tuexen KASSERT(tmr->tcb == stcb, 2747*a412576eSMichael Tuexen ("sctp_timer_stop of type %d: stcb = %p, tmr->stcb = %p", 2748*a412576eSMichael Tuexen t_type, stcb, tmr->tcb)); 2749*a412576eSMichael Tuexen KASSERT(((t_type == SCTP_TIMER_TYPE_ASCONF) && (tmr->net != NULL)) || 2750*a412576eSMichael Tuexen ((t_type != SCTP_TIMER_TYPE_ASCONF) && (tmr->net == net)), 2751*a412576eSMichael Tuexen ("sctp_timer_stop of type %d: net = %p, tmr->net = %p", 2752*a412576eSMichael Tuexen t_type, net, tmr->net)); 2753*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2754*a412576eSMichael Tuexen "timer type %d stopped: inp=%p, stcb=%p, net=%p.\n", 2755*a412576eSMichael Tuexen t_type, inp, stcb, net); 2756*a412576eSMichael Tuexen tmr->ep = NULL; 2757*a412576eSMichael Tuexen tmr->tcb = NULL; 2758*a412576eSMichael Tuexen tmr->net = NULL; 2759*a412576eSMichael Tuexen } else { 2760*a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2761*a412576eSMichael Tuexen "timer type %d not stopped: inp=%p, stcb=%p, net=%p.\n", 2762*a412576eSMichael Tuexen t_type, inp, stcb, net); 2763*a412576eSMichael Tuexen } 27646e55db54SRandall Stewart return; 2765f8829a4aSRandall Stewart } 2766f8829a4aSRandall Stewart 2767f8829a4aSRandall Stewart uint32_t 2768b0471b4bSMichael Tuexen sctp_calculate_len(struct mbuf *m) 2769b0471b4bSMichael Tuexen { 2770f8829a4aSRandall Stewart uint32_t tlen = 0; 2771f8829a4aSRandall Stewart struct mbuf *at; 2772f8829a4aSRandall Stewart 2773f8829a4aSRandall Stewart at = m; 2774f8829a4aSRandall Stewart while (at) { 2775139bc87fSRandall Stewart tlen += SCTP_BUF_LEN(at); 2776139bc87fSRandall Stewart at = SCTP_BUF_NEXT(at); 2777f8829a4aSRandall Stewart } 2778f8829a4aSRandall Stewart return (tlen); 2779f8829a4aSRandall Stewart } 2780f8829a4aSRandall Stewart 2781f8829a4aSRandall Stewart void 2782f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp, 278344b7479bSRandall Stewart struct sctp_association *asoc, uint32_t mtu) 2784f8829a4aSRandall Stewart { 2785f8829a4aSRandall Stewart /* 2786f8829a4aSRandall Stewart * Reset the P-MTU size on this association, this involves changing 2787f8829a4aSRandall Stewart * the asoc MTU, going through ANY chunk+overhead larger than mtu to 2788f8829a4aSRandall Stewart * allow the DF flag to be cleared. 2789f8829a4aSRandall Stewart */ 2790f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 2791f8829a4aSRandall Stewart unsigned int eff_mtu, ovh; 2792f8829a4aSRandall Stewart 2793f8829a4aSRandall Stewart asoc->smallest_mtu = mtu; 2794f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2795f8829a4aSRandall Stewart ovh = SCTP_MIN_OVERHEAD; 2796f8829a4aSRandall Stewart } else { 2797f8829a4aSRandall Stewart ovh = SCTP_MIN_V4_OVERHEAD; 2798f8829a4aSRandall Stewart } 2799f8829a4aSRandall Stewart eff_mtu = mtu - ovh; 2800f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 2801f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2802f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2803f8829a4aSRandall Stewart } 2804f8829a4aSRandall Stewart } 2805f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 2806f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2807f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2808f8829a4aSRandall Stewart } 2809f8829a4aSRandall Stewart } 2810f8829a4aSRandall Stewart } 2811f8829a4aSRandall Stewart 2812f8829a4aSRandall Stewart 2813f8829a4aSRandall Stewart /* 281444f2a327SMichael Tuexen * Given an association and starting time of the current RTT period, update 281544f2a327SMichael Tuexen * RTO in number of msecs. net should point to the current network. 281644f2a327SMichael Tuexen * Return 1, if an RTO update was performed, return 0 if no update was 281744f2a327SMichael Tuexen * performed due to invalid starting point. 2818f8829a4aSRandall Stewart */ 2819899288aeSRandall Stewart 282044f2a327SMichael Tuexen int 2821f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb, 2822f8829a4aSRandall Stewart struct sctp_association *asoc, 2823f8829a4aSRandall Stewart struct sctp_nets *net, 28248c8e10b7SMichael Tuexen struct timeval *old, 2825b0471b4bSMichael Tuexen int rtt_from_sack) 2826b0471b4bSMichael Tuexen { 282744f2a327SMichael Tuexen struct timeval now; 282844f2a327SMichael Tuexen uint64_t rtt_us; /* RTT in us */ 2829be1d9176SMichael Tuexen int32_t rtt; /* RTT in ms */ 2830be1d9176SMichael Tuexen uint32_t new_rto; 2831f8829a4aSRandall Stewart int first_measure = 0; 2832f8829a4aSRandall Stewart 2833f8829a4aSRandall Stewart /************************/ 2834f8829a4aSRandall Stewart /* 1. calculate new RTT */ 2835f8829a4aSRandall Stewart /************************/ 2836f8829a4aSRandall Stewart /* get the current time */ 2837299108c5SRandall Stewart if (stcb->asoc.use_precise_time) { 2838299108c5SRandall Stewart (void)SCTP_GETPTIME_TIMEVAL(&now); 2839299108c5SRandall Stewart } else { 28406e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 2841299108c5SRandall Stewart } 284244f2a327SMichael Tuexen if ((old->tv_sec > now.tv_sec) || 284344f2a327SMichael Tuexen ((old->tv_sec == now.tv_sec) && (old->tv_sec > now.tv_sec))) { 284444f2a327SMichael Tuexen /* The starting point is in the future. */ 284544f2a327SMichael Tuexen return (0); 284644f2a327SMichael Tuexen } 2847be1d9176SMichael Tuexen timevalsub(&now, old); 284844f2a327SMichael Tuexen rtt_us = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec; 284944f2a327SMichael Tuexen if (rtt_us > SCTP_RTO_UPPER_BOUND * 1000) { 285044f2a327SMichael Tuexen /* The RTT is larger than a sane value. */ 285144f2a327SMichael Tuexen return (0); 285244f2a327SMichael Tuexen } 2853be1d9176SMichael Tuexen /* store the current RTT in us */ 285444f2a327SMichael Tuexen net->rtt = rtt_us; 2855b60b0fe6SMichael Tuexen /* compute rtt in ms */ 2856b60b0fe6SMichael Tuexen rtt = (int32_t)(net->rtt / 1000); 2857f79aab18SRandall Stewart if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) { 2858b7b84c0eSMichael Tuexen /* 2859b7b84c0eSMichael Tuexen * Tell the CC module that a new update has just occurred 2860b7b84c0eSMichael Tuexen * from a sack 2861b7b84c0eSMichael Tuexen */ 2862f79aab18SRandall Stewart (*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now); 2863f79aab18SRandall Stewart } 2864f79aab18SRandall Stewart /* 2865f79aab18SRandall Stewart * Do we need to determine the lan? We do this only on sacks i.e. 2866f79aab18SRandall Stewart * RTT being determined from data not non-data (HB/INIT->INITACK). 2867f79aab18SRandall Stewart */ 2868f79aab18SRandall Stewart if ((rtt_from_sack == SCTP_RTT_FROM_DATA) && 2869be1d9176SMichael Tuexen (net->lan_type == SCTP_LAN_UNKNOWN)) { 2870be1d9176SMichael Tuexen if (net->rtt > SCTP_LOCAL_LAN_RTT) { 2871899288aeSRandall Stewart net->lan_type = SCTP_LAN_INTERNET; 2872899288aeSRandall Stewart } else { 2873899288aeSRandall Stewart net->lan_type = SCTP_LAN_LOCAL; 2874899288aeSRandall Stewart } 2875899288aeSRandall Stewart } 28760053ed28SMichael Tuexen 2877f8829a4aSRandall Stewart /***************************/ 2878f8829a4aSRandall Stewart /* 2. update RTTVAR & SRTT */ 2879f8829a4aSRandall Stewart /***************************/ 2880be1d9176SMichael Tuexen /*- 2881be1d9176SMichael Tuexen * Compute the scaled average lastsa and the 2882be1d9176SMichael Tuexen * scaled variance lastsv as described in van Jacobson 2883be1d9176SMichael Tuexen * Paper "Congestion Avoidance and Control", Annex A. 2884be1d9176SMichael Tuexen * 2885be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt 288644f2a327SMichael Tuexen * (net->lastsv >> SCTP_RTT_VAR_SHIFT) is the rttvar 2887be1d9176SMichael Tuexen */ 28889a972525SRandall Stewart if (net->RTO_measured) { 2889be1d9176SMichael Tuexen rtt -= (net->lastsa >> SCTP_RTT_SHIFT); 2890be1d9176SMichael Tuexen net->lastsa += rtt; 2891be1d9176SMichael Tuexen if (rtt < 0) { 2892be1d9176SMichael Tuexen rtt = -rtt; 2893be1d9176SMichael Tuexen } 2894be1d9176SMichael Tuexen rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); 2895be1d9176SMichael Tuexen net->lastsv += rtt; 2896b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2897f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_RTTVAR); 289880fefe0aSRandall Stewart } 2899f8829a4aSRandall Stewart } else { 2900f8829a4aSRandall Stewart /* First RTO measurment */ 29019a972525SRandall Stewart net->RTO_measured = 1; 2902f8829a4aSRandall Stewart first_measure = 1; 2903be1d9176SMichael Tuexen net->lastsa = rtt << SCTP_RTT_SHIFT; 2904be1d9176SMichael Tuexen net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT; 2905b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2906f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_INITIAL_RTT); 290780fefe0aSRandall Stewart } 2908f8829a4aSRandall Stewart } 2909be1d9176SMichael Tuexen if (net->lastsv == 0) { 2910be1d9176SMichael Tuexen net->lastsv = SCTP_CLOCK_GRANULARITY; 2911be1d9176SMichael Tuexen } 2912108df27cSRandall Stewart new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 2913f8829a4aSRandall Stewart if ((new_rto > SCTP_SAT_NETWORK_MIN) && 2914f8829a4aSRandall Stewart (stcb->asoc.sat_network_lockout == 0)) { 2915f8829a4aSRandall Stewart stcb->asoc.sat_network = 1; 2916f8829a4aSRandall Stewart } else if ((!first_measure) && stcb->asoc.sat_network) { 2917f8829a4aSRandall Stewart stcb->asoc.sat_network = 0; 2918f8829a4aSRandall Stewart stcb->asoc.sat_network_lockout = 1; 2919f8829a4aSRandall Stewart } 2920f8829a4aSRandall Stewart /* bound it, per C6/C7 in Section 5.3.1 */ 2921f8829a4aSRandall Stewart if (new_rto < stcb->asoc.minrto) { 2922f8829a4aSRandall Stewart new_rto = stcb->asoc.minrto; 2923f8829a4aSRandall Stewart } 2924f8829a4aSRandall Stewart if (new_rto > stcb->asoc.maxrto) { 2925f8829a4aSRandall Stewart new_rto = stcb->asoc.maxrto; 2926f8829a4aSRandall Stewart } 292744f2a327SMichael Tuexen net->RTO = new_rto; 292844f2a327SMichael Tuexen return (1); 2929f8829a4aSRandall Stewart } 2930f8829a4aSRandall Stewart 2931f8829a4aSRandall Stewart /* 2932f8829a4aSRandall Stewart * return a pointer to a contiguous piece of data from the given mbuf chain 2933f8829a4aSRandall Stewart * starting at 'off' for 'len' bytes. If the desired piece spans more than 2934f8829a4aSRandall Stewart * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size 2935f8829a4aSRandall Stewart * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain. 2936f8829a4aSRandall Stewart */ 293772fb6fdbSRandall Stewart caddr_t 2938f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t *in_ptr) 2939f8829a4aSRandall Stewart { 2940f8829a4aSRandall Stewart uint32_t count; 2941f8829a4aSRandall Stewart uint8_t *ptr; 2942f8829a4aSRandall Stewart 2943f8829a4aSRandall Stewart ptr = in_ptr; 2944f8829a4aSRandall Stewart if ((off < 0) || (len <= 0)) 2945f8829a4aSRandall Stewart return (NULL); 2946f8829a4aSRandall Stewart 2947f8829a4aSRandall Stewart /* find the desired start location */ 2948f8829a4aSRandall Stewart while ((m != NULL) && (off > 0)) { 2949139bc87fSRandall Stewart if (off < SCTP_BUF_LEN(m)) 2950f8829a4aSRandall Stewart break; 2951139bc87fSRandall Stewart off -= SCTP_BUF_LEN(m); 2952139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2953f8829a4aSRandall Stewart } 2954f8829a4aSRandall Stewart if (m == NULL) 2955f8829a4aSRandall Stewart return (NULL); 2956f8829a4aSRandall Stewart 2957f8829a4aSRandall Stewart /* is the current mbuf large enough (eg. contiguous)? */ 2958139bc87fSRandall Stewart if ((SCTP_BUF_LEN(m) - off) >= len) { 2959f8829a4aSRandall Stewart return (mtod(m, caddr_t)+off); 2960f8829a4aSRandall Stewart } else { 2961f8829a4aSRandall Stewart /* else, it spans more than one mbuf, so save a temp copy... */ 2962f8829a4aSRandall Stewart while ((m != NULL) && (len > 0)) { 2963139bc87fSRandall Stewart count = min(SCTP_BUF_LEN(m) - off, len); 29645ba7f91fSMichael Tuexen memcpy(ptr, mtod(m, caddr_t)+off, count); 2965f8829a4aSRandall Stewart len -= count; 2966f8829a4aSRandall Stewart ptr += count; 2967f8829a4aSRandall Stewart off = 0; 2968139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2969f8829a4aSRandall Stewart } 2970f8829a4aSRandall Stewart if ((m == NULL) && (len > 0)) 2971f8829a4aSRandall Stewart return (NULL); 2972f8829a4aSRandall Stewart else 2973f8829a4aSRandall Stewart return ((caddr_t)in_ptr); 2974f8829a4aSRandall Stewart } 2975f8829a4aSRandall Stewart } 2976f8829a4aSRandall Stewart 2977f8829a4aSRandall Stewart 297844b7479bSRandall Stewart 2979f8829a4aSRandall Stewart struct sctp_paramhdr * 2980f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m, 2981f8829a4aSRandall Stewart int offset, 2982f8829a4aSRandall Stewart struct sctp_paramhdr *pull, 2983f8829a4aSRandall Stewart int pull_limit) 2984f8829a4aSRandall Stewart { 2985f8829a4aSRandall Stewart /* This just provides a typed signature to Peter's Pull routine */ 2986f8829a4aSRandall Stewart return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit, 2987f8829a4aSRandall Stewart (uint8_t *)pull)); 2988f8829a4aSRandall Stewart } 2989f8829a4aSRandall Stewart 2990f8829a4aSRandall Stewart 2991ce11b842SMichael Tuexen struct mbuf * 2992f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen) 2993f8829a4aSRandall Stewart { 2994ce11b842SMichael Tuexen struct mbuf *m_last; 2995ce11b842SMichael Tuexen caddr_t dp; 2996f8829a4aSRandall Stewart 2997f8829a4aSRandall Stewart if (padlen > 3) { 2998ce11b842SMichael Tuexen return (NULL); 2999f8829a4aSRandall Stewart } 300041eee555SRandall Stewart if (padlen <= M_TRAILINGSPACE(m)) { 3001f8829a4aSRandall Stewart /* 3002f8829a4aSRandall Stewart * The easy way. We hope the majority of the time we hit 3003f8829a4aSRandall Stewart * here :) 3004f8829a4aSRandall Stewart */ 3005ce11b842SMichael Tuexen m_last = m; 3006f8829a4aSRandall Stewart } else { 3007ce11b842SMichael Tuexen /* Hard way we must grow the mbuf chain */ 3008ce11b842SMichael Tuexen m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA); 3009ce11b842SMichael Tuexen if (m_last == NULL) { 3010ce11b842SMichael Tuexen return (NULL); 3011f8829a4aSRandall Stewart } 3012ce11b842SMichael Tuexen SCTP_BUF_LEN(m_last) = 0; 3013ce11b842SMichael Tuexen SCTP_BUF_NEXT(m_last) = NULL; 3014ce11b842SMichael Tuexen SCTP_BUF_NEXT(m) = m_last; 3015f8829a4aSRandall Stewart } 3016ce11b842SMichael Tuexen dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last); 3017ce11b842SMichael Tuexen SCTP_BUF_LEN(m_last) += padlen; 3018ce11b842SMichael Tuexen memset(dp, 0, padlen); 3019ce11b842SMichael Tuexen return (m_last); 3020f8829a4aSRandall Stewart } 3021f8829a4aSRandall Stewart 3022ce11b842SMichael Tuexen struct mbuf * 3023f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) 3024f8829a4aSRandall Stewart { 3025f8829a4aSRandall Stewart /* find the last mbuf in chain and pad it */ 3026f8829a4aSRandall Stewart struct mbuf *m_at; 3027f8829a4aSRandall Stewart 3028ce11b842SMichael Tuexen if (last_mbuf != NULL) { 3029f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(last_mbuf, padval)); 3030f8829a4aSRandall Stewart } else { 303117267b32SMichael Tuexen for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) { 3032139bc87fSRandall Stewart if (SCTP_BUF_NEXT(m_at) == NULL) { 3033f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(m_at, padval)); 3034f8829a4aSRandall Stewart } 3035f8829a4aSRandall Stewart } 3036f8829a4aSRandall Stewart } 3037ce11b842SMichael Tuexen return (NULL); 3038f8829a4aSRandall Stewart } 3039f8829a4aSRandall Stewart 3040f8829a4aSRandall Stewart static void 3041c5b5675dSMichael Tuexen sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, 3042410a3b1eSMichael Tuexen uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked 3043ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3044ceaad40aSRandall Stewart SCTP_UNUSED 3045ceaad40aSRandall Stewart #endif 3046ceaad40aSRandall Stewart ) 3047f8829a4aSRandall Stewart { 3048f8829a4aSRandall Stewart struct mbuf *m_notify; 3049f8829a4aSRandall Stewart struct sctp_assoc_change *sac; 3050f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 30519a8e3088SMichael Tuexen unsigned int notif_len; 30529a8e3088SMichael Tuexen uint16_t abort_len; 3053e06b67c7SMichael Tuexen unsigned int i; 3054ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3055ceaad40aSRandall Stewart struct socket *so; 3056ceaad40aSRandall Stewart #endif 3057ceaad40aSRandall Stewart 305859713bbfSMichael Tuexen if (stcb == NULL) { 305959713bbfSMichael Tuexen return; 306059713bbfSMichael Tuexen } 306158411b08SMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { 30629a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_assoc_change); 3063a2b42326SMichael Tuexen if (abort != NULL) { 3064c9eb4473SMichael Tuexen abort_len = ntohs(abort->ch.chunk_length); 30659669e724SMichael Tuexen /* 30669669e724SMichael Tuexen * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be 306745d41de5SMichael Tuexen * contiguous. 30689669e724SMichael Tuexen */ 30699669e724SMichael Tuexen if (abort_len > SCTP_CHUNK_BUFFER_SIZE) { 30709669e724SMichael Tuexen abort_len = SCTP_CHUNK_BUFFER_SIZE; 30719669e724SMichael Tuexen } 3072a2b42326SMichael Tuexen } else { 3073a2b42326SMichael Tuexen abort_len = 0; 3074c5b5675dSMichael Tuexen } 3075a2b42326SMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 3076a2b42326SMichael Tuexen notif_len += SCTP_ASSOC_SUPPORTS_MAX; 3077a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 3078a2b42326SMichael Tuexen notif_len += abort_len; 3079a2b42326SMichael Tuexen } 3080eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3081a2b42326SMichael Tuexen if (m_notify == NULL) { 3082a2b42326SMichael Tuexen /* Retry with smaller value. */ 30839a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_assoc_change); 3084eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3085a2b42326SMichael Tuexen if (m_notify == NULL) { 308658411b08SMichael Tuexen goto set_error; 3087a2b42326SMichael Tuexen } 3088a2b42326SMichael Tuexen } 3089a2b42326SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 3090f8829a4aSRandall Stewart sac = mtod(m_notify, struct sctp_assoc_change *); 3091e432298aSXin LI memset(sac, 0, notif_len); 3092f8829a4aSRandall Stewart sac->sac_type = SCTP_ASSOC_CHANGE; 3093f8829a4aSRandall Stewart sac->sac_flags = 0; 3094f8829a4aSRandall Stewart sac->sac_length = sizeof(struct sctp_assoc_change); 3095c5b5675dSMichael Tuexen sac->sac_state = state; 3096f8829a4aSRandall Stewart sac->sac_error = error; 3097f8829a4aSRandall Stewart /* XXX verify these stream counts */ 3098f8829a4aSRandall Stewart sac->sac_outbound_streams = stcb->asoc.streamoutcnt; 3099f8829a4aSRandall Stewart sac->sac_inbound_streams = stcb->asoc.streamincnt; 3100f8829a4aSRandall Stewart sac->sac_assoc_id = sctp_get_associd(stcb); 3101a2b42326SMichael Tuexen if (notif_len > sizeof(struct sctp_assoc_change)) { 3102c5b5675dSMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 3103e06b67c7SMichael Tuexen i = 0; 3104c79bec9cSMichael Tuexen if (stcb->asoc.prsctp_supported == 1) { 3105e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR; 3106e06b67c7SMichael Tuexen } 3107c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 1) { 3108e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH; 3109e06b67c7SMichael Tuexen } 3110c79bec9cSMichael Tuexen if (stcb->asoc.asconf_supported == 1) { 3111e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; 3112e06b67c7SMichael Tuexen } 311344249214SRandall Stewart if (stcb->asoc.idata_supported == 1) { 311444249214SRandall Stewart sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING; 311544249214SRandall Stewart } 3116e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; 3117c79bec9cSMichael Tuexen if (stcb->asoc.reconfig_supported == 1) { 3118e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; 3119e06b67c7SMichael Tuexen } 3120e06b67c7SMichael Tuexen sac->sac_length += i; 3121a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 3122a2b42326SMichael Tuexen memcpy(sac->sac_info, abort, abort_len); 3123a2b42326SMichael Tuexen sac->sac_length += abort_len; 3124a2b42326SMichael Tuexen } 3125c5b5675dSMichael Tuexen } 3126e06b67c7SMichael Tuexen SCTP_BUF_LEN(m_notify) = sac->sac_length; 3127f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 31287215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3129f8829a4aSRandall Stewart m_notify); 313058411b08SMichael Tuexen if (control != NULL) { 3131139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 313228cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3133f8829a4aSRandall Stewart /* not that we need this */ 3134f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3135f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3136f8829a4aSRandall Stewart control, 3137cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, 3138cfde3ff7SRandall Stewart so_locked); 313958411b08SMichael Tuexen } else { 314058411b08SMichael Tuexen sctp_m_freem(m_notify); 314158411b08SMichael Tuexen } 314258411b08SMichael Tuexen } 314358411b08SMichael Tuexen /* 314458411b08SMichael Tuexen * For 1-to-1 style sockets, we send up and error when an ABORT 314558411b08SMichael Tuexen * comes in. 314658411b08SMichael Tuexen */ 314758411b08SMichael Tuexen set_error: 314858411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 314958411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 315058411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 3151e045904fSMichael Tuexen SOCK_LOCK(stcb->sctp_socket); 3152410a3b1eSMichael Tuexen if (from_peer) { 3153839d21d6SMichael Tuexen if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { 315458411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); 315558411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNREFUSED; 315658411b08SMichael Tuexen } else { 315758411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 315858411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNRESET; 315958411b08SMichael Tuexen } 3160410a3b1eSMichael Tuexen } else { 3161839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 3162839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 3163553bb068SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT); 3164553bb068SMichael Tuexen stcb->sctp_socket->so_error = ETIMEDOUT; 3165553bb068SMichael Tuexen } else { 3166410a3b1eSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED); 3167410a3b1eSMichael Tuexen stcb->sctp_socket->so_error = ECONNABORTED; 3168410a3b1eSMichael Tuexen } 316958411b08SMichael Tuexen } 31703acfe1e1SGleb Smirnoff SOCK_UNLOCK(stcb->sctp_socket); 3171553bb068SMichael Tuexen } 317258411b08SMichael Tuexen /* Wake ANY sleepers */ 3173ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3174ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3175ceaad40aSRandall Stewart if (!so_locked) { 3176ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3177ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3178ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3179ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3180ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3181ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3182ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3183ceaad40aSRandall Stewart return; 3184ceaad40aSRandall Stewart } 3185ceaad40aSRandall Stewart } 3186ceaad40aSRandall Stewart #endif 318758411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 318858411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 318958411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 31903acfe1e1SGleb Smirnoff socantrcvmore(stcb->sctp_socket); 319158411b08SMichael Tuexen } 319258411b08SMichael Tuexen sorwakeup(stcb->sctp_socket); 319358411b08SMichael Tuexen sowwakeup(stcb->sctp_socket); 3194ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3195ceaad40aSRandall Stewart if (!so_locked) { 3196ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3197ceaad40aSRandall Stewart } 3198ceaad40aSRandall Stewart #endif 3199f8829a4aSRandall Stewart } 3200f8829a4aSRandall Stewart 3201f8829a4aSRandall Stewart static void 3202f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, 32033cb3567dSMichael Tuexen struct sockaddr *sa, uint32_t error, int so_locked 32043cb3567dSMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 32053cb3567dSMichael Tuexen SCTP_UNUSED 32063cb3567dSMichael Tuexen #endif 32073cb3567dSMichael Tuexen ) 3208f8829a4aSRandall Stewart { 3209f8829a4aSRandall Stewart struct mbuf *m_notify; 3210f8829a4aSRandall Stewart struct sctp_paddr_change *spc; 3211f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3212f8829a4aSRandall Stewart 321360990c0cSMichael Tuexen if ((stcb == NULL) || 321460990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { 3215f8829a4aSRandall Stewart /* event not enabled */ 3216f8829a4aSRandall Stewart return; 3217830d754dSRandall Stewart } 3218eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA); 3219f8829a4aSRandall Stewart if (m_notify == NULL) 3220f8829a4aSRandall Stewart return; 3221139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3222f8829a4aSRandall Stewart spc = mtod(m_notify, struct sctp_paddr_change *); 322356711f94SMichael Tuexen memset(spc, 0, sizeof(struct sctp_paddr_change)); 3224f8829a4aSRandall Stewart spc->spc_type = SCTP_PEER_ADDR_CHANGE; 3225f8829a4aSRandall Stewart spc->spc_flags = 0; 3226f8829a4aSRandall Stewart spc->spc_length = sizeof(struct sctp_paddr_change); 32275e2c2d87SRandall Stewart switch (sa->sa_family) { 3228ea5eba11SMichael Tuexen #ifdef INET 32295e2c2d87SRandall Stewart case AF_INET: 3230d59107f7SMichael Tuexen #ifdef INET6 3231d59107f7SMichael Tuexen if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 3232d59107f7SMichael Tuexen in6_sin_2_v4mapsin6((struct sockaddr_in *)sa, 3233d59107f7SMichael Tuexen (struct sockaddr_in6 *)&spc->spc_aaddr); 3234d59107f7SMichael Tuexen } else { 3235f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 3236d59107f7SMichael Tuexen } 3237d59107f7SMichael Tuexen #else 3238d59107f7SMichael Tuexen memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 3239d59107f7SMichael Tuexen #endif 32405e2c2d87SRandall Stewart break; 3241ea5eba11SMichael Tuexen #endif 32425e2c2d87SRandall Stewart #ifdef INET6 32435e2c2d87SRandall Stewart case AF_INET6: 32445e2c2d87SRandall Stewart { 3245f42a358aSRandall Stewart struct sockaddr_in6 *sin6; 3246f42a358aSRandall Stewart 3247f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6)); 3248f42a358aSRandall Stewart 3249f42a358aSRandall Stewart sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; 3250f42a358aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 325142551e99SRandall Stewart if (sin6->sin6_scope_id == 0) { 325242551e99SRandall Stewart /* recover scope_id for user */ 3253f42a358aSRandall Stewart (void)sa6_recoverscope(sin6); 325442551e99SRandall Stewart } else { 325542551e99SRandall Stewart /* clear embedded scope_id for user */ 325642551e99SRandall Stewart in6_clearscope(&sin6->sin6_addr); 325742551e99SRandall Stewart } 3258f42a358aSRandall Stewart } 32595e2c2d87SRandall Stewart break; 32605e2c2d87SRandall Stewart } 32615e2c2d87SRandall Stewart #endif 32625e2c2d87SRandall Stewart default: 32635e2c2d87SRandall Stewart /* TSNH */ 32645e2c2d87SRandall Stewart break; 3265f8829a4aSRandall Stewart } 3266f8829a4aSRandall Stewart spc->spc_state = state; 3267f8829a4aSRandall Stewart spc->spc_error = error; 3268f8829a4aSRandall Stewart spc->spc_assoc_id = sctp_get_associd(stcb); 3269f8829a4aSRandall Stewart 3270139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change); 3271139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3272f8829a4aSRandall Stewart 3273f8829a4aSRandall Stewart /* append to socket */ 3274f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 32757215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3276f8829a4aSRandall Stewart m_notify); 3277f8829a4aSRandall Stewart if (control == NULL) { 3278f8829a4aSRandall Stewart /* no memory */ 3279f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3280f8829a4aSRandall Stewart return; 3281f8829a4aSRandall Stewart } 3282139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3283139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3284f8829a4aSRandall Stewart /* not that we need this */ 3285f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3286f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3287f8829a4aSRandall Stewart control, 3288cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 3289cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 32903cb3567dSMichael Tuexen so_locked); 3291f8829a4aSRandall Stewart } 3292f8829a4aSRandall Stewart 3293f8829a4aSRandall Stewart 3294f8829a4aSRandall Stewart static void 32951edc9dbaSMichael Tuexen sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, 3296ceaad40aSRandall Stewart struct sctp_tmit_chunk *chk, int so_locked 3297ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3298ceaad40aSRandall Stewart SCTP_UNUSED 3299ceaad40aSRandall Stewart #endif 3300ceaad40aSRandall Stewart ) 3301f8829a4aSRandall Stewart { 3302830d754dSRandall Stewart struct mbuf *m_notify; 3303f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 33049935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 3305f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3306ab337314SMichael Tuexen struct sctp_chunkhdr *chkhdr; 3307ab337314SMichael Tuexen int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len; 3308f8829a4aSRandall Stewart 330960990c0cSMichael Tuexen if ((stcb == NULL) || 33109935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 33119935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 3312f8829a4aSRandall Stewart /* event not enabled */ 3313f8829a4aSRandall Stewart return; 3314830d754dSRandall Stewart } 33150053ed28SMichael Tuexen 33169935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 3317ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed_event); 33189935403aSMichael Tuexen } else { 3319ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed); 33209935403aSMichael Tuexen } 3321ab337314SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); 3322f8829a4aSRandall Stewart if (m_notify == NULL) 3323f8829a4aSRandall Stewart /* no space left */ 3324f8829a4aSRandall Stewart return; 3325ab337314SMichael Tuexen SCTP_BUF_LEN(m_notify) = notifhdr_len; 3326ab337314SMichael Tuexen if (stcb->asoc.idata_supported) { 3327ab337314SMichael Tuexen chkhdr_len = sizeof(struct sctp_idata_chunk); 3328ab337314SMichael Tuexen } else { 3329ab337314SMichael Tuexen chkhdr_len = sizeof(struct sctp_data_chunk); 3330ab337314SMichael Tuexen } 3331ab337314SMichael Tuexen /* Use some defaults in case we can't access the chunk header */ 3332ab337314SMichael Tuexen if (chk->send_size >= chkhdr_len) { 3333ab337314SMichael Tuexen payload_len = chk->send_size - chkhdr_len; 3334ab337314SMichael Tuexen } else { 3335ab337314SMichael Tuexen payload_len = 0; 3336ab337314SMichael Tuexen } 3337ab337314SMichael Tuexen padding_len = 0; 3338ab337314SMichael Tuexen if (chk->data != NULL) { 3339ab337314SMichael Tuexen chkhdr = mtod(chk->data, struct sctp_chunkhdr *); 3340ab337314SMichael Tuexen if (chkhdr != NULL) { 3341ab337314SMichael Tuexen chk_len = ntohs(chkhdr->chunk_length); 3342ab337314SMichael Tuexen if ((chk_len >= chkhdr_len) && 3343ab337314SMichael Tuexen (chk->send_size >= chk_len) && 3344ab337314SMichael Tuexen (chk->send_size - chk_len < 4)) { 3345ab337314SMichael Tuexen padding_len = chk->send_size - chk_len; 3346ab337314SMichael Tuexen payload_len = chk->send_size - chkhdr_len - padding_len; 3347ab337314SMichael Tuexen } 3348ab337314SMichael Tuexen } 3349ab337314SMichael Tuexen } 33509935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 33519935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 3352ab337314SMichael Tuexen memset(ssfe, 0, notifhdr_len); 33539935403aSMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 33541edc9dbaSMichael Tuexen if (sent) { 33559935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_SENT; 33561edc9dbaSMichael Tuexen } else { 33571edc9dbaSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 33581edc9dbaSMichael Tuexen } 3359ab337314SMichael Tuexen ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len); 33609935403aSMichael Tuexen ssfe->ssfe_error = error; 33619935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 336249656eefSMichael Tuexen ssfe->ssfe_info.snd_sid = chk->rec.data.sid; 33639935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags; 336449656eefSMichael Tuexen ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid; 33659935403aSMichael Tuexen ssfe->ssfe_info.snd_context = chk->rec.data.context; 33669935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 33679935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 33689935403aSMichael Tuexen } else { 3369f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 3370ab337314SMichael Tuexen memset(ssf, 0, notifhdr_len); 3371f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 33721edc9dbaSMichael Tuexen if (sent) { 3373f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_SENT; 33741edc9dbaSMichael Tuexen } else { 33751edc9dbaSMichael Tuexen ssf->ssf_flags = SCTP_DATA_UNSENT; 33761edc9dbaSMichael Tuexen } 3377ab337314SMichael Tuexen ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len); 3378f8829a4aSRandall Stewart ssf->ssf_error = error; 3379f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 338049656eefSMichael Tuexen ssf->ssf_info.sinfo_stream = chk->rec.data.sid; 338149656eefSMichael Tuexen ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid; 3382f8829a4aSRandall Stewart ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; 338349656eefSMichael Tuexen ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid; 3384f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = chk->rec.data.context; 3385f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 3386f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 33879935403aSMichael Tuexen } 3388ab337314SMichael Tuexen if (chk->data != NULL) { 3389ab337314SMichael Tuexen /* Trim off the sctp chunk header (it should be there) */ 3390ab337314SMichael Tuexen if (chk->send_size == chkhdr_len + payload_len + padding_len) { 3391ab337314SMichael Tuexen m_adj(chk->data, chkhdr_len); 3392ab337314SMichael Tuexen m_adj(chk->data, -padding_len); 3393830d754dSRandall Stewart sctp_mbuf_crush(chk->data); 3394ab337314SMichael Tuexen chk->send_size -= (chkhdr_len + padding_len); 3395830d754dSRandall Stewart } 3396830d754dSRandall Stewart } 3397810ec536SMichael Tuexen SCTP_BUF_NEXT(m_notify) = chk->data; 3398f8829a4aSRandall Stewart /* Steal off the mbuf */ 3399f8829a4aSRandall Stewart chk->data = NULL; 3400f8829a4aSRandall Stewart /* 3401f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 3402f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 3403f8829a4aSRandall Stewart * non-reader 3404f8829a4aSRandall Stewart */ 3405139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3406f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3407f8829a4aSRandall Stewart return; 3408f8829a4aSRandall Stewart } 3409f8829a4aSRandall Stewart /* append to socket */ 3410f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 34117215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3412f8829a4aSRandall Stewart m_notify); 3413f8829a4aSRandall Stewart if (control == NULL) { 3414f8829a4aSRandall Stewart /* no memory */ 3415f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3416f8829a4aSRandall Stewart return; 3417f8829a4aSRandall Stewart } 341828cd0699SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3419139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 342028cd0699SMichael Tuexen /* not that we need this */ 342128cd0699SMichael Tuexen control->tail_mbuf = m_notify; 3422f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3423f8829a4aSRandall Stewart control, 3424cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 3425cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 3426cfde3ff7SRandall Stewart so_locked); 3427f8829a4aSRandall Stewart } 3428f8829a4aSRandall Stewart 3429f8829a4aSRandall Stewart 3430f8829a4aSRandall Stewart static void 3431f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, 3432ceaad40aSRandall Stewart struct sctp_stream_queue_pending *sp, int so_locked 3433ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3434ceaad40aSRandall Stewart SCTP_UNUSED 3435ceaad40aSRandall Stewart #endif 3436ceaad40aSRandall Stewart ) 3437f8829a4aSRandall Stewart { 3438f8829a4aSRandall Stewart struct mbuf *m_notify; 3439f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 34409935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 3441f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3442ab337314SMichael Tuexen int notifhdr_len; 3443f8829a4aSRandall Stewart 344460990c0cSMichael Tuexen if ((stcb == NULL) || 34459935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 34469935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 3447f8829a4aSRandall Stewart /* event not enabled */ 3448f8829a4aSRandall Stewart return; 3449830d754dSRandall Stewart } 34509935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 3451ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed_event); 34529935403aSMichael Tuexen } else { 3453ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed); 34549935403aSMichael Tuexen } 3455ab337314SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); 34569935403aSMichael Tuexen if (m_notify == NULL) { 3457f8829a4aSRandall Stewart /* no space left */ 3458f8829a4aSRandall Stewart return; 34599935403aSMichael Tuexen } 3460ab337314SMichael Tuexen SCTP_BUF_LEN(m_notify) = notifhdr_len; 34619935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 34629935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 3463ab337314SMichael Tuexen memset(ssfe, 0, notifhdr_len); 3464ad83c8a5SMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 34659935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 3466ab337314SMichael Tuexen ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length); 34679935403aSMichael Tuexen ssfe->ssfe_error = error; 34689935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 346949656eefSMichael Tuexen ssfe->ssfe_info.snd_sid = sp->sid; 34709935403aSMichael Tuexen if (sp->some_taken) { 34719935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG; 34729935403aSMichael Tuexen } else { 34739935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG; 34749935403aSMichael Tuexen } 34759935403aSMichael Tuexen ssfe->ssfe_info.snd_ppid = sp->ppid; 34769935403aSMichael Tuexen ssfe->ssfe_info.snd_context = sp->context; 34779935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 34789935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 34799935403aSMichael Tuexen } else { 3480f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 3481ab337314SMichael Tuexen memset(ssf, 0, notifhdr_len); 3482f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 3483f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_UNSENT; 3484ab337314SMichael Tuexen ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length); 3485f8829a4aSRandall Stewart ssf->ssf_error = error; 3486f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 348749656eefSMichael Tuexen ssf->ssf_info.sinfo_stream = sp->sid; 3488f3b05218SMichael Tuexen ssf->ssf_info.sinfo_ssn = 0; 3489fc14de76SRandall Stewart if (sp->some_taken) { 3490fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG; 3491fc14de76SRandall Stewart } else { 3492fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG; 3493fc14de76SRandall Stewart } 3494f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = sp->ppid; 3495f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = sp->context; 3496f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 3497f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 34989935403aSMichael Tuexen } 34999935403aSMichael Tuexen SCTP_BUF_NEXT(m_notify) = sp->data; 3500f8829a4aSRandall Stewart 3501f8829a4aSRandall Stewart /* Steal off the mbuf */ 3502f8829a4aSRandall Stewart sp->data = NULL; 3503f8829a4aSRandall Stewart /* 3504f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 3505f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 3506f8829a4aSRandall Stewart * non-reader 3507f8829a4aSRandall Stewart */ 3508139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3509f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3510f8829a4aSRandall Stewart return; 3511f8829a4aSRandall Stewart } 3512f8829a4aSRandall Stewart /* append to socket */ 3513f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 35147215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3515f8829a4aSRandall Stewart m_notify); 3516f8829a4aSRandall Stewart if (control == NULL) { 3517f8829a4aSRandall Stewart /* no memory */ 3518f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3519f8829a4aSRandall Stewart return; 3520f8829a4aSRandall Stewart } 352128cd0699SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3522139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 352328cd0699SMichael Tuexen /* not that we need this */ 352428cd0699SMichael Tuexen control->tail_mbuf = m_notify; 3525f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3526f8829a4aSRandall Stewart control, 3527cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3528f8829a4aSRandall Stewart } 3529f8829a4aSRandall Stewart 3530f8829a4aSRandall Stewart 3531f8829a4aSRandall Stewart 3532f8829a4aSRandall Stewart static void 35337215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb) 3534f8829a4aSRandall Stewart { 3535f8829a4aSRandall Stewart struct mbuf *m_notify; 3536f8829a4aSRandall Stewart struct sctp_adaptation_event *sai; 3537f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3538f8829a4aSRandall Stewart 353960990c0cSMichael Tuexen if ((stcb == NULL) || 354060990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { 3541f8829a4aSRandall Stewart /* event not enabled */ 3542f8829a4aSRandall Stewart return; 3543830d754dSRandall Stewart } 35440053ed28SMichael Tuexen 3545eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA); 3546f8829a4aSRandall Stewart if (m_notify == NULL) 3547f8829a4aSRandall Stewart /* no space left */ 3548f8829a4aSRandall Stewart return; 3549139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3550f8829a4aSRandall Stewart sai = mtod(m_notify, struct sctp_adaptation_event *); 3551e432298aSXin LI memset(sai, 0, sizeof(struct sctp_adaptation_event)); 3552f8829a4aSRandall Stewart sai->sai_type = SCTP_ADAPTATION_INDICATION; 3553f8829a4aSRandall Stewart sai->sai_flags = 0; 3554f8829a4aSRandall Stewart sai->sai_length = sizeof(struct sctp_adaptation_event); 35552afb3e84SRandall Stewart sai->sai_adaptation_ind = stcb->asoc.peers_adaptation; 3556f8829a4aSRandall Stewart sai->sai_assoc_id = sctp_get_associd(stcb); 3557f8829a4aSRandall Stewart 3558139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event); 3559139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3560f8829a4aSRandall Stewart 3561f8829a4aSRandall Stewart /* append to socket */ 3562f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 35637215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3564f8829a4aSRandall Stewart m_notify); 3565f8829a4aSRandall Stewart if (control == NULL) { 3566f8829a4aSRandall Stewart /* no memory */ 3567f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3568f8829a4aSRandall Stewart return; 3569f8829a4aSRandall Stewart } 3570139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3571139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3572f8829a4aSRandall Stewart /* not that we need this */ 3573f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3574f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3575f8829a4aSRandall Stewart control, 3576cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3577f8829a4aSRandall Stewart } 3578f8829a4aSRandall Stewart 357903b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */ 3580810ec536SMichael Tuexen static void 35812dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, 3582810ec536SMichael Tuexen uint32_t val, int so_locked 3583810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3584810ec536SMichael Tuexen SCTP_UNUSED 3585810ec536SMichael Tuexen #endif 3586810ec536SMichael Tuexen ) 3587f8829a4aSRandall Stewart { 3588f8829a4aSRandall Stewart struct mbuf *m_notify; 3589f8829a4aSRandall Stewart struct sctp_pdapi_event *pdapi; 3590f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 359103b0b021SRandall Stewart struct sockbuf *sb; 3592f8829a4aSRandall Stewart 359360990c0cSMichael Tuexen if ((stcb == NULL) || 359460990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { 3595f8829a4aSRandall Stewart /* event not enabled */ 3596f8829a4aSRandall Stewart return; 3597830d754dSRandall Stewart } 3598cd1386abSMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 3599cd1386abSMichael Tuexen return; 3600cd1386abSMichael Tuexen } 36010053ed28SMichael Tuexen 3602eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA); 3603f8829a4aSRandall Stewart if (m_notify == NULL) 3604f8829a4aSRandall Stewart /* no space left */ 3605f8829a4aSRandall Stewart return; 3606139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3607f8829a4aSRandall Stewart pdapi = mtod(m_notify, struct sctp_pdapi_event *); 3608e432298aSXin LI memset(pdapi, 0, sizeof(struct sctp_pdapi_event)); 3609f8829a4aSRandall Stewart pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; 3610f8829a4aSRandall Stewart pdapi->pdapi_flags = 0; 3611f8829a4aSRandall Stewart pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); 3612f8829a4aSRandall Stewart pdapi->pdapi_indication = error; 36139a6142d8SRandall Stewart pdapi->pdapi_stream = (val >> 16); 36149a6142d8SRandall Stewart pdapi->pdapi_seq = (val & 0x0000ffff); 3615f8829a4aSRandall Stewart pdapi->pdapi_assoc_id = sctp_get_associd(stcb); 3616f8829a4aSRandall Stewart 3617139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); 3618139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3619f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 36207215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3621f8829a4aSRandall Stewart m_notify); 3622f8829a4aSRandall Stewart if (control == NULL) { 3623f8829a4aSRandall Stewart /* no memory */ 3624f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3625f8829a4aSRandall Stewart return; 3626f8829a4aSRandall Stewart } 3627139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 362828cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3629f8829a4aSRandall Stewart /* not that we need this */ 3630f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 363103b0b021SRandall Stewart sb = &stcb->sctp_socket->so_rcv; 3632b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 3633139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify)); 363480fefe0aSRandall Stewart } 363503b0b021SRandall Stewart sctp_sballoc(stcb, sb, m_notify); 3636b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 363703b0b021SRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 363880fefe0aSRandall Stewart } 363903b0b021SRandall Stewart control->end_added = 1; 364003b0b021SRandall Stewart if (stcb->asoc.control_pdapi) 364103b0b021SRandall Stewart TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); 364203b0b021SRandall Stewart else { 364303b0b021SRandall Stewart /* we really should not see this case */ 364403b0b021SRandall Stewart TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); 364503b0b021SRandall Stewart } 364603b0b021SRandall Stewart if (stcb->sctp_ep && stcb->sctp_socket) { 364703b0b021SRandall Stewart /* This should always be the case */ 3648810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3649810ec536SMichael Tuexen struct socket *so; 3650810ec536SMichael Tuexen 3651810ec536SMichael Tuexen so = SCTP_INP_SO(stcb->sctp_ep); 3652810ec536SMichael Tuexen if (!so_locked) { 3653810ec536SMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, 1); 3654810ec536SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 3655810ec536SMichael Tuexen SCTP_SOCKET_LOCK(so, 1); 3656810ec536SMichael Tuexen SCTP_TCB_LOCK(stcb); 3657810ec536SMichael Tuexen atomic_subtract_int(&stcb->asoc.refcnt, 1); 3658810ec536SMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3659810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3660810ec536SMichael Tuexen return; 3661810ec536SMichael Tuexen } 3662810ec536SMichael Tuexen } 3663810ec536SMichael Tuexen #endif 366403b0b021SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 3665810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3666810ec536SMichael Tuexen if (!so_locked) { 3667810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3668810ec536SMichael Tuexen } 3669810ec536SMichael Tuexen #endif 3670f8829a4aSRandall Stewart } 3671f8829a4aSRandall Stewart } 3672f8829a4aSRandall Stewart 3673f8829a4aSRandall Stewart static void 3674f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb) 3675f8829a4aSRandall Stewart { 3676f8829a4aSRandall Stewart struct mbuf *m_notify; 3677f8829a4aSRandall Stewart struct sctp_shutdown_event *sse; 3678f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3679f8829a4aSRandall Stewart 3680f8829a4aSRandall Stewart /* 3681f8829a4aSRandall Stewart * For TCP model AND UDP connected sockets we will send an error up 3682f8829a4aSRandall Stewart * when an SHUTDOWN completes 3683f8829a4aSRandall Stewart */ 3684f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3685f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3686f8829a4aSRandall Stewart /* mark socket closed for read/write and wakeup! */ 3687ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3688ceaad40aSRandall Stewart struct socket *so; 3689ceaad40aSRandall Stewart 3690ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3691ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3692ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3693ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3694ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3695ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3696ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3697ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3698ceaad40aSRandall Stewart return; 3699ceaad40aSRandall Stewart } 3700ceaad40aSRandall Stewart #endif 3701f8829a4aSRandall Stewart socantsendmore(stcb->sctp_socket); 3702ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3703ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3704ceaad40aSRandall Stewart #endif 3705f8829a4aSRandall Stewart } 3706e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { 3707f8829a4aSRandall Stewart /* event not enabled */ 3708f8829a4aSRandall Stewart return; 3709830d754dSRandall Stewart } 37100053ed28SMichael Tuexen 3711eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA); 3712f8829a4aSRandall Stewart if (m_notify == NULL) 3713f8829a4aSRandall Stewart /* no space left */ 3714f8829a4aSRandall Stewart return; 3715f8829a4aSRandall Stewart sse = mtod(m_notify, struct sctp_shutdown_event *); 3716e432298aSXin LI memset(sse, 0, sizeof(struct sctp_shutdown_event)); 3717f8829a4aSRandall Stewart sse->sse_type = SCTP_SHUTDOWN_EVENT; 3718f8829a4aSRandall Stewart sse->sse_flags = 0; 3719f8829a4aSRandall Stewart sse->sse_length = sizeof(struct sctp_shutdown_event); 3720f8829a4aSRandall Stewart sse->sse_assoc_id = sctp_get_associd(stcb); 3721f8829a4aSRandall Stewart 3722139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event); 3723139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3724f8829a4aSRandall Stewart 3725f8829a4aSRandall Stewart /* append to socket */ 3726f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 37277215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3728f8829a4aSRandall Stewart m_notify); 3729f8829a4aSRandall Stewart if (control == NULL) { 3730f8829a4aSRandall Stewart /* no memory */ 3731f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3732f8829a4aSRandall Stewart return; 3733f8829a4aSRandall Stewart } 3734139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 373528cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3736f8829a4aSRandall Stewart /* not that we need this */ 3737f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3738f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3739f8829a4aSRandall Stewart control, 3740cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3741f8829a4aSRandall Stewart } 3742f8829a4aSRandall Stewart 3743f8829a4aSRandall Stewart static void 3744830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb, 3745830d754dSRandall Stewart int so_locked 3746830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3747830d754dSRandall Stewart SCTP_UNUSED 3748830d754dSRandall Stewart #endif 3749830d754dSRandall Stewart ) 3750830d754dSRandall Stewart { 3751830d754dSRandall Stewart struct mbuf *m_notify; 3752830d754dSRandall Stewart struct sctp_sender_dry_event *event; 3753830d754dSRandall Stewart struct sctp_queued_to_read *control; 3754830d754dSRandall Stewart 375560990c0cSMichael Tuexen if ((stcb == NULL) || 375660990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { 3757830d754dSRandall Stewart /* event not enabled */ 3758830d754dSRandall Stewart return; 3759830d754dSRandall Stewart } 37600053ed28SMichael Tuexen 3761eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA); 3762830d754dSRandall Stewart if (m_notify == NULL) { 3763830d754dSRandall Stewart /* no space left */ 3764830d754dSRandall Stewart return; 3765830d754dSRandall Stewart } 3766830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3767830d754dSRandall Stewart event = mtod(m_notify, struct sctp_sender_dry_event *); 3768e432298aSXin LI memset(event, 0, sizeof(struct sctp_sender_dry_event)); 3769830d754dSRandall Stewart event->sender_dry_type = SCTP_SENDER_DRY_EVENT; 3770830d754dSRandall Stewart event->sender_dry_flags = 0; 3771830d754dSRandall Stewart event->sender_dry_length = sizeof(struct sctp_sender_dry_event); 3772830d754dSRandall Stewart event->sender_dry_assoc_id = sctp_get_associd(stcb); 3773830d754dSRandall Stewart 3774830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event); 3775830d754dSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3776830d754dSRandall Stewart 3777830d754dSRandall Stewart /* append to socket */ 3778830d754dSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 37797215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 37807215cc1bSMichael Tuexen m_notify); 3781830d754dSRandall Stewart if (control == NULL) { 3782830d754dSRandall Stewart /* no memory */ 3783830d754dSRandall Stewart sctp_m_freem(m_notify); 3784830d754dSRandall Stewart return; 3785830d754dSRandall Stewart } 3786830d754dSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3787830d754dSRandall Stewart control->spec_flags = M_NOTIFICATION; 3788830d754dSRandall Stewart /* not that we need this */ 3789830d754dSRandall Stewart control->tail_mbuf = m_notify; 3790830d754dSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control, 3791cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3792830d754dSRandall Stewart } 3793830d754dSRandall Stewart 3794ea44232bSRandall Stewart 3795c4e848b7SRandall Stewart void 3796c4e848b7SRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag) 3797ea44232bSRandall Stewart { 3798ea44232bSRandall Stewart struct mbuf *m_notify; 3799ea44232bSRandall Stewart struct sctp_queued_to_read *control; 3800c4e848b7SRandall Stewart struct sctp_stream_change_event *stradd; 3801ea44232bSRandall Stewart 38028c501e51SMichael Tuexen if ((stcb == NULL) || 38038c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) { 3804ea44232bSRandall Stewart /* event not enabled */ 3805ea44232bSRandall Stewart return; 3806ea44232bSRandall Stewart } 3807c4e848b7SRandall Stewart if ((stcb->asoc.peer_req_out) && flag) { 3808c4e848b7SRandall Stewart /* Peer made the request, don't tell the local user */ 3809c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3810c4e848b7SRandall Stewart return; 3811c4e848b7SRandall Stewart } 3812c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3813e432298aSXin LI m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA); 3814ea44232bSRandall Stewart if (m_notify == NULL) 3815ea44232bSRandall Stewart /* no space left */ 3816ea44232bSRandall Stewart return; 3817ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3818c4e848b7SRandall Stewart stradd = mtod(m_notify, struct sctp_stream_change_event *); 3819e432298aSXin LI memset(stradd, 0, sizeof(struct sctp_stream_change_event)); 3820c4e848b7SRandall Stewart stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT; 3821c4e848b7SRandall Stewart stradd->strchange_flags = flag; 3822e432298aSXin LI stradd->strchange_length = sizeof(struct sctp_stream_change_event); 3823c4e848b7SRandall Stewart stradd->strchange_assoc_id = sctp_get_associd(stcb); 3824c4e848b7SRandall Stewart stradd->strchange_instrms = numberin; 3825c4e848b7SRandall Stewart stradd->strchange_outstrms = numberout; 3826e432298aSXin LI SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event); 3827ea44232bSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3828ea44232bSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3829ea44232bSRandall Stewart /* no space */ 3830ea44232bSRandall Stewart sctp_m_freem(m_notify); 3831ea44232bSRandall Stewart return; 3832ea44232bSRandall Stewart } 3833ea44232bSRandall Stewart /* append to socket */ 3834ea44232bSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 38357215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3836ea44232bSRandall Stewart m_notify); 3837ea44232bSRandall Stewart if (control == NULL) { 3838ea44232bSRandall Stewart /* no memory */ 3839ea44232bSRandall Stewart sctp_m_freem(m_notify); 3840ea44232bSRandall Stewart return; 3841ea44232bSRandall Stewart } 3842ea44232bSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 384328cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3844ea44232bSRandall Stewart /* not that we need this */ 3845ea44232bSRandall Stewart control->tail_mbuf = m_notify; 3846ea44232bSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3847ea44232bSRandall Stewart control, 3848cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3849ea44232bSRandall Stewart } 3850ea44232bSRandall Stewart 3851c4e848b7SRandall Stewart void 3852c4e848b7SRandall Stewart sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag) 3853c4e848b7SRandall Stewart { 3854c4e848b7SRandall Stewart struct mbuf *m_notify; 3855c4e848b7SRandall Stewart struct sctp_queued_to_read *control; 3856c4e848b7SRandall Stewart struct sctp_assoc_reset_event *strasoc; 3857c4e848b7SRandall Stewart 38588c501e51SMichael Tuexen if ((stcb == NULL) || 38598c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) { 3860c4e848b7SRandall Stewart /* event not enabled */ 3861c4e848b7SRandall Stewart return; 3862c4e848b7SRandall Stewart } 3863e432298aSXin LI m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA); 3864c4e848b7SRandall Stewart if (m_notify == NULL) 3865c4e848b7SRandall Stewart /* no space left */ 3866c4e848b7SRandall Stewart return; 3867c4e848b7SRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3868c4e848b7SRandall Stewart strasoc = mtod(m_notify, struct sctp_assoc_reset_event *); 3869e432298aSXin LI memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event)); 3870c4e848b7SRandall Stewart strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT; 3871c4e848b7SRandall Stewart strasoc->assocreset_flags = flag; 3872e432298aSXin LI strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event); 3873c4e848b7SRandall Stewart strasoc->assocreset_assoc_id = sctp_get_associd(stcb); 3874c4e848b7SRandall Stewart strasoc->assocreset_local_tsn = sending_tsn; 3875c4e848b7SRandall Stewart strasoc->assocreset_remote_tsn = recv_tsn; 3876e432298aSXin LI SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event); 3877c4e848b7SRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3878c4e848b7SRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3879c4e848b7SRandall Stewart /* no space */ 3880c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3881c4e848b7SRandall Stewart return; 3882c4e848b7SRandall Stewart } 3883c4e848b7SRandall Stewart /* append to socket */ 3884c4e848b7SRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3885c4e848b7SRandall Stewart 0, 0, stcb->asoc.context, 0, 0, 0, 3886c4e848b7SRandall Stewart m_notify); 3887c4e848b7SRandall Stewart if (control == NULL) { 3888c4e848b7SRandall Stewart /* no memory */ 3889c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3890c4e848b7SRandall Stewart return; 3891c4e848b7SRandall Stewart } 3892c4e848b7SRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 389328cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3894c4e848b7SRandall Stewart /* not that we need this */ 3895c4e848b7SRandall Stewart control->tail_mbuf = m_notify; 3896c4e848b7SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3897c4e848b7SRandall Stewart control, 3898c4e848b7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3899c4e848b7SRandall Stewart } 3900c4e848b7SRandall Stewart 3901c4e848b7SRandall Stewart 3902ea44232bSRandall Stewart 3903830d754dSRandall Stewart static void 3904f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb, 3905f8829a4aSRandall Stewart int number_entries, uint16_t *list, int flag) 3906f8829a4aSRandall Stewart { 3907f8829a4aSRandall Stewart struct mbuf *m_notify; 3908f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3909f8829a4aSRandall Stewart struct sctp_stream_reset_event *strreset; 3910f8829a4aSRandall Stewart int len; 3911f8829a4aSRandall Stewart 39128c501e51SMichael Tuexen if ((stcb == NULL) || 39138c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) { 3914f8829a4aSRandall Stewart /* event not enabled */ 3915f8829a4aSRandall Stewart return; 3916830d754dSRandall Stewart } 39170053ed28SMichael Tuexen 3918eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); 3919f8829a4aSRandall Stewart if (m_notify == NULL) 3920f8829a4aSRandall Stewart /* no space left */ 3921f8829a4aSRandall Stewart return; 3922139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3923f8829a4aSRandall Stewart len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); 3924f8829a4aSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3925f8829a4aSRandall Stewart /* never enough room */ 3926f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3927f8829a4aSRandall Stewart return; 3928f8829a4aSRandall Stewart } 3929f8829a4aSRandall Stewart strreset = mtod(m_notify, struct sctp_stream_reset_event *); 3930e432298aSXin LI memset(strreset, 0, len); 3931f8829a4aSRandall Stewart strreset->strreset_type = SCTP_STREAM_RESET_EVENT; 3932c4e848b7SRandall Stewart strreset->strreset_flags = flag; 3933f8829a4aSRandall Stewart strreset->strreset_length = len; 3934f8829a4aSRandall Stewart strreset->strreset_assoc_id = sctp_get_associd(stcb); 3935f8829a4aSRandall Stewart if (number_entries) { 3936f8829a4aSRandall Stewart int i; 3937f8829a4aSRandall Stewart 3938f8829a4aSRandall Stewart for (i = 0; i < number_entries; i++) { 3939c4e848b7SRandall Stewart strreset->strreset_stream_list[i] = ntohs(list[i]); 3940f8829a4aSRandall Stewart } 3941f8829a4aSRandall Stewart } 3942139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3943139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3944139bc87fSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3945f8829a4aSRandall Stewart /* no space */ 3946f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3947f8829a4aSRandall Stewart return; 3948f8829a4aSRandall Stewart } 3949f8829a4aSRandall Stewart /* append to socket */ 3950f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 39517215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3952f8829a4aSRandall Stewart m_notify); 3953f8829a4aSRandall Stewart if (control == NULL) { 3954f8829a4aSRandall Stewart /* no memory */ 3955f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3956f8829a4aSRandall Stewart return; 3957f8829a4aSRandall Stewart } 3958139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 395928cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3960f8829a4aSRandall Stewart /* not that we need this */ 3961f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3962f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3963f8829a4aSRandall Stewart control, 3964cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3965f8829a4aSRandall Stewart } 3966f8829a4aSRandall Stewart 3967f8829a4aSRandall Stewart 3968389b1b11SMichael Tuexen static void 3969389b1b11SMichael Tuexen sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk) 3970389b1b11SMichael Tuexen { 3971389b1b11SMichael Tuexen struct mbuf *m_notify; 3972389b1b11SMichael Tuexen struct sctp_remote_error *sre; 3973389b1b11SMichael Tuexen struct sctp_queued_to_read *control; 39749a8e3088SMichael Tuexen unsigned int notif_len; 39759a8e3088SMichael Tuexen uint16_t chunk_len; 3976389b1b11SMichael Tuexen 3977389b1b11SMichael Tuexen if ((stcb == NULL) || 3978389b1b11SMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { 3979389b1b11SMichael Tuexen return; 3980389b1b11SMichael Tuexen } 3981389b1b11SMichael Tuexen if (chunk != NULL) { 3982c9eb4473SMichael Tuexen chunk_len = ntohs(chunk->ch.chunk_length); 39839669e724SMichael Tuexen /* 39849669e724SMichael Tuexen * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be 398545d41de5SMichael Tuexen * contiguous. 39869669e724SMichael Tuexen */ 39879669e724SMichael Tuexen if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) { 39889669e724SMichael Tuexen chunk_len = SCTP_CHUNK_BUFFER_SIZE; 39899669e724SMichael Tuexen } 3990389b1b11SMichael Tuexen } else { 3991389b1b11SMichael Tuexen chunk_len = 0; 3992389b1b11SMichael Tuexen } 39939a8e3088SMichael Tuexen notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len); 3994eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3995389b1b11SMichael Tuexen if (m_notify == NULL) { 3996389b1b11SMichael Tuexen /* Retry with smaller value. */ 39979a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_remote_error); 3998eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3999389b1b11SMichael Tuexen if (m_notify == NULL) { 4000389b1b11SMichael Tuexen return; 4001389b1b11SMichael Tuexen } 4002389b1b11SMichael Tuexen } 4003389b1b11SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 4004389b1b11SMichael Tuexen sre = mtod(m_notify, struct sctp_remote_error *); 400556711f94SMichael Tuexen memset(sre, 0, notif_len); 4006389b1b11SMichael Tuexen sre->sre_type = SCTP_REMOTE_ERROR; 4007389b1b11SMichael Tuexen sre->sre_flags = 0; 4008389b1b11SMichael Tuexen sre->sre_length = sizeof(struct sctp_remote_error); 4009389b1b11SMichael Tuexen sre->sre_error = error; 4010389b1b11SMichael Tuexen sre->sre_assoc_id = sctp_get_associd(stcb); 4011389b1b11SMichael Tuexen if (notif_len > sizeof(struct sctp_remote_error)) { 4012389b1b11SMichael Tuexen memcpy(sre->sre_data, chunk, chunk_len); 4013389b1b11SMichael Tuexen sre->sre_length += chunk_len; 4014389b1b11SMichael Tuexen } 4015389b1b11SMichael Tuexen SCTP_BUF_LEN(m_notify) = sre->sre_length; 4016389b1b11SMichael Tuexen control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 4017389b1b11SMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 4018389b1b11SMichael Tuexen m_notify); 4019389b1b11SMichael Tuexen if (control != NULL) { 4020389b1b11SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 402128cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 4022389b1b11SMichael Tuexen /* not that we need this */ 4023389b1b11SMichael Tuexen control->tail_mbuf = m_notify; 4024389b1b11SMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, 4025389b1b11SMichael Tuexen control, 4026389b1b11SMichael Tuexen &stcb->sctp_socket->so_rcv, 1, 4027389b1b11SMichael Tuexen SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 4028389b1b11SMichael Tuexen } else { 4029389b1b11SMichael Tuexen sctp_m_freem(m_notify); 4030389b1b11SMichael Tuexen } 4031389b1b11SMichael Tuexen } 4032389b1b11SMichael Tuexen 4033389b1b11SMichael Tuexen 4034f8829a4aSRandall Stewart void 4035f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, 4036ceaad40aSRandall Stewart uint32_t error, void *data, int so_locked 4037ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4038ceaad40aSRandall Stewart SCTP_UNUSED 4039ceaad40aSRandall Stewart #endif 4040ceaad40aSRandall Stewart ) 4041f8829a4aSRandall Stewart { 4042830d754dSRandall Stewart if ((stcb == NULL) || 4043830d754dSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4044f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 4045830d754dSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 4046830d754dSRandall Stewart /* If the socket is gone we are out of here */ 4047f8829a4aSRandall Stewart return; 4048f8829a4aSRandall Stewart } 4049a99b6783SRandall Stewart if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { 4050a99b6783SRandall Stewart return; 4051a99b6783SRandall Stewart } 4052839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 4053839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 405417205eccSRandall Stewart if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || 405517205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_UP) || 405617205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { 405717205eccSRandall Stewart /* Don't report these in front states */ 405817205eccSRandall Stewart return; 405917205eccSRandall Stewart } 406017205eccSRandall Stewart } 4061f8829a4aSRandall Stewart switch (notification) { 4062f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_UP: 4063f8829a4aSRandall Stewart if (stcb->asoc.assoc_up_sent == 0) { 4064410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked); 4065f8829a4aSRandall Stewart stcb->asoc.assoc_up_sent = 1; 4066f8829a4aSRandall Stewart } 40672afb3e84SRandall Stewart if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { 40687215cc1bSMichael Tuexen sctp_notify_adaptation_layer(stcb); 40692afb3e84SRandall Stewart } 4070c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 0) { 4071830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 4072830d754dSRandall Stewart NULL, so_locked); 4073830d754dSRandall Stewart } 4074f8829a4aSRandall Stewart break; 4075f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_DOWN: 4076410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked); 4077f8829a4aSRandall Stewart break; 4078f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_DOWN: 4079f8829a4aSRandall Stewart { 4080f8829a4aSRandall Stewart struct sctp_nets *net; 4081f8829a4aSRandall Stewart 4082f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 4083f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, 40843cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 4085f8829a4aSRandall Stewart break; 4086f8829a4aSRandall Stewart } 4087f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_UP: 4088f8829a4aSRandall Stewart { 4089f8829a4aSRandall Stewart struct sctp_nets *net; 4090f8829a4aSRandall Stewart 4091f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 4092f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, 40933cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 4094f8829a4aSRandall Stewart break; 4095f8829a4aSRandall Stewart } 4096f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_CONFIRMED: 4097f8829a4aSRandall Stewart { 4098f8829a4aSRandall Stewart struct sctp_nets *net; 4099f8829a4aSRandall Stewart 4100f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 4101f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, 41023cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 4103f8829a4aSRandall Stewart break; 4104f8829a4aSRandall Stewart } 4105f8829a4aSRandall Stewart case SCTP_NOTIFY_SPECIAL_SP_FAIL: 4106f8829a4aSRandall Stewart sctp_notify_send_failed2(stcb, error, 4107ceaad40aSRandall Stewart (struct sctp_stream_queue_pending *)data, so_locked); 4108f8829a4aSRandall Stewart break; 41091edc9dbaSMichael Tuexen case SCTP_NOTIFY_SENT_DG_FAIL: 41101edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 1, error, 41111edc9dbaSMichael Tuexen (struct sctp_tmit_chunk *)data, so_locked); 41121edc9dbaSMichael Tuexen break; 41131edc9dbaSMichael Tuexen case SCTP_NOTIFY_UNSENT_DG_FAIL: 41141edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 0, error, 4115ceaad40aSRandall Stewart (struct sctp_tmit_chunk *)data, so_locked); 4116f8829a4aSRandall Stewart break; 4117f8829a4aSRandall Stewart case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: 41189a6142d8SRandall Stewart { 41199a6142d8SRandall Stewart uint32_t val; 41209a6142d8SRandall Stewart 41219a6142d8SRandall Stewart val = *((uint32_t *)data); 41229a6142d8SRandall Stewart 4123810ec536SMichael Tuexen sctp_notify_partial_delivery_indication(stcb, error, val, so_locked); 4124f8829a4aSRandall Stewart break; 4125810ec536SMichael Tuexen } 4126410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_LOC_ABORTED: 4127839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 4128839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 4129410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked); 4130c105859eSRandall Stewart } else { 4131410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked); 4132410a3b1eSMichael Tuexen } 4133410a3b1eSMichael Tuexen break; 4134410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_REM_ABORTED: 4135839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 4136839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 4137410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked); 4138410a3b1eSMichael Tuexen } else { 4139410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked); 4140c105859eSRandall Stewart } 4141f8829a4aSRandall Stewart break; 4142f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_RESTART: 4143410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked); 4144c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 0) { 4145830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 4146830d754dSRandall Stewart NULL, so_locked); 4147830d754dSRandall Stewart } 4148f8829a4aSRandall Stewart break; 4149f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_SEND: 4150d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_OUTGOING_SSN); 4151f8829a4aSRandall Stewart break; 4152f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_RECV: 4153d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_INCOMING); 4154f8829a4aSRandall Stewart break; 4155f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_OUT: 4156c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4157d7714577SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED)); 4158f8829a4aSRandall Stewart break; 4159d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_OUT: 4160d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4161d4260646SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED)); 4162d4260646SMichael Tuexen break; 4163f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_IN: 4164c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4165d7714577SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED)); 4166f8829a4aSRandall Stewart break; 4167d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_IN: 4168d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4169d4260646SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED)); 4170d4260646SMichael Tuexen break; 4171f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_ADD_IP: 4172f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, 41733cb3567dSMichael Tuexen error, so_locked); 4174f8829a4aSRandall Stewart break; 4175f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_DELETE_IP: 4176f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, 41773cb3567dSMichael Tuexen error, so_locked); 4178f8829a4aSRandall Stewart break; 4179f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_SET_PRIMARY: 4180f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data, 41813cb3567dSMichael Tuexen error, so_locked); 4182f8829a4aSRandall Stewart break; 4183f8829a4aSRandall Stewart case SCTP_NOTIFY_PEER_SHUTDOWN: 4184f8829a4aSRandall Stewart sctp_notify_shutdown_event(stcb); 4185f8829a4aSRandall Stewart break; 4186f8829a4aSRandall Stewart case SCTP_NOTIFY_AUTH_NEW_KEY: 418778f28045SMichael Tuexen sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error, 4188830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 4189830d754dSRandall Stewart so_locked); 4190f8829a4aSRandall Stewart break; 4191830d754dSRandall Stewart case SCTP_NOTIFY_AUTH_FREE_KEY: 4192830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, 4193830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 4194830d754dSRandall Stewart so_locked); 4195f8829a4aSRandall Stewart break; 4196830d754dSRandall Stewart case SCTP_NOTIFY_NO_PEER_AUTH: 4197830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, 4198830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 4199830d754dSRandall Stewart so_locked); 4200830d754dSRandall Stewart break; 4201830d754dSRandall Stewart case SCTP_NOTIFY_SENDER_DRY: 4202830d754dSRandall Stewart sctp_notify_sender_dry_event(stcb, so_locked); 4203830d754dSRandall Stewart break; 4204389b1b11SMichael Tuexen case SCTP_NOTIFY_REMOTE_ERROR: 4205389b1b11SMichael Tuexen sctp_notify_remote_error(stcb, error, data); 4206389b1b11SMichael Tuexen break; 4207f8829a4aSRandall Stewart default: 4208ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", 42096e9c45e0SMichael Tuexen __func__, notification, notification); 4210f8829a4aSRandall Stewart break; 4211f8829a4aSRandall Stewart } /* end switch */ 4212f8829a4aSRandall Stewart } 4213f8829a4aSRandall Stewart 4214f8829a4aSRandall Stewart void 42151edc9dbaSMichael Tuexen sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked 4216ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4217ceaad40aSRandall Stewart SCTP_UNUSED 4218ceaad40aSRandall Stewart #endif 4219ceaad40aSRandall Stewart ) 4220f8829a4aSRandall Stewart { 4221f8829a4aSRandall Stewart struct sctp_association *asoc; 4222f8829a4aSRandall Stewart struct sctp_stream_out *outs; 42234a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk; 42244a9ef3f8SMichael Tuexen struct sctp_stream_queue_pending *sp, *nsp; 42257f34832bSRandall Stewart int i; 4226f8829a4aSRandall Stewart 4227ad81507eSRandall Stewart if (stcb == NULL) { 4228ad81507eSRandall Stewart return; 4229ad81507eSRandall Stewart } 42304a9ef3f8SMichael Tuexen asoc = &stcb->asoc; 42314a9ef3f8SMichael Tuexen if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { 4232478fbccbSRandall Stewart /* already being freed */ 4233478fbccbSRandall Stewart return; 4234478fbccbSRandall Stewart } 4235f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4236f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 42374a9ef3f8SMichael Tuexen (asoc->state & SCTP_STATE_CLOSED_SOCKET)) { 4238f8829a4aSRandall Stewart return; 4239f8829a4aSRandall Stewart } 4240f8829a4aSRandall Stewart /* now through all the gunk freeing chunks */ 4241ad81507eSRandall Stewart if (holds_lock == 0) { 42427f34832bSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 4243ad81507eSRandall Stewart } 4244d00aff5dSRandall Stewart /* sent queue SHOULD be empty */ 42454a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { 4246d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); 4247d00aff5dSRandall Stewart asoc->sent_queue_cnt--; 4248325c8c46SMichael Tuexen if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { 424949656eefSMichael Tuexen if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { 425049656eefSMichael Tuexen asoc->strmout[chk->rec.data.sid].chunks_on_queues--; 4251a7ad6026SMichael Tuexen #ifdef INVARIANTS 4252a7ad6026SMichael Tuexen } else { 425349656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.sid); 4254a7ad6026SMichael Tuexen #endif 4255a7ad6026SMichael Tuexen } 4256a7ad6026SMichael Tuexen } 42570c0982b8SRandall Stewart if (chk->data != NULL) { 4258d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 42591edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 42601edc9dbaSMichael Tuexen error, chk, so_locked); 4261810ec536SMichael Tuexen if (chk->data) { 4262d00aff5dSRandall Stewart sctp_m_freem(chk->data); 4263d00aff5dSRandall Stewart chk->data = NULL; 4264d00aff5dSRandall Stewart } 4265810ec536SMichael Tuexen } 4266689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 4267d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 4268d00aff5dSRandall Stewart } 4269d00aff5dSRandall Stewart /* pending send queue SHOULD be empty */ 42704a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { 4271d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); 4272d00aff5dSRandall Stewart asoc->send_queue_cnt--; 427349656eefSMichael Tuexen if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { 427449656eefSMichael Tuexen asoc->strmout[chk->rec.data.sid].chunks_on_queues--; 4275a7ad6026SMichael Tuexen #ifdef INVARIANTS 4276a7ad6026SMichael Tuexen } else { 427749656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.sid); 4278a7ad6026SMichael Tuexen #endif 4279a7ad6026SMichael Tuexen } 42800c0982b8SRandall Stewart if (chk->data != NULL) { 4281d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 42821edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 42831edc9dbaSMichael Tuexen error, chk, so_locked); 4284810ec536SMichael Tuexen if (chk->data) { 4285d00aff5dSRandall Stewart sctp_m_freem(chk->data); 4286d00aff5dSRandall Stewart chk->data = NULL; 4287d00aff5dSRandall Stewart } 4288810ec536SMichael Tuexen } 4289689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 4290d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 4291d00aff5dSRandall Stewart } 42924a9ef3f8SMichael Tuexen for (i = 0; i < asoc->streamoutcnt; i++) { 42937f34832bSRandall Stewart /* For each stream */ 42944a9ef3f8SMichael Tuexen outs = &asoc->strmout[i]; 42957f34832bSRandall Stewart /* clean up any sends there */ 42964a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { 42974d58b0c3SMichael Tuexen atomic_subtract_int(&asoc->stream_queue_cnt, 1); 4298f8829a4aSRandall Stewart TAILQ_REMOVE(&outs->outqueue, sp, next); 4299d9707e43SMichael Tuexen stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1); 4300f8829a4aSRandall Stewart sctp_free_spbufspace(stcb, asoc, sp); 4301478fbccbSRandall Stewart if (sp->data) { 4302f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 43031edc9dbaSMichael Tuexen error, (void *)sp, so_locked); 4304f8829a4aSRandall Stewart if (sp->data) { 4305f8829a4aSRandall Stewart sctp_m_freem(sp->data); 4306f8829a4aSRandall Stewart sp->data = NULL; 4307d07b2ac6SMichael Tuexen sp->tail_mbuf = NULL; 4308d07b2ac6SMichael Tuexen sp->length = 0; 4309f8829a4aSRandall Stewart } 4310478fbccbSRandall Stewart } 43119eea4a2dSMichael Tuexen if (sp->net) { 4312f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 4313f8829a4aSRandall Stewart sp->net = NULL; 43149eea4a2dSMichael Tuexen } 4315f8829a4aSRandall Stewart /* Free the chunk */ 4316689e6a5fSMichael Tuexen sctp_free_a_strmoq(stcb, sp, so_locked); 43173c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 4318f8829a4aSRandall Stewart } 4319f8829a4aSRandall Stewart } 4320f8829a4aSRandall Stewart 4321ad81507eSRandall Stewart if (holds_lock == 0) { 43227f34832bSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 4323f8829a4aSRandall Stewart } 4324ad81507eSRandall Stewart } 4325f8829a4aSRandall Stewart 4326f8829a4aSRandall Stewart void 4327410a3b1eSMichael Tuexen sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error, 4328a2b42326SMichael Tuexen struct sctp_abort_chunk *abort, int so_locked 4329ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4330ceaad40aSRandall Stewart SCTP_UNUSED 4331ceaad40aSRandall Stewart #endif 4332ceaad40aSRandall Stewart ) 4333f8829a4aSRandall Stewart { 4334ad81507eSRandall Stewart if (stcb == NULL) { 4335ad81507eSRandall Stewart return; 4336ad81507eSRandall Stewart } 4337c55b70ceSMichael Tuexen if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4338c55b70ceSMichael Tuexen ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 4339c55b70ceSMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { 4340c55b70ceSMichael Tuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; 4341c55b70ceSMichael Tuexen } 4342f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4343f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 4344f8829a4aSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 4345f8829a4aSRandall Stewart return; 4346f8829a4aSRandall Stewart } 4347f8829a4aSRandall Stewart /* Tell them we lost the asoc */ 43486982c0faSMichael Tuexen sctp_report_all_outbound(stcb, error, 0, so_locked); 4349410a3b1eSMichael Tuexen if (from_peer) { 4350410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); 4351410a3b1eSMichael Tuexen } else { 4352410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); 4353410a3b1eSMichael Tuexen } 4354f8829a4aSRandall Stewart } 4355f8829a4aSRandall Stewart 4356f8829a4aSRandall Stewart void 4357f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 4358b1754ad1SMichael Tuexen struct mbuf *m, int iphlen, 4359b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4360b1754ad1SMichael Tuexen struct sctphdr *sh, struct mbuf *op_err, 4361457b4b88SMichael Tuexen uint8_t mflowtype, uint32_t mflowid, 4362c54a18d2SRandall Stewart uint32_t vrf_id, uint16_t port) 4363f8829a4aSRandall Stewart { 4364f8829a4aSRandall Stewart uint32_t vtag; 4365ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4366ceaad40aSRandall Stewart struct socket *so; 4367ceaad40aSRandall Stewart #endif 4368ceaad40aSRandall Stewart 4369f8829a4aSRandall Stewart vtag = 0; 4370f8829a4aSRandall Stewart if (stcb != NULL) { 4371f8829a4aSRandall Stewart vtag = stcb->asoc.peer_vtag; 437217205eccSRandall Stewart vrf_id = stcb->asoc.vrf_id; 4373f8829a4aSRandall Stewart } 4374b1754ad1SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, 4375d089f9b9SMichael Tuexen mflowtype, mflowid, inp->fibnum, 4376f30ac432SMichael Tuexen vrf_id, port); 4377f8829a4aSRandall Stewart if (stcb != NULL) { 4378884d8c53SMichael Tuexen /* We have a TCB to abort, send notification too */ 4379884d8c53SMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); 4380839d21d6SMichael Tuexen SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED); 4381f8829a4aSRandall Stewart /* Ok, now lets free it */ 4382ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4383ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4384ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4385ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4386ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4387ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4388ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4389ceaad40aSRandall Stewart #endif 43900271d0cdSMichael Tuexen SCTP_STAT_INCR_COUNTER32(sctps_aborted); 4391839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || 4392839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 43930271d0cdSMichael Tuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 43940271d0cdSMichael Tuexen } 4395ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 4396ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_4); 4397ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4398ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4399ceaad40aSRandall Stewart #endif 4400f8829a4aSRandall Stewart } 4401f8829a4aSRandall Stewart } 4402f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 4403f1f73e57SRandall Stewart void 4404f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb) 4405f1f73e57SRandall Stewart { 440618e198d3SRandall Stewart #ifdef NOSIY_PRINTS 4407f1f73e57SRandall Stewart int i; 4408f1f73e57SRandall Stewart 4409ad81507eSRandall Stewart SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code); 4410ad81507eSRandall Stewart SCTP_PRINTF("IN bound TSN log-aaa\n"); 4411f1f73e57SRandall Stewart if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) { 4412ad81507eSRandall Stewart SCTP_PRINTF("None rcvd\n"); 4413f1f73e57SRandall Stewart goto none_in; 4414f1f73e57SRandall Stewart } 4415f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_wrapped) { 4416f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) { 4417ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4418f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 4419f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 4420f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 4421f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 4422f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 4423f1f73e57SRandall Stewart } 4424f1f73e57SRandall Stewart } 4425f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_at) { 4426f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_in_at; i++) { 4427ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4428f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 4429f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 4430f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 4431f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 4432f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 4433f1f73e57SRandall Stewart } 4434f1f73e57SRandall Stewart } 4435f1f73e57SRandall Stewart none_in: 4436ad81507eSRandall Stewart SCTP_PRINTF("OUT bound TSN log-aaa\n"); 4437ad81507eSRandall Stewart if ((stcb->asoc.tsn_out_at == 0) && 4438ad81507eSRandall Stewart (stcb->asoc.tsn_out_wrapped == 0)) { 4439ad81507eSRandall Stewart SCTP_PRINTF("None sent\n"); 4440f1f73e57SRandall Stewart } 4441f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_wrapped) { 4442f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) { 4443ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4444f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 4445f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 4446f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 4447f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 4448f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 4449f1f73e57SRandall Stewart } 4450f1f73e57SRandall Stewart } 4451f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_at) { 4452f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_out_at; i++) { 4453ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4454f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 4455f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 4456f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 4457f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 4458f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 4459f1f73e57SRandall Stewart } 4460f1f73e57SRandall Stewart } 446118e198d3SRandall Stewart #endif 4462f1f73e57SRandall Stewart } 4463f1f73e57SRandall Stewart #endif 4464f1f73e57SRandall Stewart 4465f8829a4aSRandall Stewart void 4466f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 4467a2b42326SMichael Tuexen struct mbuf *op_err, 4468ceaad40aSRandall Stewart int so_locked 4469ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4470ceaad40aSRandall Stewart SCTP_UNUSED 4471ceaad40aSRandall Stewart #endif 4472ceaad40aSRandall Stewart ) 4473f8829a4aSRandall Stewart { 4474ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4475ceaad40aSRandall Stewart struct socket *so; 4476ceaad40aSRandall Stewart #endif 4477ceaad40aSRandall Stewart 4478ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4479ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4480ceaad40aSRandall Stewart #endif 4481f8829a4aSRandall Stewart if (stcb == NULL) { 4482f8829a4aSRandall Stewart /* Got to have a TCB */ 4483f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4484fe1831e0SMichael Tuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 4485b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4486b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4487f8829a4aSRandall Stewart } 4488f8829a4aSRandall Stewart } 4489f8829a4aSRandall Stewart return; 449063981c2bSRandall Stewart } else { 4491839d21d6SMichael Tuexen SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED); 4492f8829a4aSRandall Stewart } 4493f8829a4aSRandall Stewart /* notify the peer */ 4494ceaad40aSRandall Stewart sctp_send_abort_tcb(stcb, op_err, so_locked); 4495f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_aborted); 4496839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || 4497839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 4498f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 4499f8829a4aSRandall Stewart } 4500884d8c53SMichael Tuexen /* notify the ulp */ 4501884d8c53SMichael Tuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 4502884d8c53SMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, so_locked); 4503884d8c53SMichael Tuexen } 4504f8829a4aSRandall Stewart /* now free the asoc */ 4505f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 4506f1f73e57SRandall Stewart sctp_print_out_track_log(stcb); 4507f1f73e57SRandall Stewart #endif 4508ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4509ceaad40aSRandall Stewart if (!so_locked) { 4510ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4511ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4512ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4513ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4514ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4515ceaad40aSRandall Stewart } 4516ceaad40aSRandall Stewart #endif 4517ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 4518ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_5); 4519ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4520ceaad40aSRandall Stewart if (!so_locked) { 4521ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4522ceaad40aSRandall Stewart } 4523ceaad40aSRandall Stewart #endif 4524f8829a4aSRandall Stewart } 4525f8829a4aSRandall Stewart 4526f8829a4aSRandall Stewart void 4527b1754ad1SMichael Tuexen sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, 4528b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4529b1754ad1SMichael Tuexen struct sctphdr *sh, struct sctp_inpcb *inp, 4530ff1ffd74SMichael Tuexen struct mbuf *cause, 4531d089f9b9SMichael Tuexen uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, 4532f30ac432SMichael Tuexen uint32_t vrf_id, uint16_t port) 4533f8829a4aSRandall Stewart { 4534f8829a4aSRandall Stewart struct sctp_chunkhdr *ch, chunk_buf; 4535f8829a4aSRandall Stewart unsigned int chk_length; 4536c58e60beSMichael Tuexen int contains_init_chunk; 4537f8829a4aSRandall Stewart 4538f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue); 4539f8829a4aSRandall Stewart /* Generate a TO address for future reference */ 4540f8829a4aSRandall Stewart if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 4541fe1831e0SMichael Tuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 4542b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4543b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4544f8829a4aSRandall Stewart } 4545f8829a4aSRandall Stewart } 4546c58e60beSMichael Tuexen contains_init_chunk = 0; 4547f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4548f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4549f8829a4aSRandall Stewart while (ch != NULL) { 4550f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4551f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4552f8829a4aSRandall Stewart /* break to abort land */ 4553f8829a4aSRandall Stewart break; 4554f8829a4aSRandall Stewart } 4555f8829a4aSRandall Stewart switch (ch->chunk_type) { 4556c58e60beSMichael Tuexen case SCTP_INIT: 4557c58e60beSMichael Tuexen contains_init_chunk = 1; 4558c58e60beSMichael Tuexen break; 4559f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED: 4560f8829a4aSRandall Stewart /* we don't respond to pkt-dropped */ 4561f8829a4aSRandall Stewart return; 4562f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION: 4563f8829a4aSRandall Stewart /* we don't respond with an ABORT to an ABORT */ 4564f8829a4aSRandall Stewart return; 4565f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE: 4566f8829a4aSRandall Stewart /* 4567f8829a4aSRandall Stewart * we ignore it since we are not waiting for it and 4568f8829a4aSRandall Stewart * peer is gone 4569f8829a4aSRandall Stewart */ 4570f8829a4aSRandall Stewart return; 4571f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK: 4572b1754ad1SMichael Tuexen sctp_send_shutdown_complete2(src, dst, sh, 4573d089f9b9SMichael Tuexen mflowtype, mflowid, fibnum, 4574f30ac432SMichael Tuexen vrf_id, port); 4575f8829a4aSRandall Stewart return; 4576f8829a4aSRandall Stewart default: 4577f8829a4aSRandall Stewart break; 4578f8829a4aSRandall Stewart } 4579f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4580f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4581f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4582f8829a4aSRandall Stewart } 4583c58e60beSMichael Tuexen if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || 4584c58e60beSMichael Tuexen ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && 4585c58e60beSMichael Tuexen (contains_init_chunk == 0))) { 4586ff1ffd74SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, 0, cause, 4587d089f9b9SMichael Tuexen mflowtype, mflowid, fibnum, 4588f30ac432SMichael Tuexen vrf_id, port); 4589f8829a4aSRandall Stewart } 4590c58e60beSMichael Tuexen } 4591f8829a4aSRandall Stewart 4592f8829a4aSRandall Stewart /* 4593f8829a4aSRandall Stewart * check the inbound datagram to make sure there is not an abort inside it, 4594f8829a4aSRandall Stewart * if there is return 1, else return 0. 4595f8829a4aSRandall Stewart */ 4596f8829a4aSRandall Stewart int 4597f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtagfill) 4598f8829a4aSRandall Stewart { 4599f8829a4aSRandall Stewart struct sctp_chunkhdr *ch; 4600f8829a4aSRandall Stewart struct sctp_init_chunk *init_chk, chunk_buf; 4601f8829a4aSRandall Stewart int offset; 4602f8829a4aSRandall Stewart unsigned int chk_length; 4603f8829a4aSRandall Stewart 4604f8829a4aSRandall Stewart offset = iphlen + sizeof(struct sctphdr); 4605f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), 4606f8829a4aSRandall Stewart (uint8_t *)&chunk_buf); 4607f8829a4aSRandall Stewart while (ch != NULL) { 4608f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4609f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4610f8829a4aSRandall Stewart /* packet is probably corrupt */ 4611f8829a4aSRandall Stewart break; 4612f8829a4aSRandall Stewart } 4613f8829a4aSRandall Stewart /* we seem to be ok, is it an abort? */ 4614f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) { 4615f8829a4aSRandall Stewart /* yep, tell them */ 4616f8829a4aSRandall Stewart return (1); 4617f8829a4aSRandall Stewart } 4618f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_INITIATION) { 4619f8829a4aSRandall Stewart /* need to update the Vtag */ 4620f8829a4aSRandall Stewart init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 4621f8829a4aSRandall Stewart offset, sizeof(*init_chk), (uint8_t *)&chunk_buf); 4622f8829a4aSRandall Stewart if (init_chk != NULL) { 4623f8829a4aSRandall Stewart *vtagfill = ntohl(init_chk->init.initiate_tag); 4624f8829a4aSRandall Stewart } 4625f8829a4aSRandall Stewart } 4626f8829a4aSRandall Stewart /* Nope, move to the next chunk */ 4627f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4628f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4629f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4630f8829a4aSRandall Stewart } 4631f8829a4aSRandall Stewart return (0); 4632f8829a4aSRandall Stewart } 4633f8829a4aSRandall Stewart 4634f8829a4aSRandall Stewart /* 4635f8829a4aSRandall Stewart * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id 4636f8829a4aSRandall Stewart * set (i.e. it's 0) so, create this function to compare link local scopes 4637f8829a4aSRandall Stewart */ 46385e2c2d87SRandall Stewart #ifdef INET6 4639f8829a4aSRandall Stewart uint32_t 4640b0471b4bSMichael Tuexen sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2) 4641b0471b4bSMichael Tuexen { 4642f8829a4aSRandall Stewart struct sockaddr_in6 a, b; 4643f8829a4aSRandall Stewart 4644f8829a4aSRandall Stewart /* save copies */ 4645f8829a4aSRandall Stewart a = *addr1; 4646f8829a4aSRandall Stewart b = *addr2; 4647f8829a4aSRandall Stewart 4648f8829a4aSRandall Stewart if (a.sin6_scope_id == 0) 4649f8829a4aSRandall Stewart if (sa6_recoverscope(&a)) { 4650f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4651f8829a4aSRandall Stewart return (0); 4652f8829a4aSRandall Stewart } 4653f8829a4aSRandall Stewart if (b.sin6_scope_id == 0) 4654f8829a4aSRandall Stewart if (sa6_recoverscope(&b)) { 4655f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4656f8829a4aSRandall Stewart return (0); 4657f8829a4aSRandall Stewart } 4658f8829a4aSRandall Stewart if (a.sin6_scope_id != b.sin6_scope_id) 4659f8829a4aSRandall Stewart return (0); 4660f8829a4aSRandall Stewart 4661f8829a4aSRandall Stewart return (1); 4662f8829a4aSRandall Stewart } 4663f8829a4aSRandall Stewart 4664f8829a4aSRandall Stewart /* 4665f8829a4aSRandall Stewart * returns a sockaddr_in6 with embedded scope recovered and removed 4666f8829a4aSRandall Stewart */ 4667f8829a4aSRandall Stewart struct sockaddr_in6 * 4668f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store) 4669f8829a4aSRandall Stewart { 4670f8829a4aSRandall Stewart /* check and strip embedded scope junk */ 4671f8829a4aSRandall Stewart if (addr->sin6_family == AF_INET6) { 4672f8829a4aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) { 4673f8829a4aSRandall Stewart if (addr->sin6_scope_id == 0) { 4674f8829a4aSRandall Stewart *store = *addr; 4675f8829a4aSRandall Stewart if (!sa6_recoverscope(store)) { 4676f8829a4aSRandall Stewart /* use the recovered scope */ 4677f8829a4aSRandall Stewart addr = store; 4678f8829a4aSRandall Stewart } 4679f42a358aSRandall Stewart } else { 4680f8829a4aSRandall Stewart /* else, return the original "to" addr */ 4681f42a358aSRandall Stewart in6_clearscope(&addr->sin6_addr); 4682f8829a4aSRandall Stewart } 4683f8829a4aSRandall Stewart } 4684f8829a4aSRandall Stewart } 4685f8829a4aSRandall Stewart return (addr); 4686f8829a4aSRandall Stewart } 46875e2c2d87SRandall Stewart #endif 46885e2c2d87SRandall Stewart 4689f8829a4aSRandall Stewart /* 4690f8829a4aSRandall Stewart * are the two addresses the same? currently a "scopeless" check returns: 1 4691f8829a4aSRandall Stewart * if same, 0 if not 4692f8829a4aSRandall Stewart */ 469372fb6fdbSRandall Stewart int 4694f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2) 4695f8829a4aSRandall Stewart { 4696f8829a4aSRandall Stewart 4697f8829a4aSRandall Stewart /* must be valid */ 4698f8829a4aSRandall Stewart if (sa1 == NULL || sa2 == NULL) 4699f8829a4aSRandall Stewart return (0); 4700f8829a4aSRandall Stewart 4701f8829a4aSRandall Stewart /* must be the same family */ 4702f8829a4aSRandall Stewart if (sa1->sa_family != sa2->sa_family) 4703f8829a4aSRandall Stewart return (0); 4704f8829a4aSRandall Stewart 47055e2c2d87SRandall Stewart switch (sa1->sa_family) { 47065e2c2d87SRandall Stewart #ifdef INET6 47075e2c2d87SRandall Stewart case AF_INET6: 47085e2c2d87SRandall Stewart { 4709f8829a4aSRandall Stewart /* IPv6 addresses */ 4710f8829a4aSRandall Stewart struct sockaddr_in6 *sin6_1, *sin6_2; 4711f8829a4aSRandall Stewart 4712f8829a4aSRandall Stewart sin6_1 = (struct sockaddr_in6 *)sa1; 4713f8829a4aSRandall Stewart sin6_2 = (struct sockaddr_in6 *)sa2; 4714c54a18d2SRandall Stewart return (SCTP6_ARE_ADDR_EQUAL(sin6_1, 4715c54a18d2SRandall Stewart sin6_2)); 47165e2c2d87SRandall Stewart } 47175e2c2d87SRandall Stewart #endif 4718ea5eba11SMichael Tuexen #ifdef INET 47195e2c2d87SRandall Stewart case AF_INET: 47205e2c2d87SRandall Stewart { 4721f8829a4aSRandall Stewart /* IPv4 addresses */ 4722f8829a4aSRandall Stewart struct sockaddr_in *sin_1, *sin_2; 4723f8829a4aSRandall Stewart 4724f8829a4aSRandall Stewart sin_1 = (struct sockaddr_in *)sa1; 4725f8829a4aSRandall Stewart sin_2 = (struct sockaddr_in *)sa2; 4726f8829a4aSRandall Stewart return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr); 47275e2c2d87SRandall Stewart } 4728ea5eba11SMichael Tuexen #endif 47295e2c2d87SRandall Stewart default: 4730f8829a4aSRandall Stewart /* we don't do these... */ 4731f8829a4aSRandall Stewart return (0); 4732f8829a4aSRandall Stewart } 4733f8829a4aSRandall Stewart } 4734f8829a4aSRandall Stewart 4735f8829a4aSRandall Stewart void 4736f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa) 4737f8829a4aSRandall Stewart { 47385e2c2d87SRandall Stewart #ifdef INET6 47397d32aa0cSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 47405e2c2d87SRandall Stewart #endif 47415e2c2d87SRandall Stewart 47425e2c2d87SRandall Stewart switch (sa->sa_family) { 47435e2c2d87SRandall Stewart #ifdef INET6 47445e2c2d87SRandall Stewart case AF_INET6: 47455e2c2d87SRandall Stewart { 4746ad81507eSRandall Stewart struct sockaddr_in6 *sin6; 4747ad81507eSRandall Stewart 4748f8829a4aSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 4749ad81507eSRandall Stewart SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", 47507d32aa0cSBjoern A. Zeeb ip6_sprintf(ip6buf, &sin6->sin6_addr), 47517d32aa0cSBjoern A. Zeeb ntohs(sin6->sin6_port), 4752f8829a4aSRandall Stewart sin6->sin6_scope_id); 47535e2c2d87SRandall Stewart break; 47545e2c2d87SRandall Stewart } 47555e2c2d87SRandall Stewart #endif 4756ea5eba11SMichael Tuexen #ifdef INET 47575e2c2d87SRandall Stewart case AF_INET: 47585e2c2d87SRandall Stewart { 4759f8829a4aSRandall Stewart struct sockaddr_in *sin; 4760f8829a4aSRandall Stewart unsigned char *p; 4761f8829a4aSRandall Stewart 4762f8829a4aSRandall Stewart sin = (struct sockaddr_in *)sa; 4763f8829a4aSRandall Stewart p = (unsigned char *)&sin->sin_addr; 4764ad81507eSRandall Stewart SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n", 4765f8829a4aSRandall Stewart p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); 47665e2c2d87SRandall Stewart break; 47675e2c2d87SRandall Stewart } 4768ea5eba11SMichael Tuexen #endif 47695e2c2d87SRandall Stewart default: 4770ad81507eSRandall Stewart SCTP_PRINTF("?\n"); 47715e2c2d87SRandall Stewart break; 4772f8829a4aSRandall Stewart } 4773f8829a4aSRandall Stewart } 4774f8829a4aSRandall Stewart 4775f8829a4aSRandall Stewart void 4776f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, 4777f8829a4aSRandall Stewart struct sctp_inpcb *new_inp, 4778d06c82f1SRandall Stewart struct sctp_tcb *stcb, 4779d06c82f1SRandall Stewart int waitflags) 4780f8829a4aSRandall Stewart { 4781f8829a4aSRandall Stewart /* 4782f8829a4aSRandall Stewart * go through our old INP and pull off any control structures that 4783f8829a4aSRandall Stewart * belong to stcb and move then to the new inp. 4784f8829a4aSRandall Stewart */ 4785f8829a4aSRandall Stewart struct socket *old_so, *new_so; 4786f8829a4aSRandall Stewart struct sctp_queued_to_read *control, *nctl; 4787f8829a4aSRandall Stewart struct sctp_readhead tmp_queue; 4788f8829a4aSRandall Stewart struct mbuf *m; 4789bff64a4dSRandall Stewart int error = 0; 4790f8829a4aSRandall Stewart 4791f8829a4aSRandall Stewart old_so = old_inp->sctp_socket; 4792f8829a4aSRandall Stewart new_so = new_inp->sctp_socket; 4793f8829a4aSRandall Stewart TAILQ_INIT(&tmp_queue); 4794d06c82f1SRandall Stewart error = sblock(&old_so->so_rcv, waitflags); 4795f8829a4aSRandall Stewart if (error) { 4796f8829a4aSRandall Stewart /* 4797f8829a4aSRandall Stewart * Gak, can't get sblock, we have a problem. data will be 4798f8829a4aSRandall Stewart * left stranded.. and we don't dare look at it since the 4799f8829a4aSRandall Stewart * other thread may be reading something. Oh well, its a 4800f8829a4aSRandall Stewart * screwed up app that does a peeloff OR a accept while 4801f8829a4aSRandall Stewart * reading from the main socket... actually its only the 4802f8829a4aSRandall Stewart * peeloff() case, since I think read will fail on a 4803f8829a4aSRandall Stewart * listening socket.. 4804f8829a4aSRandall Stewart */ 4805f8829a4aSRandall Stewart return; 4806f8829a4aSRandall Stewart } 4807f8829a4aSRandall Stewart /* lock the socket buffers */ 4808f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(old_inp); 48094a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) { 4810f8829a4aSRandall Stewart /* Pull off all for out target stcb */ 4811f8829a4aSRandall Stewart if (control->stcb == stcb) { 4812f8829a4aSRandall Stewart /* remove it we want it */ 4813f8829a4aSRandall Stewart TAILQ_REMOVE(&old_inp->read_queue, control, next); 4814f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&tmp_queue, control, next); 4815f8829a4aSRandall Stewart m = control->data; 4816f8829a4aSRandall Stewart while (m) { 4817b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4818139bc87fSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 481980fefe0aSRandall Stewart } 4820f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &old_so->so_rcv, m); 4821b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4822f8829a4aSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 482380fefe0aSRandall Stewart } 4824139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4825f8829a4aSRandall Stewart } 4826f8829a4aSRandall Stewart } 4827f8829a4aSRandall Stewart } 4828f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(old_inp); 4829f8829a4aSRandall Stewart /* Remove the sb-lock on the old socket */ 4830f8829a4aSRandall Stewart 4831f8829a4aSRandall Stewart sbunlock(&old_so->so_rcv); 4832f8829a4aSRandall Stewart /* Now we move them over to the new socket buffer */ 4833f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(new_inp); 48344a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) { 4835f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next); 4836f8829a4aSRandall Stewart m = control->data; 4837f8829a4aSRandall Stewart while (m) { 4838b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4839139bc87fSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 484080fefe0aSRandall Stewart } 4841f8829a4aSRandall Stewart sctp_sballoc(stcb, &new_so->so_rcv, m); 4842b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4843f8829a4aSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 484480fefe0aSRandall Stewart } 4845139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4846f8829a4aSRandall Stewart } 4847f8829a4aSRandall Stewart } 4848f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(new_inp); 4849f8829a4aSRandall Stewart } 4850f8829a4aSRandall Stewart 4851f8829a4aSRandall Stewart void 4852b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, 4853b1deed45SMichael Tuexen struct sctp_tcb *stcb, 4854b1deed45SMichael Tuexen int so_locked 4855b1deed45SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4856b1deed45SMichael Tuexen SCTP_UNUSED 4857b1deed45SMichael Tuexen #endif 4858b1deed45SMichael Tuexen ) 485944249214SRandall Stewart { 4860b1deed45SMichael Tuexen if ((inp != NULL) && (inp->sctp_socket != NULL)) { 486144249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 486244249214SRandall Stewart struct socket *so; 486344249214SRandall Stewart 486444249214SRandall Stewart so = SCTP_INP_SO(inp); 486544249214SRandall Stewart if (!so_locked) { 486644249214SRandall Stewart if (stcb) { 486744249214SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 486844249214SRandall Stewart SCTP_TCB_UNLOCK(stcb); 486944249214SRandall Stewart } 487044249214SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 487144249214SRandall Stewart if (stcb) { 487244249214SRandall Stewart SCTP_TCB_LOCK(stcb); 487344249214SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 487444249214SRandall Stewart } 487544249214SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 487644249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 487744249214SRandall Stewart return; 487844249214SRandall Stewart } 487944249214SRandall Stewart } 488044249214SRandall Stewart #endif 488144249214SRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 488244249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 488344249214SRandall Stewart if (!so_locked) { 488444249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 488544249214SRandall Stewart } 488644249214SRandall Stewart #endif 488744249214SRandall Stewart } 488844249214SRandall Stewart } 488944249214SRandall Stewart 489044249214SRandall Stewart void 4891f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp, 4892f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4893f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4894f8829a4aSRandall Stewart struct sockbuf *sb, 4895ceaad40aSRandall Stewart int end, 4896cfde3ff7SRandall Stewart int inp_read_lock_held, 4897ceaad40aSRandall Stewart int so_locked 4898ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4899ceaad40aSRandall Stewart SCTP_UNUSED 4900ceaad40aSRandall Stewart #endif 4901ceaad40aSRandall Stewart ) 4902f8829a4aSRandall Stewart { 4903f8829a4aSRandall Stewart /* 4904f8829a4aSRandall Stewart * Here we must place the control on the end of the socket read 49054e88d37aSMichael Tuexen * queue AND increment sb_cc so that select will work properly on 4906f8829a4aSRandall Stewart * read. 4907f8829a4aSRandall Stewart */ 4908f8829a4aSRandall Stewart struct mbuf *m, *prev = NULL; 4909f8829a4aSRandall Stewart 491003b0b021SRandall Stewart if (inp == NULL) { 491103b0b021SRandall Stewart /* Gak, TSNH!! */ 4912a5d547adSRandall Stewart #ifdef INVARIANTS 491303b0b021SRandall Stewart panic("Gak, inp NULL on add_to_readq"); 491403b0b021SRandall Stewart #endif 491503b0b021SRandall Stewart return; 491603b0b021SRandall Stewart } 4917cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4918f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4919cd1386abSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 49208a3cfbffSMichael Tuexen if (!control->on_strm_q) { 4921cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4922cd1386abSMichael Tuexen if (control->data) { 4923cd1386abSMichael Tuexen sctp_m_freem(control->data); 4924cd1386abSMichael Tuexen control->data = NULL; 4925cd1386abSMichael Tuexen } 492644249214SRandall Stewart sctp_free_a_readq(stcb, control); 49278a3cfbffSMichael Tuexen } 4928cd1386abSMichael Tuexen if (inp_read_lock_held == 0) 4929cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4930cd1386abSMichael Tuexen return; 4931cd1386abSMichael Tuexen } 493242551e99SRandall Stewart if (!(control->spec_flags & M_NOTIFICATION)) { 4933a5d547adSRandall Stewart atomic_add_int(&inp->total_recvs, 1); 493442551e99SRandall Stewart if (!control->do_not_ref_stcb) { 4935a5d547adSRandall Stewart atomic_add_int(&stcb->total_recvs, 1); 493642551e99SRandall Stewart } 493742551e99SRandall Stewart } 4938f8829a4aSRandall Stewart m = control->data; 4939f8829a4aSRandall Stewart control->held_length = 0; 4940f8829a4aSRandall Stewart control->length = 0; 4941f8829a4aSRandall Stewart while (m) { 4942139bc87fSRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 4943f8829a4aSRandall Stewart /* Skip mbufs with NO length */ 4944f8829a4aSRandall Stewart if (prev == NULL) { 4945f8829a4aSRandall Stewart /* First one */ 4946f8829a4aSRandall Stewart control->data = sctp_m_free(m); 4947f8829a4aSRandall Stewart m = control->data; 4948f8829a4aSRandall Stewart } else { 4949139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 4950139bc87fSRandall Stewart m = SCTP_BUF_NEXT(prev); 4951f8829a4aSRandall Stewart } 4952f8829a4aSRandall Stewart if (m == NULL) { 4953c2ede4b3SMartin Blapp control->tail_mbuf = prev; 4954f8829a4aSRandall Stewart } 4955f8829a4aSRandall Stewart continue; 4956f8829a4aSRandall Stewart } 4957f8829a4aSRandall Stewart prev = m; 4958b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4959139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 496080fefe0aSRandall Stewart } 4961f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, m); 4962b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4963f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 496480fefe0aSRandall Stewart } 4965139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 4966139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4967f8829a4aSRandall Stewart } 4968f8829a4aSRandall Stewart if (prev != NULL) { 4969f8829a4aSRandall Stewart control->tail_mbuf = prev; 4970f8829a4aSRandall Stewart } else { 4971139bc87fSRandall Stewart /* Everything got collapsed out?? */ 49728a3cfbffSMichael Tuexen if (!control->on_strm_q) { 4973cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 497444249214SRandall Stewart sctp_free_a_readq(stcb, control); 49758a3cfbffSMichael Tuexen } 4976cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 497747a490cbSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4978f8829a4aSRandall Stewart return; 4979f8829a4aSRandall Stewart } 4980f8829a4aSRandall Stewart if (end) { 4981f8829a4aSRandall Stewart control->end_added = 1; 4982f8829a4aSRandall Stewart } 4983f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&inp->read_queue, control, next); 498444249214SRandall Stewart control->on_read_q = 1; 4985cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4986f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4987f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 4988b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(inp, stcb, so_locked); 4989f8829a4aSRandall Stewart } 4990f8829a4aSRandall Stewart } 4991f8829a4aSRandall Stewart 4992f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF 4993f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4994f8829a4aSRandall Stewart */ 4995f8829a4aSRandall Stewart 4996f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF 4997f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4998f8829a4aSRandall Stewart */ 4999f8829a4aSRandall Stewart 5000f8829a4aSRandall Stewart struct mbuf * 5001ff1ffd74SMichael Tuexen sctp_generate_cause(uint16_t code, char *info) 5002f8829a4aSRandall Stewart { 5003f8829a4aSRandall Stewart struct mbuf *m; 5004ff1ffd74SMichael Tuexen struct sctp_gen_error_cause *cause; 50059a8e3088SMichael Tuexen size_t info_len; 50069a8e3088SMichael Tuexen uint16_t len; 5007f8829a4aSRandall Stewart 5008ff1ffd74SMichael Tuexen if ((code == 0) || (info == NULL)) { 5009ff1ffd74SMichael Tuexen return (NULL); 5010ff1ffd74SMichael Tuexen } 5011ff1ffd74SMichael Tuexen info_len = strlen(info); 50129a8e3088SMichael Tuexen if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) { 50139a8e3088SMichael Tuexen return (NULL); 50149a8e3088SMichael Tuexen } 50159a8e3088SMichael Tuexen len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len); 5016ff1ffd74SMichael Tuexen m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); 5017ff1ffd74SMichael Tuexen if (m != NULL) { 5018ff1ffd74SMichael Tuexen SCTP_BUF_LEN(m) = len; 5019ff1ffd74SMichael Tuexen cause = mtod(m, struct sctp_gen_error_cause *); 5020ff1ffd74SMichael Tuexen cause->code = htons(code); 50219a8e3088SMichael Tuexen cause->length = htons(len); 5022ff1ffd74SMichael Tuexen memcpy(cause->info, info, info_len); 5023f8829a4aSRandall Stewart } 5024f8829a4aSRandall Stewart return (m); 5025f8829a4aSRandall Stewart } 5026f8829a4aSRandall Stewart 502732451da4SMichael Tuexen struct mbuf * 502832451da4SMichael Tuexen sctp_generate_no_user_data_cause(uint32_t tsn) 502932451da4SMichael Tuexen { 503032451da4SMichael Tuexen struct mbuf *m; 503132451da4SMichael Tuexen struct sctp_error_no_user_data *no_user_data_cause; 50329a8e3088SMichael Tuexen uint16_t len; 503332451da4SMichael Tuexen 50349a8e3088SMichael Tuexen len = (uint16_t)sizeof(struct sctp_error_no_user_data); 503532451da4SMichael Tuexen m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); 503632451da4SMichael Tuexen if (m != NULL) { 503732451da4SMichael Tuexen SCTP_BUF_LEN(m) = len; 503832451da4SMichael Tuexen no_user_data_cause = mtod(m, struct sctp_error_no_user_data *); 503932451da4SMichael Tuexen no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA); 50409a8e3088SMichael Tuexen no_user_data_cause->cause.length = htons(len); 50418b9c95f4SMichael Tuexen no_user_data_cause->tsn = htonl(tsn); 504232451da4SMichael Tuexen } 504332451da4SMichael Tuexen return (m); 504432451da4SMichael Tuexen } 504532451da4SMichael Tuexen 5046f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING 5047f8829a4aSRandall Stewart void 5048f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, 5049f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, int chk_cnt) 5050f8829a4aSRandall Stewart { 5051f8829a4aSRandall Stewart if (tp1->data == NULL) { 5052f8829a4aSRandall Stewart return; 5053f8829a4aSRandall Stewart } 5054f8829a4aSRandall Stewart asoc->chunks_on_out_queue -= chk_cnt; 5055b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { 5056f8829a4aSRandall Stewart sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, 5057f8829a4aSRandall Stewart asoc->total_output_queue_size, 5058f8829a4aSRandall Stewart tp1->book_size, 5059f8829a4aSRandall Stewart 0, 5060f8829a4aSRandall Stewart tp1->mbcnt); 506180fefe0aSRandall Stewart } 5062f8829a4aSRandall Stewart if (asoc->total_output_queue_size >= tp1->book_size) { 506344b7479bSRandall Stewart atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size); 5064f8829a4aSRandall Stewart } else { 5065f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 5066f8829a4aSRandall Stewart } 5067f8829a4aSRandall Stewart 5068f8829a4aSRandall Stewart if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || 5069f8829a4aSRandall Stewart ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { 50704e88d37aSMichael Tuexen if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { 50714e88d37aSMichael Tuexen stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size; 5072f8829a4aSRandall Stewart } else { 50734e88d37aSMichael Tuexen stcb->sctp_socket->so_snd.sb_cc = 0; 5074f8829a4aSRandall Stewart 5075f8829a4aSRandall Stewart } 5076f8829a4aSRandall Stewart } 5077f8829a4aSRandall Stewart } 5078f8829a4aSRandall Stewart 5079f8829a4aSRandall Stewart #endif 5080f8829a4aSRandall Stewart 5081f8829a4aSRandall Stewart int 5082f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, 50831edc9dbaSMichael Tuexen uint8_t sent, int so_locked 5084ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 5085ceaad40aSRandall Stewart SCTP_UNUSED 5086ceaad40aSRandall Stewart #endif 5087ceaad40aSRandall Stewart ) 5088f8829a4aSRandall Stewart { 50890c0982b8SRandall Stewart struct sctp_stream_out *strq; 50904a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk = NULL, *tp2; 50910c0982b8SRandall Stewart struct sctp_stream_queue_pending *sp; 509249656eefSMichael Tuexen uint32_t mid; 509349656eefSMichael Tuexen uint16_t sid; 50940c0982b8SRandall Stewart uint8_t foundeom = 0; 5095f8829a4aSRandall Stewart int ret_sz = 0; 5096f8829a4aSRandall Stewart int notdone; 50970c0982b8SRandall Stewart int do_wakeup_routine = 0; 5098f8829a4aSRandall Stewart 509949656eefSMichael Tuexen sid = tp1->rec.data.sid; 510049656eefSMichael Tuexen mid = tp1->rec.data.mid; 5101f0396ad1SMichael Tuexen if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { 5102f0396ad1SMichael Tuexen stcb->asoc.abandoned_sent[0]++; 5103f0396ad1SMichael Tuexen stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; 510449656eefSMichael Tuexen stcb->asoc.strmout[sid].abandoned_sent[0]++; 5105f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 5106ad15e154SMichael Tuexen stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; 5107f0396ad1SMichael Tuexen #endif 5108f0396ad1SMichael Tuexen } else { 5109f0396ad1SMichael Tuexen stcb->asoc.abandoned_unsent[0]++; 5110f0396ad1SMichael Tuexen stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; 511149656eefSMichael Tuexen stcb->asoc.strmout[sid].abandoned_unsent[0]++; 5112f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 5113ad15e154SMichael Tuexen stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; 5114f0396ad1SMichael Tuexen #endif 5115f0396ad1SMichael Tuexen } 5116f8829a4aSRandall Stewart do { 5117f8829a4aSRandall Stewart ret_sz += tp1->book_size; 51180c0982b8SRandall Stewart if (tp1->data != NULL) { 51198933fa13SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 5120830d754dSRandall Stewart sctp_flight_size_decrease(tp1); 5121830d754dSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 51228933fa13SRandall Stewart } 51238933fa13SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 51240c0982b8SRandall Stewart stcb->asoc.peers_rwnd += tp1->send_size; 51250c0982b8SRandall Stewart stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); 51261edc9dbaSMichael Tuexen if (sent) { 51271edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 51281edc9dbaSMichael Tuexen } else { 51291edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 51301edc9dbaSMichael Tuexen } 51312f99457bSMichael Tuexen if (tp1->data) { 5132f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 5133f8829a4aSRandall Stewart tp1->data = NULL; 51342f99457bSMichael Tuexen } 51350c0982b8SRandall Stewart do_wakeup_routine = 1; 5136f8829a4aSRandall Stewart if (PR_SCTP_BUF_ENABLED(tp1->flags)) { 5137f8829a4aSRandall Stewart stcb->asoc.sent_queue_cnt_removeable--; 5138f8829a4aSRandall Stewart } 5139f8829a4aSRandall Stewart } 51408933fa13SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 5141f8829a4aSRandall Stewart if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 5142f8829a4aSRandall Stewart SCTP_DATA_NOT_FRAG) { 5143f8829a4aSRandall Stewart /* not frag'ed we ae done */ 5144f8829a4aSRandall Stewart notdone = 0; 5145f8829a4aSRandall Stewart foundeom = 1; 5146f8829a4aSRandall Stewart } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 5147f8829a4aSRandall Stewart /* end of frag, we are done */ 5148f8829a4aSRandall Stewart notdone = 0; 5149f8829a4aSRandall Stewart foundeom = 1; 5150f8829a4aSRandall Stewart } else { 5151f8829a4aSRandall Stewart /* 5152f8829a4aSRandall Stewart * Its a begin or middle piece, we must mark all of 5153f8829a4aSRandall Stewart * it 5154f8829a4aSRandall Stewart */ 5155f8829a4aSRandall Stewart notdone = 1; 5156f8829a4aSRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next); 5157f8829a4aSRandall Stewart } 5158f8829a4aSRandall Stewart } while (tp1 && notdone); 51590c0982b8SRandall Stewart if (foundeom == 0) { 5160f8829a4aSRandall Stewart /* 5161f8829a4aSRandall Stewart * The multi-part message was scattered across the send and 5162f8829a4aSRandall Stewart * sent queue. 5163f8829a4aSRandall Stewart */ 51644a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) { 516549656eefSMichael Tuexen if ((tp1->rec.data.sid != sid) || 516649656eefSMichael Tuexen (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) { 51674a9ef3f8SMichael Tuexen break; 51684a9ef3f8SMichael Tuexen } 51690c0982b8SRandall Stewart /* 51700c0982b8SRandall Stewart * save to chk in case we have some on stream out 51710c0982b8SRandall Stewart * queue. If so and we have an un-transmitted one we 51720c0982b8SRandall Stewart * don't have to fudge the TSN. 51730c0982b8SRandall Stewart */ 51740c0982b8SRandall Stewart chk = tp1; 51750c0982b8SRandall Stewart ret_sz += tp1->book_size; 51760c0982b8SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 51771edc9dbaSMichael Tuexen if (sent) { 51781edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 51791edc9dbaSMichael Tuexen } else { 51801edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 51811edc9dbaSMichael Tuexen } 51822f99457bSMichael Tuexen if (tp1->data) { 51830c0982b8SRandall Stewart sctp_m_freem(tp1->data); 51842f99457bSMichael Tuexen tp1->data = NULL; 51852f99457bSMichael Tuexen } 51868933fa13SRandall Stewart /* No flight involved here book the size to 0 */ 51878933fa13SRandall Stewart tp1->book_size = 0; 51880c0982b8SRandall Stewart if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 51890c0982b8SRandall Stewart foundeom = 1; 5190f8829a4aSRandall Stewart } 51910c0982b8SRandall Stewart do_wakeup_routine = 1; 51920c0982b8SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 51930c0982b8SRandall Stewart TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next); 5194b7b84c0eSMichael Tuexen /* 5195b7b84c0eSMichael Tuexen * on to the sent queue so we can wait for it to be 5196b7b84c0eSMichael Tuexen * passed by. 5197b7b84c0eSMichael Tuexen */ 51980c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1, 51990c0982b8SRandall Stewart sctp_next); 52000c0982b8SRandall Stewart stcb->asoc.send_queue_cnt--; 52010c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 52020c0982b8SRandall Stewart } 52030c0982b8SRandall Stewart } 52040c0982b8SRandall Stewart if (foundeom == 0) { 52050c0982b8SRandall Stewart /* 52060c0982b8SRandall Stewart * Still no eom found. That means there is stuff left on the 52070c0982b8SRandall Stewart * stream out queue.. yuck. 52080c0982b8SRandall Stewart */ 52090c0982b8SRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 521049656eefSMichael Tuexen strq = &stcb->asoc.strmout[sid]; 5211f3b05218SMichael Tuexen sp = TAILQ_FIRST(&strq->outqueue); 5212f3b05218SMichael Tuexen if (sp != NULL) { 52130c0982b8SRandall Stewart sp->discard_rest = 1; 52140c0982b8SRandall Stewart /* 5215f3b05218SMichael Tuexen * We may need to put a chunk on the queue that 5216f3b05218SMichael Tuexen * holds the TSN that would have been sent with the 5217f3b05218SMichael Tuexen * LAST bit. 52180c0982b8SRandall Stewart */ 52190c0982b8SRandall Stewart if (chk == NULL) { 52200c0982b8SRandall Stewart /* Yep, we have to */ 52210c0982b8SRandall Stewart sctp_alloc_a_chunk(stcb, chk); 52220c0982b8SRandall Stewart if (chk == NULL) { 52230c0982b8SRandall Stewart /* 5224f3b05218SMichael Tuexen * we are hosed. All we can do is 5225f3b05218SMichael Tuexen * nothing.. which will cause an 5226f3b05218SMichael Tuexen * abort if the peer is paying 52270c0982b8SRandall Stewart * attention. 52280c0982b8SRandall Stewart */ 52290c0982b8SRandall Stewart goto oh_well; 52300c0982b8SRandall Stewart } 52310c0982b8SRandall Stewart memset(chk, 0, sizeof(*chk)); 523263d5b568SMichael Tuexen chk->rec.data.rcv_flags = 0; 52330c0982b8SRandall Stewart chk->sent = SCTP_FORWARD_TSN_SKIP; 52340c0982b8SRandall Stewart chk->asoc = &stcb->asoc; 523563d5b568SMichael Tuexen if (stcb->asoc.idata_supported == 0) { 523663d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 523749656eefSMichael Tuexen chk->rec.data.mid = 0; 523863d5b568SMichael Tuexen } else { 523949656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_ordered; 524063d5b568SMichael Tuexen } 524163d5b568SMichael Tuexen } else { 524263d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 524349656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_unordered; 524463d5b568SMichael Tuexen } else { 524549656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_ordered; 524663d5b568SMichael Tuexen } 524763d5b568SMichael Tuexen } 524849656eefSMichael Tuexen chk->rec.data.sid = sp->sid; 524949656eefSMichael Tuexen chk->rec.data.ppid = sp->ppid; 52500c0982b8SRandall Stewart chk->rec.data.context = sp->context; 52510c0982b8SRandall Stewart chk->flags = sp->act_flags; 52527fd5b436SMichael Tuexen chk->whoTo = NULL; 525349656eefSMichael Tuexen chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); 52547fd5b436SMichael Tuexen strq->chunks_on_queues++; 52550c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); 52560c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 52578933fa13SRandall Stewart stcb->asoc.pr_sctp_cnt++; 52580c0982b8SRandall Stewart } 525963d5b568SMichael Tuexen chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; 5260d1ea5fa9SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 5261d1ea5fa9SMichael Tuexen chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED; 5262d1ea5fa9SMichael Tuexen } 526363d5b568SMichael Tuexen if (stcb->asoc.idata_supported == 0) { 526463d5b568SMichael Tuexen if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) { 526563d5b568SMichael Tuexen strq->next_mid_ordered++; 526663d5b568SMichael Tuexen } 526763d5b568SMichael Tuexen } else { 526863d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 526963d5b568SMichael Tuexen strq->next_mid_unordered++; 527063d5b568SMichael Tuexen } else { 527163d5b568SMichael Tuexen strq->next_mid_ordered++; 527263d5b568SMichael Tuexen } 527363d5b568SMichael Tuexen } 52740c0982b8SRandall Stewart oh_well: 52750c0982b8SRandall Stewart if (sp->data) { 52760c0982b8SRandall Stewart /* 5277f3b05218SMichael Tuexen * Pull any data to free up the SB and allow 5278f3b05218SMichael Tuexen * sender to "add more" while we will throw 5279f3b05218SMichael Tuexen * away :-) 52800c0982b8SRandall Stewart */ 5281f3b05218SMichael Tuexen sctp_free_spbufspace(stcb, &stcb->asoc, sp); 52820c0982b8SRandall Stewart ret_sz += sp->length; 52830c0982b8SRandall Stewart do_wakeup_routine = 1; 52840c0982b8SRandall Stewart sp->some_taken = 1; 52850c0982b8SRandall Stewart sctp_m_freem(sp->data); 52860c0982b8SRandall Stewart sp->data = NULL; 52870c0982b8SRandall Stewart sp->tail_mbuf = NULL; 5288d07b2ac6SMichael Tuexen sp->length = 0; 52890c0982b8SRandall Stewart } 52900c0982b8SRandall Stewart } 52910c0982b8SRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 52920c0982b8SRandall Stewart } 52930c0982b8SRandall Stewart if (do_wakeup_routine) { 52940c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 52958933fa13SRandall Stewart struct socket *so; 52968933fa13SRandall Stewart 52970c0982b8SRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 52980c0982b8SRandall Stewart if (!so_locked) { 52990c0982b8SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 53000c0982b8SRandall Stewart SCTP_TCB_UNLOCK(stcb); 53010c0982b8SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 53020c0982b8SRandall Stewart SCTP_TCB_LOCK(stcb); 53030c0982b8SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 53040c0982b8SRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 53050c0982b8SRandall Stewart /* assoc was freed while we were unlocked */ 53060c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 53070c0982b8SRandall Stewart return (ret_sz); 53080c0982b8SRandall Stewart } 53090c0982b8SRandall Stewart } 53100c0982b8SRandall Stewart #endif 53110c0982b8SRandall Stewart sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 53120c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 53130c0982b8SRandall Stewart if (!so_locked) { 53140c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 53150c0982b8SRandall Stewart } 53160c0982b8SRandall Stewart #endif 5317f8829a4aSRandall Stewart } 5318f8829a4aSRandall Stewart return (ret_sz); 5319f8829a4aSRandall Stewart } 5320f8829a4aSRandall Stewart 5321f8829a4aSRandall Stewart /* 5322f8829a4aSRandall Stewart * checks to see if the given address, sa, is one that is currently known by 5323f8829a4aSRandall Stewart * the kernel note: can't distinguish the same address on multiple interfaces 5324f8829a4aSRandall Stewart * and doesn't handle multiple addresses with different zone/scope id's note: 5325f8829a4aSRandall Stewart * ifa_ifwithaddr() compares the entire sockaddr struct 5326f8829a4aSRandall Stewart */ 532742551e99SRandall Stewart struct sctp_ifa * 532880fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, 532980fefe0aSRandall Stewart int holds_lock) 5330f8829a4aSRandall Stewart { 533142551e99SRandall Stewart struct sctp_laddr *laddr; 5332f8829a4aSRandall Stewart 5333ad81507eSRandall Stewart if (holds_lock == 0) { 533442551e99SRandall Stewart SCTP_INP_RLOCK(inp); 5335ad81507eSRandall Stewart } 53360053ed28SMichael Tuexen 533742551e99SRandall Stewart LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 533842551e99SRandall Stewart if (laddr->ifa == NULL) 5339f8829a4aSRandall Stewart continue; 534042551e99SRandall Stewart if (addr->sa_family != laddr->ifa->address.sa.sa_family) 534142551e99SRandall Stewart continue; 5342e6194c2eSMichael Tuexen #ifdef INET 534342551e99SRandall Stewart if (addr->sa_family == AF_INET) { 534442551e99SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 534542551e99SRandall Stewart laddr->ifa->address.sin.sin_addr.s_addr) { 534642551e99SRandall Stewart /* found him. */ 5347ad81507eSRandall Stewart if (holds_lock == 0) { 534842551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5349ad81507eSRandall Stewart } 535042551e99SRandall Stewart return (laddr->ifa); 535142551e99SRandall Stewart break; 535242551e99SRandall Stewart } 53535e2c2d87SRandall Stewart } 5354e6194c2eSMichael Tuexen #endif 53555e2c2d87SRandall Stewart #ifdef INET6 53565e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 5357c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 5358c54a18d2SRandall Stewart &laddr->ifa->address.sin6)) { 535942551e99SRandall Stewart /* found him. */ 5360ad81507eSRandall Stewart if (holds_lock == 0) { 536142551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5362ad81507eSRandall Stewart } 536342551e99SRandall Stewart return (laddr->ifa); 536442551e99SRandall Stewart break; 536542551e99SRandall Stewart } 536642551e99SRandall Stewart } 53675e2c2d87SRandall Stewart #endif 536842551e99SRandall Stewart } 5369ad81507eSRandall Stewart if (holds_lock == 0) { 537042551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5371ad81507eSRandall Stewart } 537242551e99SRandall Stewart return (NULL); 537342551e99SRandall Stewart } 5374f8829a4aSRandall Stewart 53756a27c376SRandall Stewart uint32_t 5376b0471b4bSMichael Tuexen sctp_get_ifa_hash_val(struct sockaddr *addr) 5377b0471b4bSMichael Tuexen { 5378ea5eba11SMichael Tuexen switch (addr->sa_family) { 5379ea5eba11SMichael Tuexen #ifdef INET 5380ea5eba11SMichael Tuexen case AF_INET: 5381ea5eba11SMichael Tuexen { 53826a27c376SRandall Stewart struct sockaddr_in *sin; 53836a27c376SRandall Stewart 53846a27c376SRandall Stewart sin = (struct sockaddr_in *)addr; 53856a27c376SRandall Stewart return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); 5386ea5eba11SMichael Tuexen } 5387ea5eba11SMichael Tuexen #endif 5388ea5eba11SMichael Tuexen #ifdef INET6 53892c2e3218SMichael Tuexen case AF_INET6: 5390ea5eba11SMichael Tuexen { 53916a27c376SRandall Stewart struct sockaddr_in6 *sin6; 53926a27c376SRandall Stewart uint32_t hash_of_addr; 53936a27c376SRandall Stewart 53946a27c376SRandall Stewart sin6 = (struct sockaddr_in6 *)addr; 53956a27c376SRandall Stewart hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + 53966a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[1] + 53976a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[2] + 53986a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[3]); 53996a27c376SRandall Stewart hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); 54006a27c376SRandall Stewart return (hash_of_addr); 54016a27c376SRandall Stewart } 5402ea5eba11SMichael Tuexen #endif 5403ea5eba11SMichael Tuexen default: 5404ea5eba11SMichael Tuexen break; 5405ea5eba11SMichael Tuexen } 54066a27c376SRandall Stewart return (0); 54076a27c376SRandall Stewart } 54086a27c376SRandall Stewart 540942551e99SRandall Stewart struct sctp_ifa * 541042551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) 541142551e99SRandall Stewart { 541242551e99SRandall Stewart struct sctp_ifa *sctp_ifap; 541342551e99SRandall Stewart struct sctp_vrf *vrf; 54146a27c376SRandall Stewart struct sctp_ifalist *hash_head; 54156a27c376SRandall Stewart uint32_t hash_of_addr; 541642551e99SRandall Stewart 541742551e99SRandall Stewart if (holds_lock == 0) 5418c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 541942551e99SRandall Stewart 5420bff64a4dSRandall Stewart vrf = sctp_find_vrf(vrf_id); 5421bff64a4dSRandall Stewart if (vrf == NULL) { 5422bff64a4dSRandall Stewart if (holds_lock == 0) 5423c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5424bff64a4dSRandall Stewart return (NULL); 5425bff64a4dSRandall Stewart } 54260053ed28SMichael Tuexen 5427bff64a4dSRandall Stewart hash_of_addr = sctp_get_ifa_hash_val(addr); 5428bff64a4dSRandall Stewart 542917205eccSRandall Stewart hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; 5430bff64a4dSRandall Stewart if (hash_head == NULL) { 5431ad81507eSRandall Stewart SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ", 5432c99efcf6SRandall Stewart hash_of_addr, (uint32_t)vrf->vrf_addr_hashmark, 5433c99efcf6SRandall Stewart (uint32_t)(hash_of_addr & vrf->vrf_addr_hashmark)); 5434bff64a4dSRandall Stewart sctp_print_address(addr); 5435ad81507eSRandall Stewart SCTP_PRINTF("No such bucket for address\n"); 5436bff64a4dSRandall Stewart if (holds_lock == 0) 5437c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5438bff64a4dSRandall Stewart 5439bff64a4dSRandall Stewart return (NULL); 5440bff64a4dSRandall Stewart } 54416a27c376SRandall Stewart LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { 54426a27c376SRandall Stewart if (addr->sa_family != sctp_ifap->address.sa.sa_family) 54436a27c376SRandall Stewart continue; 5444e6194c2eSMichael Tuexen #ifdef INET 54456a27c376SRandall Stewart if (addr->sa_family == AF_INET) { 54466a27c376SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 54476a27c376SRandall Stewart sctp_ifap->address.sin.sin_addr.s_addr) { 54486a27c376SRandall Stewart /* found him. */ 544942551e99SRandall Stewart if (holds_lock == 0) 5450c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 545142551e99SRandall Stewart return (sctp_ifap); 54526a27c376SRandall Stewart break; 54536a27c376SRandall Stewart } 54545e2c2d87SRandall Stewart } 5455e6194c2eSMichael Tuexen #endif 54565e2c2d87SRandall Stewart #ifdef INET6 54575e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 5458c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 5459c54a18d2SRandall Stewart &sctp_ifap->address.sin6)) { 54606a27c376SRandall Stewart /* found him. */ 54616a27c376SRandall Stewart if (holds_lock == 0) 5462c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 54636a27c376SRandall Stewart return (sctp_ifap); 54646a27c376SRandall Stewart break; 54656a27c376SRandall Stewart } 546642551e99SRandall Stewart } 54675e2c2d87SRandall Stewart #endif 546842551e99SRandall Stewart } 546942551e99SRandall Stewart if (holds_lock == 0) 5470c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5471f8829a4aSRandall Stewart return (NULL); 5472f8829a4aSRandall Stewart } 5473f8829a4aSRandall Stewart 5474f8829a4aSRandall Stewart static void 54754c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock, 5476f8829a4aSRandall Stewart uint32_t rwnd_req) 5477f8829a4aSRandall Stewart { 5478f8829a4aSRandall Stewart /* User pulled some data, do we need a rwnd update? */ 5479868b51f2SMichael Tuexen struct epoch_tracker et; 5480f8829a4aSRandall Stewart int r_unlocked = 0; 5481f8829a4aSRandall Stewart uint32_t dif, rwnd; 5482f8829a4aSRandall Stewart struct socket *so = NULL; 5483f8829a4aSRandall Stewart 5484f8829a4aSRandall Stewart if (stcb == NULL) 5485f8829a4aSRandall Stewart return; 5486f8829a4aSRandall Stewart 548750cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5488f8829a4aSRandall Stewart 5489839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || 549061a21880SMichael Tuexen (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | SCTP_STATE_SHUTDOWN_RECEIVED))) { 5491f8829a4aSRandall Stewart /* Pre-check If we are freeing no update */ 5492f8829a4aSRandall Stewart goto no_lock; 5493f8829a4aSRandall Stewart } 5494f8829a4aSRandall Stewart SCTP_INP_INCR_REF(stcb->sctp_ep); 5495f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5496f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5497f8829a4aSRandall Stewart goto out; 5498f8829a4aSRandall Stewart } 5499f8829a4aSRandall Stewart so = stcb->sctp_socket; 5500f8829a4aSRandall Stewart if (so == NULL) { 5501f8829a4aSRandall Stewart goto out; 5502f8829a4aSRandall Stewart } 5503f8829a4aSRandall Stewart atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); 5504f8829a4aSRandall Stewart /* Have you have freed enough to look */ 5505f8829a4aSRandall Stewart *freed_so_far = 0; 5506f8829a4aSRandall Stewart /* Yep, its worth a look and the lock overhead */ 5507f8829a4aSRandall Stewart 5508f8829a4aSRandall Stewart /* Figure out what the rwnd would be */ 5509f8829a4aSRandall Stewart rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); 5510f8829a4aSRandall Stewart if (rwnd >= stcb->asoc.my_last_reported_rwnd) { 5511f8829a4aSRandall Stewart dif = rwnd - stcb->asoc.my_last_reported_rwnd; 5512f8829a4aSRandall Stewart } else { 5513f8829a4aSRandall Stewart dif = 0; 5514f8829a4aSRandall Stewart } 5515f8829a4aSRandall Stewart if (dif >= rwnd_req) { 5516f8829a4aSRandall Stewart if (hold_rlock) { 5517f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 5518f8829a4aSRandall Stewart r_unlocked = 1; 5519f8829a4aSRandall Stewart } 5520f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5521f8829a4aSRandall Stewart /* 5522f8829a4aSRandall Stewart * One last check before we allow the guy possibly 5523f8829a4aSRandall Stewart * to get in. There is a race, where the guy has not 5524f8829a4aSRandall Stewart * reached the gate. In that case 5525f8829a4aSRandall Stewart */ 5526f8829a4aSRandall Stewart goto out; 5527f8829a4aSRandall Stewart } 5528f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 5529f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5530f8829a4aSRandall Stewart /* No reports here */ 5531f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5532f8829a4aSRandall Stewart goto out; 5533f8829a4aSRandall Stewart } 5534f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_wu_sacks_sent); 5535868b51f2SMichael Tuexen NET_EPOCH_ENTER(et); 5536689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_LOCKED); 5537830d754dSRandall Stewart 5538f8829a4aSRandall Stewart sctp_chunk_output(stcb->sctp_ep, stcb, 5539ceaad40aSRandall Stewart SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); 5540f8829a4aSRandall Stewart /* make sure no timer is running */ 5541868b51f2SMichael Tuexen NET_EPOCH_EXIT(et); 5542ba785902SMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, 5543ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_6); 5544f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5545f8829a4aSRandall Stewart } else { 5546f8829a4aSRandall Stewart /* Update how much we have pending */ 5547f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = dif; 5548f8829a4aSRandall Stewart } 5549f8829a4aSRandall Stewart out: 5550f8829a4aSRandall Stewart if (so && r_unlocked && hold_rlock) { 5551f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 5552f8829a4aSRandall Stewart } 55530053ed28SMichael Tuexen 5554f8829a4aSRandall Stewart SCTP_INP_DECR_REF(stcb->sctp_ep); 5555f8829a4aSRandall Stewart no_lock: 555650cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 5557f8829a4aSRandall Stewart return; 5558f8829a4aSRandall Stewart } 5559f8829a4aSRandall Stewart 5560f8829a4aSRandall Stewart int 5561f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so, 5562f8829a4aSRandall Stewart struct uio *uio, 5563f8829a4aSRandall Stewart struct mbuf **mp, 5564f8829a4aSRandall Stewart struct sockaddr *from, 5565f8829a4aSRandall Stewart int fromlen, 5566f8829a4aSRandall Stewart int *msg_flags, 5567f8829a4aSRandall Stewart struct sctp_sndrcvinfo *sinfo, 5568f8829a4aSRandall Stewart int filling_sinfo) 5569f8829a4aSRandall Stewart { 5570f8829a4aSRandall Stewart /* 5571f8829a4aSRandall Stewart * MSG flags we will look at MSG_DONTWAIT - non-blocking IO. 5572f8829a4aSRandall Stewart * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy 5573f8829a4aSRandall Stewart * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ?? 5574f8829a4aSRandall Stewart * On the way out we may send out any combination of: 5575f8829a4aSRandall Stewart * MSG_NOTIFICATION MSG_EOR 5576f8829a4aSRandall Stewart * 5577f8829a4aSRandall Stewart */ 5578f8829a4aSRandall Stewart struct sctp_inpcb *inp = NULL; 557958e6eeefSMichael Tuexen ssize_t my_len = 0; 558058e6eeefSMichael Tuexen ssize_t cp_len = 0; 55810d3cf13dSMichael Tuexen int error = 0; 5582f8829a4aSRandall Stewart struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; 558394b0d969SMichael Tuexen struct mbuf *m = NULL; 5584f8829a4aSRandall Stewart struct sctp_tcb *stcb = NULL; 5585f8829a4aSRandall Stewart int wakeup_read_socket = 0; 5586f8829a4aSRandall Stewart int freecnt_applied = 0; 5587f8829a4aSRandall Stewart int out_flags = 0, in_flags = 0; 5588f8829a4aSRandall Stewart int block_allowed = 1; 55894c9179adSRandall Stewart uint32_t freed_so_far = 0; 559058e6eeefSMichael Tuexen ssize_t copied_so_far = 0; 559193164cf9SRandall Stewart int in_eeor_mode = 0; 5592f8829a4aSRandall Stewart int no_rcv_needed = 0; 5593f8829a4aSRandall Stewart uint32_t rwnd_req = 0; 5594f8829a4aSRandall Stewart int hold_sblock = 0; 5595f8829a4aSRandall Stewart int hold_rlock = 0; 55969a8e3088SMichael Tuexen ssize_t slen = 0; 55974c9179adSRandall Stewart uint32_t held_length = 0; 55987abab911SRobert Watson int sockbuf_lock = 0; 5599f8829a4aSRandall Stewart 560017205eccSRandall Stewart if (uio == NULL) { 5601c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 560217205eccSRandall Stewart return (EINVAL); 560317205eccSRandall Stewart } 56040053ed28SMichael Tuexen 5605f8829a4aSRandall Stewart if (msg_flags) { 5606f8829a4aSRandall Stewart in_flags = *msg_flags; 5607c105859eSRandall Stewart if (in_flags & MSG_PEEK) 5608c105859eSRandall Stewart SCTP_STAT_INCR(sctps_read_peeks); 5609f8829a4aSRandall Stewart } else { 5610f8829a4aSRandall Stewart in_flags = 0; 5611f8829a4aSRandall Stewart } 5612f8829a4aSRandall Stewart slen = uio->uio_resid; 561317205eccSRandall Stewart 5614f8829a4aSRandall Stewart /* Pull in and set up our int flags */ 5615f8829a4aSRandall Stewart if (in_flags & MSG_OOB) { 5616f8829a4aSRandall Stewart /* Out of band's NOT supported */ 5617f8829a4aSRandall Stewart return (EOPNOTSUPP); 5618f8829a4aSRandall Stewart } 5619f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) && (mp != NULL)) { 5620c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 5621f8829a4aSRandall Stewart return (EINVAL); 5622f8829a4aSRandall Stewart } 5623f8829a4aSRandall Stewart if ((in_flags & (MSG_DONTWAIT 5624f8829a4aSRandall Stewart | MSG_NBIO 5625f8829a4aSRandall Stewart )) || 562642551e99SRandall Stewart SCTP_SO_IS_NBIO(so)) { 5627f8829a4aSRandall Stewart block_allowed = 0; 5628f8829a4aSRandall Stewart } 5629f8829a4aSRandall Stewart /* setup the endpoint */ 5630f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 5631f8829a4aSRandall Stewart if (inp == NULL) { 5632c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 5633f8829a4aSRandall Stewart return (EFAULT); 5634f8829a4aSRandall Stewart } 563562c1ff9cSRandall Stewart rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); 5636f8829a4aSRandall Stewart /* Must be at least a MTU's worth */ 5637f8829a4aSRandall Stewart if (rwnd_req < SCTP_MIN_RWND) 5638f8829a4aSRandall Stewart rwnd_req = SCTP_MIN_RWND; 5639f8829a4aSRandall Stewart in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 5640b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5641f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTER, 56429a8e3088SMichael Tuexen rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); 564380fefe0aSRandall Stewart } 5644b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5645f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTERPL, 56469a8e3088SMichael Tuexen rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); 564780fefe0aSRandall Stewart } 56480053ed28SMichael Tuexen 56490053ed28SMichael Tuexen 5650265de5bbSRobert Watson error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); 5651f8829a4aSRandall Stewart if (error) { 5652f8829a4aSRandall Stewart goto release_unlocked; 5653f8829a4aSRandall Stewart } 56548e1e6e5fSMateusz Guzik sockbuf_lock = 1; 5655f8829a4aSRandall Stewart restart: 56567abab911SRobert Watson 5657f8829a4aSRandall Stewart 5658f8829a4aSRandall Stewart restart_nosblocks: 5659f8829a4aSRandall Stewart if (hold_sblock == 0) { 5660f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5661f8829a4aSRandall Stewart hold_sblock = 1; 5662f8829a4aSRandall Stewart } 5663f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5664f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5665f8829a4aSRandall Stewart goto out; 5666f8829a4aSRandall Stewart } 56674e88d37aSMichael Tuexen if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) { 5668f8829a4aSRandall Stewart if (so->so_error) { 5669f8829a4aSRandall Stewart error = so->so_error; 567044b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 567144b7479bSRandall Stewart so->so_error = 0; 56729f22f500SRandall Stewart goto out; 5673f8829a4aSRandall Stewart } else { 56744e88d37aSMichael Tuexen if (so->so_rcv.sb_cc == 0) { 56757924093fSRandall Stewart /* indicate EOF */ 56767924093fSRandall Stewart error = 0; 5677f8829a4aSRandall Stewart goto out; 5678f8829a4aSRandall Stewart } 56799f22f500SRandall Stewart } 56809f22f500SRandall Stewart } 56819de217ceSMichael Tuexen if (so->so_rcv.sb_cc <= held_length) { 56829de217ceSMichael Tuexen if (so->so_error) { 56839de217ceSMichael Tuexen error = so->so_error; 56849de217ceSMichael Tuexen if ((in_flags & MSG_PEEK) == 0) { 56859de217ceSMichael Tuexen so->so_error = 0; 56869de217ceSMichael Tuexen } 56879de217ceSMichael Tuexen goto out; 56889de217ceSMichael Tuexen } 56894e88d37aSMichael Tuexen if ((so->so_rcv.sb_cc == 0) && 5690f8829a4aSRandall Stewart ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5691f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 5692f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 5693f8829a4aSRandall Stewart /* 5694f8829a4aSRandall Stewart * For active open side clear flags for 5695f8829a4aSRandall Stewart * re-use passive open is blocked by 5696f8829a4aSRandall Stewart * connect. 5697f8829a4aSRandall Stewart */ 5698f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 5699b7b84c0eSMichael Tuexen /* 5700b7b84c0eSMichael Tuexen * You were aborted, passive side 5701b7b84c0eSMichael Tuexen * always hits here 5702b7b84c0eSMichael Tuexen */ 5703c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 5704f8829a4aSRandall Stewart error = ECONNRESET; 5705f8829a4aSRandall Stewart } 5706f8829a4aSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 5707f8829a4aSRandall Stewart SS_ISDISCONNECTING | 5708f8829a4aSRandall Stewart SS_ISCONFIRMING | 5709f8829a4aSRandall Stewart SS_ISCONNECTED); 5710f8829a4aSRandall Stewart if (error == 0) { 5711f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5712c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 5713f8829a4aSRandall Stewart error = ENOTCONN; 5714f8829a4aSRandall Stewart } 5715f8829a4aSRandall Stewart } 5716f8829a4aSRandall Stewart goto out; 5717f8829a4aSRandall Stewart } 5718f8829a4aSRandall Stewart } 57199de217ceSMichael Tuexen if (block_allowed) { 5720f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5721f8829a4aSRandall Stewart if (error) { 5722f8829a4aSRandall Stewart goto out; 5723f8829a4aSRandall Stewart } 5724f8829a4aSRandall Stewart held_length = 0; 5725f8829a4aSRandall Stewart goto restart_nosblocks; 572644b7479bSRandall Stewart } else { 5727c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); 5728f8829a4aSRandall Stewart error = EWOULDBLOCK; 5729f8829a4aSRandall Stewart goto out; 5730f8829a4aSRandall Stewart } 57319de217ceSMichael Tuexen } 5732d06c82f1SRandall Stewart if (hold_sblock == 1) { 5733d06c82f1SRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5734d06c82f1SRandall Stewart hold_sblock = 0; 5735d06c82f1SRandall Stewart } 5736f8829a4aSRandall Stewart /* we possibly have data we can read */ 57373c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 5738f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5739f8829a4aSRandall Stewart if (control == NULL) { 5740f8829a4aSRandall Stewart /* 5741f8829a4aSRandall Stewart * This could be happening since the appender did the 5742f8829a4aSRandall Stewart * increment but as not yet did the tailq insert onto the 5743f8829a4aSRandall Stewart * read_queue 5744f8829a4aSRandall Stewart */ 5745f8829a4aSRandall Stewart if (hold_rlock == 0) { 5746f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5747f8829a4aSRandall Stewart } 5748f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 57494e88d37aSMichael Tuexen if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { 5750a5d547adSRandall Stewart #ifdef INVARIANTS 5751f8829a4aSRandall Stewart panic("Huh, its non zero and nothing on control?"); 5752f8829a4aSRandall Stewart #endif 57534e88d37aSMichael Tuexen so->so_rcv.sb_cc = 0; 5754f8829a4aSRandall Stewart } 5755f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5756f8829a4aSRandall Stewart hold_rlock = 0; 5757f8829a4aSRandall Stewart goto restart; 5758f8829a4aSRandall Stewart } 57590053ed28SMichael Tuexen 5760f8829a4aSRandall Stewart if ((control->length == 0) && 5761f8829a4aSRandall Stewart (control->do_not_ref_stcb)) { 5762f8829a4aSRandall Stewart /* 5763f8829a4aSRandall Stewart * Clean up code for freeing assoc that left behind a 5764f8829a4aSRandall Stewart * pdapi.. maybe a peer in EEOR that just closed after 5765f8829a4aSRandall Stewart * sending and never indicated a EOR. 5766f8829a4aSRandall Stewart */ 5767f8829a4aSRandall Stewart if (hold_rlock == 0) { 5768f8829a4aSRandall Stewart hold_rlock = 1; 5769f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5770f8829a4aSRandall Stewart } 5771f8829a4aSRandall Stewart control->held_length = 0; 5772f8829a4aSRandall Stewart if (control->data) { 5773f8829a4aSRandall Stewart /* Hmm there is data here .. fix */ 57744c9179adSRandall Stewart struct mbuf *m_tmp; 5775f8829a4aSRandall Stewart int cnt = 0; 5776f8829a4aSRandall Stewart 57774c9179adSRandall Stewart m_tmp = control->data; 57784c9179adSRandall Stewart while (m_tmp) { 57794c9179adSRandall Stewart cnt += SCTP_BUF_LEN(m_tmp); 57804c9179adSRandall Stewart if (SCTP_BUF_NEXT(m_tmp) == NULL) { 57814c9179adSRandall Stewart control->tail_mbuf = m_tmp; 5782f8829a4aSRandall Stewart control->end_added = 1; 5783f8829a4aSRandall Stewart } 57844c9179adSRandall Stewart m_tmp = SCTP_BUF_NEXT(m_tmp); 5785f8829a4aSRandall Stewart } 5786f8829a4aSRandall Stewart control->length = cnt; 5787f8829a4aSRandall Stewart } else { 5788f8829a4aSRandall Stewart /* remove it */ 5789f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5790f8829a4aSRandall Stewart /* Add back any hiddend data */ 5791f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5792f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5793f8829a4aSRandall Stewart } 5794f8829a4aSRandall Stewart if (hold_rlock) { 5795f8829a4aSRandall Stewart hold_rlock = 0; 5796f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5797f8829a4aSRandall Stewart } 5798f8829a4aSRandall Stewart goto restart; 5799f8829a4aSRandall Stewart } 5800810ec536SMichael Tuexen if ((control->length == 0) && 5801810ec536SMichael Tuexen (control->end_added == 1)) { 5802b7b84c0eSMichael Tuexen /* 5803b7b84c0eSMichael Tuexen * Do we also need to check for (control->pdapi_aborted == 5804b7b84c0eSMichael Tuexen * 1)? 5805b7b84c0eSMichael Tuexen */ 5806810ec536SMichael Tuexen if (hold_rlock == 0) { 5807810ec536SMichael Tuexen hold_rlock = 1; 5808810ec536SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5809810ec536SMichael Tuexen } 5810810ec536SMichael Tuexen TAILQ_REMOVE(&inp->read_queue, control, next); 5811810ec536SMichael Tuexen if (control->data) { 5812810ec536SMichael Tuexen #ifdef INVARIANTS 5813810ec536SMichael Tuexen panic("control->data not null but control->length == 0"); 5814810ec536SMichael Tuexen #else 5815810ec536SMichael Tuexen SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n"); 5816810ec536SMichael Tuexen sctp_m_freem(control->data); 5817810ec536SMichael Tuexen control->data = NULL; 5818810ec536SMichael Tuexen #endif 5819810ec536SMichael Tuexen } 5820810ec536SMichael Tuexen if (control->aux_data) { 5821810ec536SMichael Tuexen sctp_m_free(control->aux_data); 5822810ec536SMichael Tuexen control->aux_data = NULL; 5823810ec536SMichael Tuexen } 582498d5fd97SMichael Tuexen #ifdef INVARIANTS 582544249214SRandall Stewart if (control->on_strm_q) { 582644249214SRandall Stewart panic("About to free ctl:%p so:%p and its in %d", 582744249214SRandall Stewart control, so, control->on_strm_q); 582844249214SRandall Stewart } 582998d5fd97SMichael Tuexen #endif 5830810ec536SMichael Tuexen sctp_free_remote_addr(control->whoFrom); 5831810ec536SMichael Tuexen sctp_free_a_readq(stcb, control); 5832810ec536SMichael Tuexen if (hold_rlock) { 5833810ec536SMichael Tuexen hold_rlock = 0; 5834810ec536SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 5835810ec536SMichael Tuexen } 5836810ec536SMichael Tuexen goto restart; 5837810ec536SMichael Tuexen } 5838f8829a4aSRandall Stewart if (control->length == 0) { 5839f8829a4aSRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && 5840f8829a4aSRandall Stewart (filling_sinfo)) { 5841f8829a4aSRandall Stewart /* find a more suitable one then this */ 5842f8829a4aSRandall Stewart ctl = TAILQ_NEXT(control, next); 5843f8829a4aSRandall Stewart while (ctl) { 58449a6142d8SRandall Stewart if ((ctl->stcb != control->stcb) && (ctl->length) && 58459a6142d8SRandall Stewart (ctl->some_taken || 58466114cd96SRandall Stewart (ctl->spec_flags & M_NOTIFICATION) || 58479a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 58489a6142d8SRandall Stewart (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) 58499a6142d8SRandall Stewart ) { 58509a6142d8SRandall Stewart /*- 58519a6142d8SRandall Stewart * If we have a different TCB next, and there is data 58529a6142d8SRandall Stewart * present. If we have already taken some (pdapi), OR we can 58539a6142d8SRandall Stewart * ref the tcb and no delivery as started on this stream, we 585417205eccSRandall Stewart * take it. Note we allow a notification on a different 585517205eccSRandall Stewart * assoc to be delivered.. 58569a6142d8SRandall Stewart */ 58579a6142d8SRandall Stewart control = ctl; 58589a6142d8SRandall Stewart goto found_one; 58599a6142d8SRandall Stewart } else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) && 58609a6142d8SRandall Stewart (ctl->length) && 58619a6142d8SRandall Stewart ((ctl->some_taken) || 58629a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 586317205eccSRandall Stewart ((ctl->spec_flags & M_NOTIFICATION) == 0) && 5864b5c16493SMichael Tuexen (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) { 58659a6142d8SRandall Stewart /*- 58669a6142d8SRandall Stewart * If we have the same tcb, and there is data present, and we 58679a6142d8SRandall Stewart * have the strm interleave feature present. Then if we have 58689a6142d8SRandall Stewart * taken some (pdapi) or we can refer to tht tcb AND we have 58699a6142d8SRandall Stewart * not started a delivery for this stream, we can take it. 587017205eccSRandall Stewart * Note we do NOT allow a notificaiton on the same assoc to 587117205eccSRandall Stewart * be delivered. 58729a6142d8SRandall Stewart */ 5873f8829a4aSRandall Stewart control = ctl; 5874f8829a4aSRandall Stewart goto found_one; 5875f8829a4aSRandall Stewart } 5876f8829a4aSRandall Stewart ctl = TAILQ_NEXT(ctl, next); 5877f8829a4aSRandall Stewart } 5878f8829a4aSRandall Stewart } 5879f8829a4aSRandall Stewart /* 5880f8829a4aSRandall Stewart * if we reach here, not suitable replacement is available 58814e88d37aSMichael Tuexen * <or> fragment interleave is NOT on. So stuff the sb_cc 5882f8829a4aSRandall Stewart * into the our held count, and its time to sleep again. 5883f8829a4aSRandall Stewart */ 58844e88d37aSMichael Tuexen held_length = so->so_rcv.sb_cc; 58854e88d37aSMichael Tuexen control->held_length = so->so_rcv.sb_cc; 5886f8829a4aSRandall Stewart goto restart; 5887f8829a4aSRandall Stewart } 5888f8829a4aSRandall Stewart /* Clear the held length since there is something to read */ 5889f8829a4aSRandall Stewart control->held_length = 0; 5890f8829a4aSRandall Stewart found_one: 5891f8829a4aSRandall Stewart /* 5892f8829a4aSRandall Stewart * If we reach here, control has a some data for us to read off. 5893f8829a4aSRandall Stewart * Note that stcb COULD be NULL. 5894f8829a4aSRandall Stewart */ 58959c5ca6f2SMichael Tuexen if (hold_rlock == 0) { 58969c5ca6f2SMichael Tuexen hold_rlock = 1; 58979c5ca6f2SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5898f8829a4aSRandall Stewart } 58999c5ca6f2SMichael Tuexen control->some_taken++; 5900f8829a4aSRandall Stewart stcb = control->stcb; 5901f8829a4aSRandall Stewart if (stcb) { 59020696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 59030696e120SRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { 590450cec919SRandall Stewart if (freecnt_applied == 0) 5905f8829a4aSRandall Stewart stcb = NULL; 5906f8829a4aSRandall Stewart } else if (control->do_not_ref_stcb == 0) { 5907f8829a4aSRandall Stewart /* you can't free it on me please */ 5908f8829a4aSRandall Stewart /* 5909f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the 5910f8829a4aSRandall Stewart * free code will stop. But since we used the 5911f8829a4aSRandall Stewart * socketbuf lock and the sender uses the tcb_lock 5912f8829a4aSRandall Stewart * to increment, we need to use the atomic add to 5913f8829a4aSRandall Stewart * the refcnt 5914f8829a4aSRandall Stewart */ 5915d55b0b1bSRandall Stewart if (freecnt_applied) { 5916d55b0b1bSRandall Stewart #ifdef INVARIANTS 5917207304d4SRandall Stewart panic("refcnt already incremented"); 5918d55b0b1bSRandall Stewart #else 5919cd3fd531SMichael Tuexen SCTP_PRINTF("refcnt already incremented?\n"); 5920d55b0b1bSRandall Stewart #endif 5921d55b0b1bSRandall Stewart } else { 592250cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5923f8829a4aSRandall Stewart freecnt_applied = 1; 5924d55b0b1bSRandall Stewart } 5925f8829a4aSRandall Stewart /* 5926f8829a4aSRandall Stewart * Setup to remember how much we have not yet told 5927f8829a4aSRandall Stewart * the peer our rwnd has opened up. Note we grab the 5928f8829a4aSRandall Stewart * value from the tcb from last time. Note too that 59290696e120SRandall Stewart * sack sending clears this when a sack is sent, 5930f8829a4aSRandall Stewart * which is fine. Once we hit the rwnd_req, we then 5931f8829a4aSRandall Stewart * will go to the sctp_user_rcvd() that will not 5932f8829a4aSRandall Stewart * lock until it KNOWs it MUST send a WUP-SACK. 5933f8829a4aSRandall Stewart */ 593458e6eeefSMichael Tuexen freed_so_far = (uint32_t)stcb->freed_by_sorcv_sincelast; 5935f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = 0; 5936f8829a4aSRandall Stewart } 5937f8829a4aSRandall Stewart } 59386114cd96SRandall Stewart if (stcb && 59396114cd96SRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0) && 59406114cd96SRandall Stewart control->do_not_ref_stcb == 0) { 5941d06c82f1SRandall Stewart stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; 5942d06c82f1SRandall Stewart } 59430053ed28SMichael Tuexen 5944f8829a4aSRandall Stewart /* First lets get off the sinfo and sockaddr info */ 59455f05199cSMichael Tuexen if ((sinfo != NULL) && (filling_sinfo != 0)) { 59465f05199cSMichael Tuexen sinfo->sinfo_stream = control->sinfo_stream; 594749656eefSMichael Tuexen sinfo->sinfo_ssn = (uint16_t)control->mid; 59485f05199cSMichael Tuexen sinfo->sinfo_flags = control->sinfo_flags; 59495f05199cSMichael Tuexen sinfo->sinfo_ppid = control->sinfo_ppid; 59505f05199cSMichael Tuexen sinfo->sinfo_context = control->sinfo_context; 59515f05199cSMichael Tuexen sinfo->sinfo_timetolive = control->sinfo_timetolive; 59525f05199cSMichael Tuexen sinfo->sinfo_tsn = control->sinfo_tsn; 59535f05199cSMichael Tuexen sinfo->sinfo_cumtsn = control->sinfo_cumtsn; 59545f05199cSMichael Tuexen sinfo->sinfo_assoc_id = control->sinfo_assoc_id; 5955f8829a4aSRandall Stewart nxt = TAILQ_NEXT(control, next); 5956e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 5957e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { 5958f8829a4aSRandall Stewart struct sctp_extrcvinfo *s_extra; 5959f8829a4aSRandall Stewart 5960f8829a4aSRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 59619a6142d8SRandall Stewart if ((nxt) && 59629a6142d8SRandall Stewart (nxt->length)) { 5963b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL; 5964f8829a4aSRandall Stewart if (nxt->sinfo_flags & SCTP_UNORDERED) { 5965b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED; 5966f8829a4aSRandall Stewart } 5967f42a358aSRandall Stewart if (nxt->spec_flags & M_NOTIFICATION) { 5968b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION; 5969f42a358aSRandall Stewart } 5970b70b526dSMichael Tuexen s_extra->serinfo_next_aid = nxt->sinfo_assoc_id; 5971b70b526dSMichael Tuexen s_extra->serinfo_next_length = nxt->length; 5972b70b526dSMichael Tuexen s_extra->serinfo_next_ppid = nxt->sinfo_ppid; 5973b70b526dSMichael Tuexen s_extra->serinfo_next_stream = nxt->sinfo_stream; 5974f8829a4aSRandall Stewart if (nxt->tail_mbuf != NULL) { 5975139bc87fSRandall Stewart if (nxt->end_added) { 5976b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE; 5977f8829a4aSRandall Stewart } 5978f8829a4aSRandall Stewart } 5979f8829a4aSRandall Stewart } else { 5980f8829a4aSRandall Stewart /* 5981f8829a4aSRandall Stewart * we explicitly 0 this, since the memcpy 5982f8829a4aSRandall Stewart * got some other things beyond the older 5983f8829a4aSRandall Stewart * sinfo_ that is on the control's structure 5984f8829a4aSRandall Stewart * :-D 5985f8829a4aSRandall Stewart */ 59869a6142d8SRandall Stewart nxt = NULL; 5987b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; 5988b70b526dSMichael Tuexen s_extra->serinfo_next_aid = 0; 5989b70b526dSMichael Tuexen s_extra->serinfo_next_length = 0; 5990b70b526dSMichael Tuexen s_extra->serinfo_next_ppid = 0; 5991b70b526dSMichael Tuexen s_extra->serinfo_next_stream = 0; 5992f8829a4aSRandall Stewart } 5993f8829a4aSRandall Stewart } 5994f8829a4aSRandall Stewart /* 5995f8829a4aSRandall Stewart * update off the real current cum-ack, if we have an stcb. 5996f8829a4aSRandall Stewart */ 59970696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb) 5998f8829a4aSRandall Stewart sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 5999f8829a4aSRandall Stewart /* 6000f8829a4aSRandall Stewart * mask off the high bits, we keep the actual chunk bits in 6001f8829a4aSRandall Stewart * there. 6002f8829a4aSRandall Stewart */ 6003f8829a4aSRandall Stewart sinfo->sinfo_flags &= 0x00ff; 60045f26a41dSRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { 60055f26a41dSRandall Stewart sinfo->sinfo_flags |= SCTP_UNORDERED; 60065f26a41dSRandall Stewart } 6007f8829a4aSRandall Stewart } 600818e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 600918e198d3SRandall Stewart { 601018e198d3SRandall Stewart int index, newindex; 601118e198d3SRandall Stewart struct sctp_pcbtsn_rlog *entry; 601218e198d3SRandall Stewart 601318e198d3SRandall Stewart do { 601418e198d3SRandall Stewart index = inp->readlog_index; 601518e198d3SRandall Stewart newindex = index + 1; 601618e198d3SRandall Stewart if (newindex >= SCTP_READ_LOG_SIZE) { 601718e198d3SRandall Stewart newindex = 0; 601818e198d3SRandall Stewart } 601918e198d3SRandall Stewart } while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0); 602018e198d3SRandall Stewart entry = &inp->readlog[index]; 602118e198d3SRandall Stewart entry->vtag = control->sinfo_assoc_id; 602218e198d3SRandall Stewart entry->strm = control->sinfo_stream; 602349656eefSMichael Tuexen entry->seq = (uint16_t)control->mid; 602418e198d3SRandall Stewart entry->sz = control->length; 602518e198d3SRandall Stewart entry->flgs = control->sinfo_flags; 602618e198d3SRandall Stewart } 602718e198d3SRandall Stewart #endif 6028d59107f7SMichael Tuexen if ((fromlen > 0) && (from != NULL)) { 6029d59107f7SMichael Tuexen union sctp_sockstore store; 6030d59107f7SMichael Tuexen size_t len; 6031d59107f7SMichael Tuexen 6032b5b6e5c2SMichael Tuexen switch (control->whoFrom->ro._l_addr.sa.sa_family) { 6033b5b6e5c2SMichael Tuexen #ifdef INET6 6034b5b6e5c2SMichael Tuexen case AF_INET6: 6035d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in6); 6036d59107f7SMichael Tuexen store.sin6 = control->whoFrom->ro._l_addr.sin6; 6037d59107f7SMichael Tuexen store.sin6.sin6_port = control->port_from; 6038b5b6e5c2SMichael Tuexen break; 6039f8829a4aSRandall Stewart #endif 6040b5b6e5c2SMichael Tuexen #ifdef INET 6041b5b6e5c2SMichael Tuexen case AF_INET: 6042d59107f7SMichael Tuexen #ifdef INET6 6043d59107f7SMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 6044d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in6); 6045d59107f7SMichael Tuexen in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin, 6046d59107f7SMichael Tuexen &store.sin6); 6047d59107f7SMichael Tuexen store.sin6.sin6_port = control->port_from; 6048d59107f7SMichael Tuexen } else { 6049d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in); 6050d59107f7SMichael Tuexen store.sin = control->whoFrom->ro._l_addr.sin; 6051d59107f7SMichael Tuexen store.sin.sin_port = control->port_from; 6052d59107f7SMichael Tuexen } 6053d59107f7SMichael Tuexen #else 6054d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in); 6055d59107f7SMichael Tuexen store.sin = control->whoFrom->ro._l_addr.sin; 6056d59107f7SMichael Tuexen store.sin.sin_port = control->port_from; 6057d59107f7SMichael Tuexen #endif 6058b5b6e5c2SMichael Tuexen break; 6059b5b6e5c2SMichael Tuexen #endif 6060b5b6e5c2SMichael Tuexen default: 6061d59107f7SMichael Tuexen len = 0; 6062b5b6e5c2SMichael Tuexen break; 6063b5b6e5c2SMichael Tuexen } 6064d59107f7SMichael Tuexen memcpy(from, &store, min((size_t)fromlen, len)); 6065e0e00a4dSMichael Tuexen #ifdef INET6 6066f8829a4aSRandall Stewart { 6067b5b6e5c2SMichael Tuexen struct sockaddr_in6 lsa6, *from6; 6068f8829a4aSRandall Stewart 6069b5b6e5c2SMichael Tuexen from6 = (struct sockaddr_in6 *)from; 6070b5b6e5c2SMichael Tuexen sctp_recover_scope_mac(from6, (&lsa6)); 6071f8829a4aSRandall Stewart } 6072f8829a4aSRandall Stewart #endif 6073f8829a4aSRandall Stewart } 60749c5ca6f2SMichael Tuexen if (hold_rlock) { 60759c5ca6f2SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 60769c5ca6f2SMichael Tuexen hold_rlock = 0; 60779c5ca6f2SMichael Tuexen } 60789c5ca6f2SMichael Tuexen if (hold_sblock) { 60799c5ca6f2SMichael Tuexen SOCKBUF_UNLOCK(&so->so_rcv); 60809c5ca6f2SMichael Tuexen hold_sblock = 0; 60819c5ca6f2SMichael Tuexen } 6082f8829a4aSRandall Stewart /* now copy out what data we can */ 6083f8829a4aSRandall Stewart if (mp == NULL) { 6084f8829a4aSRandall Stewart /* copy out each mbuf in the chain up to length */ 6085f8829a4aSRandall Stewart get_more_data: 6086f8829a4aSRandall Stewart m = control->data; 6087f8829a4aSRandall Stewart while (m) { 6088f8829a4aSRandall Stewart /* Move out all we can */ 60890d3cf13dSMichael Tuexen cp_len = uio->uio_resid; 60900d3cf13dSMichael Tuexen my_len = SCTP_BUF_LEN(m); 6091f8829a4aSRandall Stewart if (cp_len > my_len) { 6092f8829a4aSRandall Stewart /* not enough in this buf */ 6093f8829a4aSRandall Stewart cp_len = my_len; 6094f8829a4aSRandall Stewart } 6095f8829a4aSRandall Stewart if (hold_rlock) { 6096f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6097f8829a4aSRandall Stewart hold_rlock = 0; 6098f8829a4aSRandall Stewart } 6099f8829a4aSRandall Stewart if (cp_len > 0) 610058e6eeefSMichael Tuexen error = uiomove(mtod(m, char *), (int)cp_len, uio); 6101f8829a4aSRandall Stewart /* re-read */ 6102f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 6103f8829a4aSRandall Stewart goto release; 6104f8829a4aSRandall Stewart } 61050053ed28SMichael Tuexen 61060696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb && 6107f8829a4aSRandall Stewart stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 6108f8829a4aSRandall Stewart no_rcv_needed = 1; 6109f8829a4aSRandall Stewart } 6110f8829a4aSRandall Stewart if (error) { 6111f8829a4aSRandall Stewart /* error we are out of here */ 6112f8829a4aSRandall Stewart goto release; 6113f8829a4aSRandall Stewart } 6114f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6115f8829a4aSRandall Stewart hold_rlock = 1; 6116139bc87fSRandall Stewart if (cp_len == SCTP_BUF_LEN(m)) { 6117139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 6118139bc87fSRandall Stewart (control->end_added)) { 6119f8829a4aSRandall Stewart out_flags |= MSG_EOR; 612052129fcdSRandall Stewart if ((control->do_not_ref_stcb == 0) && 612152129fcdSRandall Stewart (control->stcb != NULL) && 612252129fcdSRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0)) 6123ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 6124f8829a4aSRandall Stewart } 6125139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6126f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6127f8829a4aSRandall Stewart } 6128f8829a4aSRandall Stewart /* we ate up the mbuf */ 6129f8829a4aSRandall Stewart if (in_flags & MSG_PEEK) { 6130f8829a4aSRandall Stewart /* just looking */ 6131139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 6132f8829a4aSRandall Stewart copied_so_far += cp_len; 6133f8829a4aSRandall Stewart } else { 6134f8829a4aSRandall Stewart /* dispose of the mbuf */ 6135b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6136f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6137139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 613880fefe0aSRandall Stewart } 6139f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 6140b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6141f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6142f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 614380fefe0aSRandall Stewart } 6144f8829a4aSRandall Stewart copied_so_far += cp_len; 614558e6eeefSMichael Tuexen freed_so_far += (uint32_t)cp_len; 6146c4739e2fSRandall Stewart freed_so_far += MSIZE; 614718e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 6148f8829a4aSRandall Stewart control->data = sctp_m_free(m); 6149f8829a4aSRandall Stewart m = control->data; 6150b7b84c0eSMichael Tuexen /* 6151b7b84c0eSMichael Tuexen * been through it all, must hold sb 6152b7b84c0eSMichael Tuexen * lock ok to null tail 6153b7b84c0eSMichael Tuexen */ 6154f8829a4aSRandall Stewart if (control->data == NULL) { 6155a5d547adSRandall Stewart #ifdef INVARIANTS 6156f8829a4aSRandall Stewart if ((control->end_added == 0) || 6157f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 6158f8829a4aSRandall Stewart /* 6159f8829a4aSRandall Stewart * If the end is not 6160f8829a4aSRandall Stewart * added, OR the 6161f8829a4aSRandall Stewart * next is NOT null 6162f8829a4aSRandall Stewart * we MUST have the 6163f8829a4aSRandall Stewart * lock. 6164f8829a4aSRandall Stewart */ 6165f8829a4aSRandall Stewart if (mtx_owned(&inp->inp_rdata_mtx) == 0) { 6166f8829a4aSRandall Stewart panic("Hmm we don't own the lock?"); 6167f8829a4aSRandall Stewart } 6168f8829a4aSRandall Stewart } 6169f8829a4aSRandall Stewart #endif 6170f8829a4aSRandall Stewart control->tail_mbuf = NULL; 6171a5d547adSRandall Stewart #ifdef INVARIANTS 6172f8829a4aSRandall Stewart if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { 6173f8829a4aSRandall Stewart panic("end_added, nothing left and no MSG_EOR"); 6174f8829a4aSRandall Stewart } 6175f8829a4aSRandall Stewart #endif 6176f8829a4aSRandall Stewart } 6177f8829a4aSRandall Stewart } 6178f8829a4aSRandall Stewart } else { 6179f8829a4aSRandall Stewart /* Do we need to trim the mbuf? */ 6180139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6181f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6182f8829a4aSRandall Stewart } 6183f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) == 0) { 6184139bc87fSRandall Stewart SCTP_BUF_RESV_UF(m, cp_len); 618558e6eeefSMichael Tuexen SCTP_BUF_LEN(m) -= (int)cp_len; 6186b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 618758e6eeefSMichael Tuexen sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, (int)cp_len); 618880fefe0aSRandall Stewart } 61894e88d37aSMichael Tuexen atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); 61900696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 61910696e120SRandall Stewart stcb) { 61924e88d37aSMichael Tuexen atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); 6193f8829a4aSRandall Stewart } 6194f8829a4aSRandall Stewart copied_so_far += cp_len; 619558e6eeefSMichael Tuexen freed_so_far += (uint32_t)cp_len; 6196c4739e2fSRandall Stewart freed_so_far += MSIZE; 6197b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6198f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, 6199f8829a4aSRandall Stewart SCTP_LOG_SBRESULT, 0); 620080fefe0aSRandall Stewart } 620118e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 6202f8829a4aSRandall Stewart } else { 6203f8829a4aSRandall Stewart copied_so_far += cp_len; 6204f8829a4aSRandall Stewart } 6205f8829a4aSRandall Stewart } 6206d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { 6207f8829a4aSRandall Stewart break; 6208f8829a4aSRandall Stewart } 6209f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 6210f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 6211f8829a4aSRandall Stewart (freed_so_far >= rwnd_req)) { 6212f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6213f8829a4aSRandall Stewart } 6214f8829a4aSRandall Stewart } /* end while(m) */ 6215f8829a4aSRandall Stewart /* 6216f8829a4aSRandall Stewart * At this point we have looked at it all and we either have 6217f8829a4aSRandall Stewart * a MSG_EOR/or read all the user wants... <OR> 6218f8829a4aSRandall Stewart * control->length == 0. 6219f8829a4aSRandall Stewart */ 6220d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) { 6221f8829a4aSRandall Stewart /* we are done with this control */ 6222f8829a4aSRandall Stewart if (control->length == 0) { 6223f8829a4aSRandall Stewart if (control->data) { 6224a5d547adSRandall Stewart #ifdef INVARIANTS 6225f8829a4aSRandall Stewart panic("control->data not null at read eor?"); 6226f8829a4aSRandall Stewart #else 6227ad81507eSRandall Stewart SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n"); 6228f8829a4aSRandall Stewart sctp_m_freem(control->data); 6229f8829a4aSRandall Stewart control->data = NULL; 6230f8829a4aSRandall Stewart #endif 6231f8829a4aSRandall Stewart } 6232f8829a4aSRandall Stewart done_with_control: 6233f8829a4aSRandall Stewart if (hold_rlock == 0) { 6234f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6235f8829a4aSRandall Stewart hold_rlock = 1; 6236f8829a4aSRandall Stewart } 6237f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 6238f8829a4aSRandall Stewart /* Add back any hiddend data */ 6239f8829a4aSRandall Stewart if (control->held_length) { 6240f8829a4aSRandall Stewart held_length = 0; 6241f8829a4aSRandall Stewart control->held_length = 0; 6242f8829a4aSRandall Stewart wakeup_read_socket = 1; 6243f8829a4aSRandall Stewart } 624417205eccSRandall Stewart if (control->aux_data) { 624517205eccSRandall Stewart sctp_m_free(control->aux_data); 624617205eccSRandall Stewart control->aux_data = NULL; 624717205eccSRandall Stewart } 6248f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 6249f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 6250f8829a4aSRandall Stewart control->data = NULL; 625198d5fd97SMichael Tuexen #ifdef INVARIANTS 625244249214SRandall Stewart if (control->on_strm_q) { 625344249214SRandall Stewart panic("About to free ctl:%p so:%p and its in %d", 625444249214SRandall Stewart control, so, control->on_strm_q); 625544249214SRandall Stewart } 625698d5fd97SMichael Tuexen #endif 6257f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 6258f8829a4aSRandall Stewart control = NULL; 62590696e120SRandall Stewart if ((freed_so_far >= rwnd_req) && 62600696e120SRandall Stewart (no_rcv_needed == 0)) 6261f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6262f8829a4aSRandall Stewart 6263f8829a4aSRandall Stewart } else { 6264f8829a4aSRandall Stewart /* 6265f8829a4aSRandall Stewart * The user did not read all of this 6266f8829a4aSRandall Stewart * message, turn off the returned MSG_EOR 6267f8829a4aSRandall Stewart * since we are leaving more behind on the 6268f8829a4aSRandall Stewart * control to read. 6269f8829a4aSRandall Stewart */ 6270a5d547adSRandall Stewart #ifdef INVARIANTS 62710696e120SRandall Stewart if (control->end_added && 62720696e120SRandall Stewart (control->data == NULL) && 6273f8829a4aSRandall Stewart (control->tail_mbuf == NULL)) { 6274f8829a4aSRandall Stewart panic("Gak, control->length is corrupt?"); 6275f8829a4aSRandall Stewart } 6276f8829a4aSRandall Stewart #endif 6277f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 6278f8829a4aSRandall Stewart out_flags &= ~MSG_EOR; 6279f8829a4aSRandall Stewart } 6280f8829a4aSRandall Stewart } 6281f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 6282f8829a4aSRandall Stewart goto release; 6283f8829a4aSRandall Stewart } 6284f8829a4aSRandall Stewart if ((uio->uio_resid == 0) || 628504aab884SMichael Tuexen ((in_eeor_mode) && 628643ecbff2SMichael Tuexen (copied_so_far >= max(so->so_rcv.sb_lowat, 1)))) { 6287f8829a4aSRandall Stewart goto release; 6288f8829a4aSRandall Stewart } 6289f8829a4aSRandall Stewart /* 6290f8829a4aSRandall Stewart * If I hit here the receiver wants more and this message is 6291f8829a4aSRandall Stewart * NOT done (pd-api). So two questions. Can we block? if not 6292f8829a4aSRandall Stewart * we are done. Did the user NOT set MSG_WAITALL? 6293f8829a4aSRandall Stewart */ 6294f8829a4aSRandall Stewart if (block_allowed == 0) { 6295f8829a4aSRandall Stewart goto release; 6296f8829a4aSRandall Stewart } 6297f8829a4aSRandall Stewart /* 6298f8829a4aSRandall Stewart * We need to wait for more data a few things: - We don't 6299f8829a4aSRandall Stewart * sbunlock() so we don't get someone else reading. - We 6300f8829a4aSRandall Stewart * must be sure to account for the case where what is added 6301f8829a4aSRandall Stewart * is NOT to our control when we wakeup. 6302f8829a4aSRandall Stewart */ 6303f8829a4aSRandall Stewart 6304f8829a4aSRandall Stewart /* 6305f8829a4aSRandall Stewart * Do we need to tell the transport a rwnd update might be 6306f8829a4aSRandall Stewart * needed before we go to sleep? 6307f8829a4aSRandall Stewart */ 6308f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 6309f8829a4aSRandall Stewart ((freed_so_far >= rwnd_req) && 6310f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 6311f8829a4aSRandall Stewart (no_rcv_needed == 0))) { 6312f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6313f8829a4aSRandall Stewart } 6314f8829a4aSRandall Stewart wait_some_more: 631544b7479bSRandall Stewart if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { 6316f8829a4aSRandall Stewart goto release; 6317f8829a4aSRandall Stewart } 63180053ed28SMichael Tuexen 6319f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) 6320f8829a4aSRandall Stewart goto release; 6321f8829a4aSRandall Stewart 6322f8829a4aSRandall Stewart if (hold_rlock == 1) { 6323f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6324f8829a4aSRandall Stewart hold_rlock = 0; 6325f8829a4aSRandall Stewart } 6326f8829a4aSRandall Stewart if (hold_sblock == 0) { 6327f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 6328f8829a4aSRandall Stewart hold_sblock = 1; 6329f8829a4aSRandall Stewart } 6330851b7298SRandall Stewart if ((copied_so_far) && (control->length == 0) && 6331b5c16493SMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) { 6332851b7298SRandall Stewart goto release; 6333851b7298SRandall Stewart } 63344e88d37aSMichael Tuexen if (so->so_rcv.sb_cc <= control->held_length) { 6335f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 6336f8829a4aSRandall Stewart if (error) { 6337f8829a4aSRandall Stewart goto release; 6338f8829a4aSRandall Stewart } 6339f8829a4aSRandall Stewart control->held_length = 0; 6340f8829a4aSRandall Stewart } 6341f8829a4aSRandall Stewart if (hold_sblock) { 6342f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6343f8829a4aSRandall Stewart hold_sblock = 0; 6344f8829a4aSRandall Stewart } 6345f8829a4aSRandall Stewart if (control->length == 0) { 6346f8829a4aSRandall Stewart /* still nothing here */ 6347f8829a4aSRandall Stewart if (control->end_added == 1) { 6348f8829a4aSRandall Stewart /* he aborted, or is done i.e.did a shutdown */ 6349f8829a4aSRandall Stewart out_flags |= MSG_EOR; 63509a6142d8SRandall Stewart if (control->pdapi_aborted) { 63516114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 6352ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 63539a6142d8SRandall Stewart 635403b0b021SRandall Stewart out_flags |= MSG_TRUNC; 63559a6142d8SRandall Stewart } else { 63566114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 6357ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 63589a6142d8SRandall Stewart } 6359f8829a4aSRandall Stewart goto done_with_control; 6360f8829a4aSRandall Stewart } 63614e88d37aSMichael Tuexen if (so->so_rcv.sb_cc > held_length) { 63624e88d37aSMichael Tuexen control->held_length = so->so_rcv.sb_cc; 6363f8829a4aSRandall Stewart held_length = 0; 6364f8829a4aSRandall Stewart } 6365f8829a4aSRandall Stewart goto wait_some_more; 6366f8829a4aSRandall Stewart } else if (control->data == NULL) { 636750cec919SRandall Stewart /* 636850cec919SRandall Stewart * we must re-sync since data is probably being 636950cec919SRandall Stewart * added 637050cec919SRandall Stewart */ 637150cec919SRandall Stewart SCTP_INP_READ_LOCK(inp); 637250cec919SRandall Stewart if ((control->length > 0) && (control->data == NULL)) { 6373b7b84c0eSMichael Tuexen /* 6374b7b84c0eSMichael Tuexen * big trouble.. we have the lock and its 6375b7b84c0eSMichael Tuexen * corrupt? 6376b7b84c0eSMichael Tuexen */ 63779c04b296SRandall Stewart #ifdef INVARIANTS 63789d18771fSRandall Stewart panic("Impossible data==NULL length !=0"); 63799c04b296SRandall Stewart #endif 63809c04b296SRandall Stewart out_flags |= MSG_EOR; 63819c04b296SRandall Stewart out_flags |= MSG_TRUNC; 63829c04b296SRandall Stewart control->length = 0; 63839c04b296SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 63849c04b296SRandall Stewart goto done_with_control; 6385f8829a4aSRandall Stewart } 638650cec919SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 638750cec919SRandall Stewart /* We will fall around to get more data */ 638850cec919SRandall Stewart } 6389f8829a4aSRandall Stewart goto get_more_data; 6390f8829a4aSRandall Stewart } else { 639117205eccSRandall Stewart /*- 639217205eccSRandall Stewart * Give caller back the mbuf chain, 639317205eccSRandall Stewart * store in uio_resid the length 6394f8829a4aSRandall Stewart */ 639517205eccSRandall Stewart wakeup_read_socket = 0; 6396f8829a4aSRandall Stewart if ((control->end_added == 0) || 6397f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 6398f8829a4aSRandall Stewart /* Need to get rlock */ 6399f8829a4aSRandall Stewart if (hold_rlock == 0) { 6400f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6401f8829a4aSRandall Stewart hold_rlock = 1; 6402f8829a4aSRandall Stewart } 6403f8829a4aSRandall Stewart } 6404139bc87fSRandall Stewart if (control->end_added) { 6405f8829a4aSRandall Stewart out_flags |= MSG_EOR; 640660990c0cSMichael Tuexen if ((control->do_not_ref_stcb == 0) && 640760990c0cSMichael Tuexen (control->stcb != NULL) && 640860990c0cSMichael Tuexen ((control->spec_flags & M_NOTIFICATION) == 0)) 6409ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 6410f8829a4aSRandall Stewart } 6411139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6412f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6413f8829a4aSRandall Stewart } 641417205eccSRandall Stewart uio->uio_resid = control->length; 6415f8829a4aSRandall Stewart *mp = control->data; 6416f8829a4aSRandall Stewart m = control->data; 6417f8829a4aSRandall Stewart while (m) { 6418b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6419f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6420139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 642180fefe0aSRandall Stewart } 6422f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 642358e6eeefSMichael Tuexen freed_so_far += (uint32_t)SCTP_BUF_LEN(m); 6424c4739e2fSRandall Stewart freed_so_far += MSIZE; 6425b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6426f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6427f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 642880fefe0aSRandall Stewart } 6429139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 6430f8829a4aSRandall Stewart } 6431f8829a4aSRandall Stewart control->data = control->tail_mbuf = NULL; 6432f8829a4aSRandall Stewart control->length = 0; 6433f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 6434f8829a4aSRandall Stewart /* Done with this control */ 6435f8829a4aSRandall Stewart goto done_with_control; 6436f8829a4aSRandall Stewart } 6437f8829a4aSRandall Stewart } 6438f8829a4aSRandall Stewart release: 6439f8829a4aSRandall Stewart if (hold_rlock == 1) { 6440f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6441f8829a4aSRandall Stewart hold_rlock = 0; 6442f8829a4aSRandall Stewart } 64437abab911SRobert Watson if (hold_sblock == 1) { 64447abab911SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 64457abab911SRobert Watson hold_sblock = 0; 6446f8829a4aSRandall Stewart } 64470053ed28SMichael Tuexen 6448f8829a4aSRandall Stewart sbunlock(&so->so_rcv); 64497abab911SRobert Watson sockbuf_lock = 0; 6450f8829a4aSRandall Stewart 6451f8829a4aSRandall Stewart release_unlocked: 6452f8829a4aSRandall Stewart if (hold_sblock) { 6453f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6454f8829a4aSRandall Stewart hold_sblock = 0; 6455f8829a4aSRandall Stewart } 6456f8829a4aSRandall Stewart if ((stcb) && (in_flags & MSG_PEEK) == 0) { 6457f8829a4aSRandall Stewart if ((freed_so_far >= rwnd_req) && 6458f8829a4aSRandall Stewart (control && (control->do_not_ref_stcb == 0)) && 6459f8829a4aSRandall Stewart (no_rcv_needed == 0)) 6460f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6461f8829a4aSRandall Stewart } 6462f8829a4aSRandall Stewart out: 64631b9f62a0SRandall Stewart if (msg_flags) { 64641b9f62a0SRandall Stewart *msg_flags = out_flags; 64651b9f62a0SRandall Stewart } 64669a6142d8SRandall Stewart if (((out_flags & MSG_EOR) == 0) && 64679a6142d8SRandall Stewart ((in_flags & MSG_PEEK) == 0) && 64689a6142d8SRandall Stewart (sinfo) && 6469e2e7c62eSMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 6470e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) { 64719a6142d8SRandall Stewart struct sctp_extrcvinfo *s_extra; 64729a6142d8SRandall Stewart 64739a6142d8SRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 6474b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; 64759a6142d8SRandall Stewart } 6476f8829a4aSRandall Stewart if (hold_rlock == 1) { 6477f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6478f8829a4aSRandall Stewart } 6479f8829a4aSRandall Stewart if (hold_sblock) { 6480f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6481f8829a4aSRandall Stewart } 64827abab911SRobert Watson if (sockbuf_lock) { 64837abab911SRobert Watson sbunlock(&so->so_rcv); 64847abab911SRobert Watson } 64850053ed28SMichael Tuexen 648650cec919SRandall Stewart if (freecnt_applied) { 6487f8829a4aSRandall Stewart /* 6488f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the free 6489f8829a4aSRandall Stewart * code will stop. But since we used the socketbuf lock and 6490f8829a4aSRandall Stewart * the sender uses the tcb_lock to increment, we need to use 6491f8829a4aSRandall Stewart * the atomic add to the refcnt. 6492f8829a4aSRandall Stewart */ 649350cec919SRandall Stewart if (stcb == NULL) { 6494df6e0cc3SRandall Stewart #ifdef INVARIANTS 649550cec919SRandall Stewart panic("stcb for refcnt has gone NULL?"); 6496df6e0cc3SRandall Stewart goto stage_left; 6497df6e0cc3SRandall Stewart #else 6498df6e0cc3SRandall Stewart goto stage_left; 6499df6e0cc3SRandall Stewart #endif 650050cec919SRandall Stewart } 6501f8829a4aSRandall Stewart /* Save the value back for next time */ 6502f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = freed_so_far; 6503cf46caceSMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, -1); 6504f8829a4aSRandall Stewart } 6505b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 6506f8829a4aSRandall Stewart if (stcb) { 6507f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6508f8829a4aSRandall Stewart freed_so_far, 65099a8e3088SMichael Tuexen (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), 6510f8829a4aSRandall Stewart stcb->asoc.my_rwnd, 65114e88d37aSMichael Tuexen so->so_rcv.sb_cc); 6512f8829a4aSRandall Stewart } else { 6513f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6514f8829a4aSRandall Stewart freed_so_far, 65159a8e3088SMichael Tuexen (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), 6516f8829a4aSRandall Stewart 0, 65174e88d37aSMichael Tuexen so->so_rcv.sb_cc); 6518f8829a4aSRandall Stewart } 651980fefe0aSRandall Stewart } 6520df6e0cc3SRandall Stewart stage_left: 6521f8829a4aSRandall Stewart if (wakeup_read_socket) { 6522f8829a4aSRandall Stewart sctp_sorwakeup(inp, so); 6523f8829a4aSRandall Stewart } 6524f8829a4aSRandall Stewart return (error); 6525f8829a4aSRandall Stewart } 6526f8829a4aSRandall Stewart 6527f8829a4aSRandall Stewart 6528f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING 6529f8829a4aSRandall Stewart struct mbuf * 6530f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m) 6531f8829a4aSRandall Stewart { 6532b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 6533f8829a4aSRandall Stewart sctp_log_mb(m, SCTP_MBUF_IFREE); 6534f8829a4aSRandall Stewart } 6535f8829a4aSRandall Stewart return (m_free(m)); 6536f8829a4aSRandall Stewart } 6537f8829a4aSRandall Stewart 6538f8829a4aSRandall Stewart void 6539f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb) 6540f8829a4aSRandall Stewart { 6541f8829a4aSRandall Stewart while (mb != NULL) 6542f8829a4aSRandall Stewart mb = sctp_m_free(mb); 6543f8829a4aSRandall Stewart } 6544f8829a4aSRandall Stewart 6545f8829a4aSRandall Stewart #endif 6546f8829a4aSRandall Stewart 654742551e99SRandall Stewart int 654842551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) 654942551e99SRandall Stewart { 655042551e99SRandall Stewart /* 655142551e99SRandall Stewart * Given a local address. For all associations that holds the 655242551e99SRandall Stewart * address, request a peer-set-primary. 655342551e99SRandall Stewart */ 655442551e99SRandall Stewart struct sctp_ifa *ifa; 655542551e99SRandall Stewart struct sctp_laddr *wi; 655642551e99SRandall Stewart 655742551e99SRandall Stewart ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); 655842551e99SRandall Stewart if (ifa == NULL) { 6559c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); 656042551e99SRandall Stewart return (EADDRNOTAVAIL); 656142551e99SRandall Stewart } 656242551e99SRandall Stewart /* 656342551e99SRandall Stewart * Now that we have the ifa we must awaken the iterator with this 656442551e99SRandall Stewart * message. 656542551e99SRandall Stewart */ 6566b3f1ea41SRandall Stewart wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); 656742551e99SRandall Stewart if (wi == NULL) { 6568c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 656942551e99SRandall Stewart return (ENOMEM); 657042551e99SRandall Stewart } 657142551e99SRandall Stewart /* Now incr the count and int wi structure */ 657242551e99SRandall Stewart SCTP_INCR_LADDR_COUNT(); 65735ba7f91fSMichael Tuexen memset(wi, 0, sizeof(*wi)); 6574d61a0ae0SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); 657542551e99SRandall Stewart wi->ifa = ifa; 657642551e99SRandall Stewart wi->action = SCTP_SET_PRIM_ADDR; 657742551e99SRandall Stewart atomic_add_int(&ifa->refcount, 1); 657842551e99SRandall Stewart 657942551e99SRandall Stewart /* Now add it to the work queue */ 6580f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 658142551e99SRandall Stewart /* 658242551e99SRandall Stewart * Should this really be a tailq? As it is we will process the 658342551e99SRandall Stewart * newest first :-0 658442551e99SRandall Stewart */ 6585b3f1ea41SRandall Stewart LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 658642551e99SRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 658742551e99SRandall Stewart (struct sctp_inpcb *)NULL, 658842551e99SRandall Stewart (struct sctp_tcb *)NULL, 658942551e99SRandall Stewart (struct sctp_nets *)NULL); 65902c62ba73SMichael Tuexen SCTP_WQ_ADDR_UNLOCK(); 659142551e99SRandall Stewart return (0); 659242551e99SRandall Stewart } 659342551e99SRandall Stewart 659442551e99SRandall Stewart 6595f8829a4aSRandall Stewart int 659617205eccSRandall Stewart sctp_soreceive(struct socket *so, 659717205eccSRandall Stewart struct sockaddr **psa, 659817205eccSRandall Stewart struct uio *uio, 659917205eccSRandall Stewart struct mbuf **mp0, 660017205eccSRandall Stewart struct mbuf **controlp, 660117205eccSRandall Stewart int *flagsp) 6602f8829a4aSRandall Stewart { 6603f8829a4aSRandall Stewart int error, fromlen; 6604f8829a4aSRandall Stewart uint8_t sockbuf[256]; 6605f8829a4aSRandall Stewart struct sockaddr *from; 6606f8829a4aSRandall Stewart struct sctp_extrcvinfo sinfo; 6607f8829a4aSRandall Stewart int filling_sinfo = 1; 660846bf534cSMichael Tuexen int flags; 6609f8829a4aSRandall Stewart struct sctp_inpcb *inp; 6610f8829a4aSRandall Stewart 6611f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 6612f8829a4aSRandall Stewart /* pickup the assoc we are reading from */ 6613f8829a4aSRandall Stewart if (inp == NULL) { 6614c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6615f8829a4aSRandall Stewart return (EINVAL); 6616f8829a4aSRandall Stewart } 6617e2e7c62eSMichael Tuexen if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && 6618e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && 6619e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) || 6620f8829a4aSRandall Stewart (controlp == NULL)) { 6621f8829a4aSRandall Stewart /* user does not want the sndrcv ctl */ 6622f8829a4aSRandall Stewart filling_sinfo = 0; 6623f8829a4aSRandall Stewart } 6624f8829a4aSRandall Stewart if (psa) { 6625f8829a4aSRandall Stewart from = (struct sockaddr *)sockbuf; 6626f8829a4aSRandall Stewart fromlen = sizeof(sockbuf); 6627f8829a4aSRandall Stewart from->sa_len = 0; 6628f8829a4aSRandall Stewart } else { 6629f8829a4aSRandall Stewart from = NULL; 6630f8829a4aSRandall Stewart fromlen = 0; 6631f8829a4aSRandall Stewart } 6632f8829a4aSRandall Stewart 6633e432298aSXin LI if (filling_sinfo) { 6634e432298aSXin LI memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo)); 6635e432298aSXin LI } 663646bf534cSMichael Tuexen if (flagsp != NULL) { 663746bf534cSMichael Tuexen flags = *flagsp; 663846bf534cSMichael Tuexen } else { 663946bf534cSMichael Tuexen flags = 0; 664046bf534cSMichael Tuexen } 664146bf534cSMichael Tuexen error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags, 6642f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo); 664346bf534cSMichael Tuexen if (flagsp != NULL) { 664446bf534cSMichael Tuexen *flagsp = flags; 664546bf534cSMichael Tuexen } 6646e432298aSXin LI if (controlp != NULL) { 6647f8829a4aSRandall Stewart /* copy back the sinfo in a CMSG format */ 664846bf534cSMichael Tuexen if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) { 6649f8829a4aSRandall Stewart *controlp = sctp_build_ctl_nchunk(inp, 6650f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo); 665146bf534cSMichael Tuexen } else { 6652f8829a4aSRandall Stewart *controlp = NULL; 6653f8829a4aSRandall Stewart } 665446bf534cSMichael Tuexen } 6655f8829a4aSRandall Stewart if (psa) { 6656f8829a4aSRandall Stewart /* copy back the address info */ 6657f8829a4aSRandall Stewart if (from && from->sa_len) { 6658f8829a4aSRandall Stewart *psa = sodupsockaddr(from, M_NOWAIT); 6659f8829a4aSRandall Stewart } else { 6660f8829a4aSRandall Stewart *psa = NULL; 6661f8829a4aSRandall Stewart } 6662f8829a4aSRandall Stewart } 6663f8829a4aSRandall Stewart return (error); 6664f8829a4aSRandall Stewart } 666517205eccSRandall Stewart 666617205eccSRandall Stewart 666717205eccSRandall Stewart 666817205eccSRandall Stewart 666917205eccSRandall Stewart 667017205eccSRandall Stewart int 6671d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, 6672d61a0ae0SRandall Stewart int totaddr, int *error) 667317205eccSRandall Stewart { 667417205eccSRandall Stewart int added = 0; 667517205eccSRandall Stewart int i; 667617205eccSRandall Stewart struct sctp_inpcb *inp; 667717205eccSRandall Stewart struct sockaddr *sa; 667817205eccSRandall Stewart size_t incr = 0; 667992776dfdSMichael Tuexen #ifdef INET 668092776dfdSMichael Tuexen struct sockaddr_in *sin; 668192776dfdSMichael Tuexen #endif 668292776dfdSMichael Tuexen #ifdef INET6 668392776dfdSMichael Tuexen struct sockaddr_in6 *sin6; 668492776dfdSMichael Tuexen #endif 668592776dfdSMichael Tuexen 668617205eccSRandall Stewart sa = addr; 668717205eccSRandall Stewart inp = stcb->sctp_ep; 668817205eccSRandall Stewart *error = 0; 668917205eccSRandall Stewart for (i = 0; i < totaddr; i++) { 6690ea5eba11SMichael Tuexen switch (sa->sa_family) { 6691ea5eba11SMichael Tuexen #ifdef INET 6692ea5eba11SMichael Tuexen case AF_INET: 669317205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 669492776dfdSMichael Tuexen sin = (struct sockaddr_in *)sa; 669592776dfdSMichael Tuexen if ((sin->sin_addr.s_addr == INADDR_ANY) || 669692776dfdSMichael Tuexen (sin->sin_addr.s_addr == INADDR_BROADCAST) || 669792776dfdSMichael Tuexen IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 669892776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6699ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6700ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_7); 670192776dfdSMichael Tuexen *error = EINVAL; 670292776dfdSMichael Tuexen goto out_now; 670392776dfdSMichael Tuexen } 67047154bf4aSMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, 67057154bf4aSMichael Tuexen SCTP_DONOT_SETSCOPE, 67067154bf4aSMichael Tuexen SCTP_ADDR_IS_CONFIRMED)) { 670717205eccSRandall Stewart /* assoc gone no un-lock */ 6708c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6709ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6710ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_8); 671117205eccSRandall Stewart *error = ENOBUFS; 671217205eccSRandall Stewart goto out_now; 671317205eccSRandall Stewart } 671417205eccSRandall Stewart added++; 6715ea5eba11SMichael Tuexen break; 6716ea5eba11SMichael Tuexen #endif 6717ea5eba11SMichael Tuexen #ifdef INET6 6718ea5eba11SMichael Tuexen case AF_INET6: 671917205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 672092776dfdSMichael Tuexen sin6 = (struct sockaddr_in6 *)sa; 672192776dfdSMichael Tuexen if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 672292776dfdSMichael Tuexen IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 672392776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6724ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6725ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_9); 672692776dfdSMichael Tuexen *error = EINVAL; 672792776dfdSMichael Tuexen goto out_now; 672892776dfdSMichael Tuexen } 67297154bf4aSMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, 67307154bf4aSMichael Tuexen SCTP_DONOT_SETSCOPE, 67317154bf4aSMichael Tuexen SCTP_ADDR_IS_CONFIRMED)) { 673217205eccSRandall Stewart /* assoc gone no un-lock */ 6733c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6734ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6735ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_10); 673617205eccSRandall Stewart *error = ENOBUFS; 673717205eccSRandall Stewart goto out_now; 673817205eccSRandall Stewart } 673917205eccSRandall Stewart added++; 6740ea5eba11SMichael Tuexen break; 6741ea5eba11SMichael Tuexen #endif 6742ea5eba11SMichael Tuexen default: 6743ea5eba11SMichael Tuexen break; 674417205eccSRandall Stewart } 674517205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 674617205eccSRandall Stewart } 674717205eccSRandall Stewart out_now: 674817205eccSRandall Stewart return (added); 674917205eccSRandall Stewart } 675017205eccSRandall Stewart 6751fc26bf71SMichael Tuexen int 6752d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, 6753fc26bf71SMichael Tuexen unsigned int totaddr, 6754fc26bf71SMichael Tuexen unsigned int *num_v4, unsigned int *num_v6, 6755fc26bf71SMichael Tuexen unsigned int limit) 675617205eccSRandall Stewart { 675717205eccSRandall Stewart struct sockaddr *sa; 6758fc26bf71SMichael Tuexen struct sctp_tcb *stcb; 67599a8e3088SMichael Tuexen unsigned int incr, at, i; 676017205eccSRandall Stewart 6761e1949767SMichael Tuexen at = 0; 676217205eccSRandall Stewart sa = addr; 6763fc26bf71SMichael Tuexen *num_v6 = *num_v4 = 0; 676417205eccSRandall Stewart /* account and validate addresses */ 6765fc26bf71SMichael Tuexen if (totaddr == 0) { 6766fc26bf71SMichael Tuexen return (EINVAL); 6767fc26bf71SMichael Tuexen } 6768fc26bf71SMichael Tuexen for (i = 0; i < totaddr; i++) { 6769fc26bf71SMichael Tuexen if (at + sizeof(struct sockaddr) > limit) { 6770fc26bf71SMichael Tuexen return (EINVAL); 6771fc26bf71SMichael Tuexen } 6772ea5eba11SMichael Tuexen switch (sa->sa_family) { 6773ea5eba11SMichael Tuexen #ifdef INET 6774ea5eba11SMichael Tuexen case AF_INET: 6775e1949767SMichael Tuexen incr = (unsigned int)sizeof(struct sockaddr_in); 6776d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6777fc26bf71SMichael Tuexen return (EINVAL); 6778d61a0ae0SRandall Stewart } 67799a8e3088SMichael Tuexen (*num_v4) += 1; 6780ea5eba11SMichael Tuexen break; 6781ea5eba11SMichael Tuexen #endif 6782ea5eba11SMichael Tuexen #ifdef INET6 6783ea5eba11SMichael Tuexen case AF_INET6: 6784ea5eba11SMichael Tuexen { 678517205eccSRandall Stewart struct sockaddr_in6 *sin6; 678617205eccSRandall Stewart 678717205eccSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 678817205eccSRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 678917205eccSRandall Stewart /* Must be non-mapped for connectx */ 6790fc26bf71SMichael Tuexen return (EINVAL); 679117205eccSRandall Stewart } 6792e1949767SMichael Tuexen incr = (unsigned int)sizeof(struct sockaddr_in6); 6793d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6794fc26bf71SMichael Tuexen return (EINVAL); 6795d61a0ae0SRandall Stewart } 67969a8e3088SMichael Tuexen (*num_v6) += 1; 6797ea5eba11SMichael Tuexen break; 6798ea5eba11SMichael Tuexen } 6799ea5eba11SMichael Tuexen #endif 6800ea5eba11SMichael Tuexen default: 6801fc26bf71SMichael Tuexen return (EINVAL); 680217205eccSRandall Stewart } 6803fc26bf71SMichael Tuexen if ((at + incr) > limit) { 6804fc26bf71SMichael Tuexen return (EINVAL); 6805ea5eba11SMichael Tuexen } 6806d61a0ae0SRandall Stewart SCTP_INP_INCR_REF(inp); 680717205eccSRandall Stewart stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 680817205eccSRandall Stewart if (stcb != NULL) { 6809fc26bf71SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 6810fc26bf71SMichael Tuexen return (EALREADY); 6811d61a0ae0SRandall Stewart } else { 6812d61a0ae0SRandall Stewart SCTP_INP_DECR_REF(inp); 681317205eccSRandall Stewart } 6814fc26bf71SMichael Tuexen at += incr; 681517205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 681617205eccSRandall Stewart } 6817fc26bf71SMichael Tuexen return (0); 681817205eccSRandall Stewart } 681935918f85SRandall Stewart 682035918f85SRandall Stewart /* 682135918f85SRandall Stewart * sctp_bindx(ADD) for one address. 682235918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 682335918f85SRandall Stewart */ 682435918f85SRandall Stewart void 682535918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, 682635918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 682735918f85SRandall Stewart uint32_t vrf_id, int *error, void *p) 682835918f85SRandall Stewart { 682935918f85SRandall Stewart struct sockaddr *addr_touse; 6830d59107f7SMichael Tuexen #if defined(INET) && defined(INET6) 683135918f85SRandall Stewart struct sockaddr_in sin; 68325e2c2d87SRandall Stewart #endif 68335e2c2d87SRandall Stewart 683435918f85SRandall Stewart /* see if we're bound all already! */ 683535918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6836c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 683735918f85SRandall Stewart *error = EINVAL; 683835918f85SRandall Stewart return; 683935918f85SRandall Stewart } 684035918f85SRandall Stewart addr_touse = sa; 6841ea5eba11SMichael Tuexen #ifdef INET6 684235918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 6843d59107f7SMichael Tuexen #ifdef INET 684435918f85SRandall Stewart struct sockaddr_in6 *sin6; 684535918f85SRandall Stewart 6846d59107f7SMichael Tuexen #endif 684735918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6848c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 684935918f85SRandall Stewart *error = EINVAL; 685035918f85SRandall Stewart return; 685135918f85SRandall Stewart } 6852db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6853db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6854c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6855db4fd95bSRandall Stewart *error = EINVAL; 6856db4fd95bSRandall Stewart return; 6857db4fd95bSRandall Stewart } 6858d59107f7SMichael Tuexen #ifdef INET 685935918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 686035918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6861db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6862db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6863db4fd95bSRandall Stewart /* can't bind v4-mapped on PF_INET sockets */ 6864c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6865db4fd95bSRandall Stewart *error = EINVAL; 6866db4fd95bSRandall Stewart return; 6867db4fd95bSRandall Stewart } 686835918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 686935918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 687035918f85SRandall Stewart } 6871d59107f7SMichael Tuexen #endif 687235918f85SRandall Stewart } 687335918f85SRandall Stewart #endif 6874ea5eba11SMichael Tuexen #ifdef INET 687535918f85SRandall Stewart if (sa->sa_family == AF_INET) { 687635918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6877c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 687835918f85SRandall Stewart *error = EINVAL; 687935918f85SRandall Stewart return; 688035918f85SRandall Stewart } 6881db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6882db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6883db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6884c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6885db4fd95bSRandall Stewart *error = EINVAL; 6886db4fd95bSRandall Stewart return; 6887db4fd95bSRandall Stewart } 688835918f85SRandall Stewart } 6889ea5eba11SMichael Tuexen #endif 689035918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 689135918f85SRandall Stewart if (p == NULL) { 689235918f85SRandall Stewart /* Can't get proc for Net/Open BSD */ 6893c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 689435918f85SRandall Stewart *error = EINVAL; 689535918f85SRandall Stewart return; 689635918f85SRandall Stewart } 68971b649582SRandall Stewart *error = sctp_inpcb_bind(so, addr_touse, NULL, p); 689835918f85SRandall Stewart return; 689935918f85SRandall Stewart } 690035918f85SRandall Stewart /* 690135918f85SRandall Stewart * No locks required here since bind and mgmt_ep_sa all do their own 690235918f85SRandall Stewart * locking. If we do something for the FIX: below we may need to 690335918f85SRandall Stewart * lock in that case. 690435918f85SRandall Stewart */ 690535918f85SRandall Stewart if (assoc_id == 0) { 690635918f85SRandall Stewart /* add the address */ 690735918f85SRandall Stewart struct sctp_inpcb *lep; 690897c76f10SRandall Stewart struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse; 690935918f85SRandall Stewart 691097c76f10SRandall Stewart /* validate the incoming port */ 691197c76f10SRandall Stewart if ((lsin->sin_port != 0) && 691297c76f10SRandall Stewart (lsin->sin_port != inp->sctp_lport)) { 6913c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 691497c76f10SRandall Stewart *error = EINVAL; 691597c76f10SRandall Stewart return; 691697c76f10SRandall Stewart } else { 691797c76f10SRandall Stewart /* user specified 0 port, set it to existing port */ 691897c76f10SRandall Stewart lsin->sin_port = inp->sctp_lport; 691997c76f10SRandall Stewart } 692097c76f10SRandall Stewart 692135918f85SRandall Stewart lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id); 692235918f85SRandall Stewart if (lep != NULL) { 692335918f85SRandall Stewart /* 692435918f85SRandall Stewart * We must decrement the refcount since we have the 692535918f85SRandall Stewart * ep already and are binding. No remove going on 692635918f85SRandall Stewart * here. 692735918f85SRandall Stewart */ 69286d9e8f2bSRandall Stewart SCTP_INP_DECR_REF(lep); 692935918f85SRandall Stewart } 693035918f85SRandall Stewart if (lep == inp) { 693135918f85SRandall Stewart /* already bound to it.. ok */ 693235918f85SRandall Stewart return; 693335918f85SRandall Stewart } else if (lep == NULL) { 693435918f85SRandall Stewart ((struct sockaddr_in *)addr_touse)->sin_port = 0; 693535918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 693635918f85SRandall Stewart SCTP_ADD_IP_ADDRESS, 693780fefe0aSRandall Stewart vrf_id, NULL); 693835918f85SRandall Stewart } else { 693935918f85SRandall Stewart *error = EADDRINUSE; 694035918f85SRandall Stewart } 694135918f85SRandall Stewart if (*error) 694235918f85SRandall Stewart return; 694335918f85SRandall Stewart } else { 694435918f85SRandall Stewart /* 694535918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 694635918f85SRandall Stewart */ 694735918f85SRandall Stewart } 694835918f85SRandall Stewart } 694935918f85SRandall Stewart 695035918f85SRandall Stewart /* 695135918f85SRandall Stewart * sctp_bindx(DELETE) for one address. 695235918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 695335918f85SRandall Stewart */ 695435918f85SRandall Stewart void 69557215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp, 695635918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 695735918f85SRandall Stewart uint32_t vrf_id, int *error) 695835918f85SRandall Stewart { 695935918f85SRandall Stewart struct sockaddr *addr_touse; 6960d59107f7SMichael Tuexen #if defined(INET) && defined(INET6) 696135918f85SRandall Stewart struct sockaddr_in sin; 69625e2c2d87SRandall Stewart #endif 69635e2c2d87SRandall Stewart 696435918f85SRandall Stewart /* see if we're bound all already! */ 696535918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6966c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 696735918f85SRandall Stewart *error = EINVAL; 696835918f85SRandall Stewart return; 696935918f85SRandall Stewart } 697035918f85SRandall Stewart addr_touse = sa; 6971e0e00a4dSMichael Tuexen #ifdef INET6 697235918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 6973d59107f7SMichael Tuexen #ifdef INET 697435918f85SRandall Stewart struct sockaddr_in6 *sin6; 6975d59107f7SMichael Tuexen #endif 6976d59107f7SMichael Tuexen 697735918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6978c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 697935918f85SRandall Stewart *error = EINVAL; 698035918f85SRandall Stewart return; 698135918f85SRandall Stewart } 6982db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6983db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6984c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6985db4fd95bSRandall Stewart *error = EINVAL; 6986db4fd95bSRandall Stewart return; 6987db4fd95bSRandall Stewart } 6988d59107f7SMichael Tuexen #ifdef INET 698935918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 699035918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6991db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6992db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6993db4fd95bSRandall Stewart /* can't bind mapped-v4 on PF_INET sockets */ 6994c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6995db4fd95bSRandall Stewart *error = EINVAL; 6996db4fd95bSRandall Stewart return; 6997db4fd95bSRandall Stewart } 699835918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 699935918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 700035918f85SRandall Stewart } 7001d59107f7SMichael Tuexen #endif 700235918f85SRandall Stewart } 700335918f85SRandall Stewart #endif 7004ea5eba11SMichael Tuexen #ifdef INET 700535918f85SRandall Stewart if (sa->sa_family == AF_INET) { 700635918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 7007c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 700835918f85SRandall Stewart *error = EINVAL; 700935918f85SRandall Stewart return; 701035918f85SRandall Stewart } 7011db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 7012db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 7013db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 7014c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 7015db4fd95bSRandall Stewart *error = EINVAL; 7016db4fd95bSRandall Stewart return; 7017db4fd95bSRandall Stewart } 701835918f85SRandall Stewart } 7019ea5eba11SMichael Tuexen #endif 702035918f85SRandall Stewart /* 702135918f85SRandall Stewart * No lock required mgmt_ep_sa does its own locking. If the FIX: 702235918f85SRandall Stewart * below is ever changed we may need to lock before calling 702335918f85SRandall Stewart * association level binding. 702435918f85SRandall Stewart */ 702535918f85SRandall Stewart if (assoc_id == 0) { 702635918f85SRandall Stewart /* delete the address */ 702735918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 702835918f85SRandall Stewart SCTP_DEL_IP_ADDRESS, 702980fefe0aSRandall Stewart vrf_id, NULL); 703035918f85SRandall Stewart } else { 703135918f85SRandall Stewart /* 703235918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 703335918f85SRandall Stewart */ 703435918f85SRandall Stewart } 703535918f85SRandall Stewart } 70361b649582SRandall Stewart 70371b649582SRandall Stewart /* 70381b649582SRandall Stewart * returns the valid local address count for an assoc, taking into account 70391b649582SRandall Stewart * all scoping rules 70401b649582SRandall Stewart */ 70411b649582SRandall Stewart int 70421b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb) 70431b649582SRandall Stewart { 7044b54ddf22SMichael Tuexen int loopback_scope; 7045b54ddf22SMichael Tuexen #if defined(INET) 7046b54ddf22SMichael Tuexen int ipv4_local_scope, ipv4_addr_legal; 7047b54ddf22SMichael Tuexen #endif 7048b54ddf22SMichael Tuexen #if defined (INET6) 7049b54ddf22SMichael Tuexen int local_scope, site_scope, ipv6_addr_legal; 7050b54ddf22SMichael Tuexen #endif 70511b649582SRandall Stewart struct sctp_vrf *vrf; 70521b649582SRandall Stewart struct sctp_ifn *sctp_ifn; 70531b649582SRandall Stewart struct sctp_ifa *sctp_ifa; 70541b649582SRandall Stewart int count = 0; 70551b649582SRandall Stewart 70561b649582SRandall Stewart /* Turn on all the appropriate scopes */ 7057a1cb341bSMichael Tuexen loopback_scope = stcb->asoc.scope.loopback_scope; 7058b54ddf22SMichael Tuexen #if defined(INET) 7059a1cb341bSMichael Tuexen ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; 7060b54ddf22SMichael Tuexen ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; 7061b54ddf22SMichael Tuexen #endif 7062b54ddf22SMichael Tuexen #if defined(INET6) 7063a1cb341bSMichael Tuexen local_scope = stcb->asoc.scope.local_scope; 7064a1cb341bSMichael Tuexen site_scope = stcb->asoc.scope.site_scope; 7065a1cb341bSMichael Tuexen ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; 7066b54ddf22SMichael Tuexen #endif 7067c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 70681b649582SRandall Stewart vrf = sctp_find_vrf(stcb->asoc.vrf_id); 70691b649582SRandall Stewart if (vrf == NULL) { 70701b649582SRandall Stewart /* no vrf, no addresses */ 7071c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 70721b649582SRandall Stewart return (0); 70731b649582SRandall Stewart } 70740053ed28SMichael Tuexen 70751b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 70761b649582SRandall Stewart /* 70771b649582SRandall Stewart * bound all case: go through all ifns on the vrf 70781b649582SRandall Stewart */ 70791b649582SRandall Stewart LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 70801b649582SRandall Stewart if ((loopback_scope == 0) && 70811b649582SRandall Stewart SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 70821b649582SRandall Stewart continue; 70831b649582SRandall Stewart } 70841b649582SRandall Stewart LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 70851b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, sctp_ifa)) 70861b649582SRandall Stewart continue; 70875e2c2d87SRandall Stewart switch (sctp_ifa->address.sa.sa_family) { 7088ea5eba11SMichael Tuexen #ifdef INET 70895e2c2d87SRandall Stewart case AF_INET: 70905e2c2d87SRandall Stewart if (ipv4_addr_legal) { 70911b649582SRandall Stewart struct sockaddr_in *sin; 70921b649582SRandall Stewart 709324aaac8dSMichael Tuexen sin = &sctp_ifa->address.sin; 70941b649582SRandall Stewart if (sin->sin_addr.s_addr == 0) { 7095b7b84c0eSMichael Tuexen /* 7096b7b84c0eSMichael Tuexen * skip unspecified 7097b7b84c0eSMichael Tuexen * addrs 7098b7b84c0eSMichael Tuexen */ 70991b649582SRandall Stewart continue; 71001b649582SRandall Stewart } 71016ba22f19SMichael Tuexen if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, 71026ba22f19SMichael Tuexen &sin->sin_addr) != 0) { 71036ba22f19SMichael Tuexen continue; 71046ba22f19SMichael Tuexen } 71051b649582SRandall Stewart if ((ipv4_local_scope == 0) && 71061b649582SRandall Stewart (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 71071b649582SRandall Stewart continue; 71081b649582SRandall Stewart } 71091b649582SRandall Stewart /* count this one */ 71101b649582SRandall Stewart count++; 71115e2c2d87SRandall Stewart } else { 71125e2c2d87SRandall Stewart continue; 71135e2c2d87SRandall Stewart } 71145e2c2d87SRandall Stewart break; 7115ea5eba11SMichael Tuexen #endif 71165e2c2d87SRandall Stewart #ifdef INET6 71175e2c2d87SRandall Stewart case AF_INET6: 71185e2c2d87SRandall Stewart if (ipv6_addr_legal) { 71191b649582SRandall Stewart struct sockaddr_in6 *sin6; 71201b649582SRandall Stewart 712124aaac8dSMichael Tuexen sin6 = &sctp_ifa->address.sin6; 71221b649582SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 71231b649582SRandall Stewart continue; 71241b649582SRandall Stewart } 71256ba22f19SMichael Tuexen if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, 71266ba22f19SMichael Tuexen &sin6->sin6_addr) != 0) { 71276ba22f19SMichael Tuexen continue; 71286ba22f19SMichael Tuexen } 71291b649582SRandall Stewart if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 71301b649582SRandall Stewart if (local_scope == 0) 71311b649582SRandall Stewart continue; 71321b649582SRandall Stewart if (sin6->sin6_scope_id == 0) { 71331b649582SRandall Stewart if (sa6_recoverscope(sin6) != 0) 71341b649582SRandall Stewart /* 71355e2c2d87SRandall Stewart * 71365e2c2d87SRandall Stewart * bad 71375b495f17SMichael Tuexen * link 71385e2c2d87SRandall Stewart * 71395b495f17SMichael Tuexen * local 71405e2c2d87SRandall Stewart * 71415b495f17SMichael Tuexen * address 71425b495f17SMichael Tuexen */ 71431b649582SRandall Stewart continue; 71441b649582SRandall Stewart } 71451b649582SRandall Stewart } 71461b649582SRandall Stewart if ((site_scope == 0) && 71471b649582SRandall Stewart (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 71481b649582SRandall Stewart continue; 71491b649582SRandall Stewart } 71501b649582SRandall Stewart /* count this one */ 71511b649582SRandall Stewart count++; 71521b649582SRandall Stewart } 71535e2c2d87SRandall Stewart break; 71545e2c2d87SRandall Stewart #endif 71555e2c2d87SRandall Stewart default: 71565e2c2d87SRandall Stewart /* TSNH */ 71575e2c2d87SRandall Stewart break; 71585e2c2d87SRandall Stewart } 71591b649582SRandall Stewart } 71601b649582SRandall Stewart } 71611b649582SRandall Stewart } else { 71621b649582SRandall Stewart /* 71631b649582SRandall Stewart * subset bound case 71641b649582SRandall Stewart */ 71651b649582SRandall Stewart struct sctp_laddr *laddr; 71661b649582SRandall Stewart 71671b649582SRandall Stewart LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, 71681b649582SRandall Stewart sctp_nxt_addr) { 71691b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 71701b649582SRandall Stewart continue; 71711b649582SRandall Stewart } 71721b649582SRandall Stewart /* count this one */ 71731b649582SRandall Stewart count++; 71741b649582SRandall Stewart } 71751b649582SRandall Stewart } 7176c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 71771b649582SRandall Stewart return (count); 71781b649582SRandall Stewart } 7179c4739e2fSRandall Stewart 7180c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF) 7181c4739e2fSRandall Stewart 7182c4739e2fSRandall Stewart void 7183b27a6b7dSRandall 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) 7184c4739e2fSRandall Stewart { 7185b27a6b7dSRandall Stewart uint32_t saveindex, newindex; 7186c4739e2fSRandall Stewart 7187c4739e2fSRandall Stewart do { 7188b3f1ea41SRandall Stewart saveindex = SCTP_BASE_SYSCTL(sctp_log).index; 7189c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 7190c4739e2fSRandall Stewart newindex = 1; 7191c4739e2fSRandall Stewart } else { 7192c4739e2fSRandall Stewart newindex = saveindex + 1; 7193c4739e2fSRandall Stewart } 7194b3f1ea41SRandall Stewart } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0); 7195c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 7196c4739e2fSRandall Stewart saveindex = 0; 7197c4739e2fSRandall Stewart } 7198b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; 7199b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys; 7200b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a; 7201b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b; 7202b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c; 7203b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d; 7204b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e; 7205b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f; 7206c4739e2fSRandall Stewart } 7207c4739e2fSRandall Stewart 7208c4739e2fSRandall Stewart #endif 7209a99b6783SRandall Stewart static void 72107cca1775SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, 721181d3ec17SBryan Venteicher const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) 7212a99b6783SRandall Stewart { 7213a99b6783SRandall Stewart struct ip *iph; 72143a51a264SMichael Tuexen #ifdef INET6 72153a51a264SMichael Tuexen struct ip6_hdr *ip6; 72163a51a264SMichael Tuexen #endif 7217a99b6783SRandall Stewart struct mbuf *sp, *last; 7218a99b6783SRandall Stewart struct udphdr *uhdr; 7219285052f0SMichael Tuexen uint16_t port; 7220a99b6783SRandall Stewart 7221a99b6783SRandall Stewart if ((m->m_flags & M_PKTHDR) == 0) { 7222a99b6783SRandall Stewart /* Can't handle one that is not a pkt hdr */ 7223a99b6783SRandall Stewart goto out; 7224a99b6783SRandall Stewart } 7225285052f0SMichael Tuexen /* Pull the src port */ 7226a99b6783SRandall Stewart iph = mtod(m, struct ip *); 7227a99b6783SRandall Stewart uhdr = (struct udphdr *)((caddr_t)iph + off); 7228a99b6783SRandall Stewart port = uhdr->uh_sport; 7229285052f0SMichael Tuexen /* 7230285052f0SMichael Tuexen * Split out the mbuf chain. Leave the IP header in m, place the 7231285052f0SMichael Tuexen * rest in the sp. 7232285052f0SMichael Tuexen */ 7233eb1b1807SGleb Smirnoff sp = m_split(m, off, M_NOWAIT); 7234a99b6783SRandall Stewart if (sp == NULL) { 7235a99b6783SRandall Stewart /* Gak, drop packet, we can't do a split */ 7236a99b6783SRandall Stewart goto out; 7237a99b6783SRandall Stewart } 7238285052f0SMichael Tuexen if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) { 7239285052f0SMichael Tuexen /* Gak, packet can't have an SCTP header in it - too small */ 7240a99b6783SRandall Stewart m_freem(sp); 7241a99b6783SRandall Stewart goto out; 7242a99b6783SRandall Stewart } 7243285052f0SMichael Tuexen /* Now pull up the UDP header and SCTP header together */ 7244285052f0SMichael Tuexen sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr)); 7245a99b6783SRandall Stewart if (sp == NULL) { 7246a99b6783SRandall Stewart /* Gak pullup failed */ 7247a99b6783SRandall Stewart goto out; 7248a99b6783SRandall Stewart } 7249285052f0SMichael Tuexen /* Trim out the UDP header */ 7250a99b6783SRandall Stewart m_adj(sp, sizeof(struct udphdr)); 7251a99b6783SRandall Stewart 7252a99b6783SRandall Stewart /* Now reconstruct the mbuf chain */ 7253285052f0SMichael Tuexen for (last = m; last->m_next; last = last->m_next); 7254a99b6783SRandall Stewart last->m_next = sp; 7255a99b6783SRandall Stewart m->m_pkthdr.len += sp->m_pkthdr.len; 725652f175beSMichael Tuexen /* 725752f175beSMichael Tuexen * The CSUM_DATA_VALID flags indicates that the HW checked the UDP 725852f175beSMichael Tuexen * checksum and it was valid. Since CSUM_DATA_VALID == 725952f175beSMichael Tuexen * CSUM_SCTP_VALID this would imply that the HW also verified the 726052f175beSMichael Tuexen * SCTP checksum. Therefore, clear the bit. 726152f175beSMichael Tuexen */ 726252f175beSMichael Tuexen SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 726352f175beSMichael Tuexen "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n", 726452f175beSMichael Tuexen m->m_pkthdr.len, 726552f175beSMichael Tuexen if_name(m->m_pkthdr.rcvif), 726652f175beSMichael Tuexen (int)m->m_pkthdr.csum_flags, CSUM_BITS); 726752f175beSMichael Tuexen m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID; 7268a99b6783SRandall Stewart iph = mtod(m, struct ip *); 7269a99b6783SRandall Stewart switch (iph->ip_v) { 7270e6194c2eSMichael Tuexen #ifdef INET 7271a99b6783SRandall Stewart case IPVERSION: 727209c1c856SMichael Tuexen iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); 7273a99b6783SRandall Stewart sctp_input_with_port(m, off, port); 7274a99b6783SRandall Stewart break; 7275e6194c2eSMichael Tuexen #endif 7276a99b6783SRandall Stewart #ifdef INET6 7277a99b6783SRandall Stewart case IPV6_VERSION >> 4: 72783a51a264SMichael Tuexen ip6 = mtod(m, struct ip6_hdr *); 72793a51a264SMichael Tuexen ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr)); 72803a51a264SMichael Tuexen sctp6_input_with_port(&m, &off, port); 7281a99b6783SRandall Stewart break; 7282a99b6783SRandall Stewart #endif 7283a99b6783SRandall Stewart default: 7284285052f0SMichael Tuexen goto out; 7285a99b6783SRandall Stewart break; 7286a99b6783SRandall Stewart } 7287a99b6783SRandall Stewart return; 7288a99b6783SRandall Stewart out: 7289a99b6783SRandall Stewart m_freem(m); 7290a99b6783SRandall Stewart } 7291c54a18d2SRandall Stewart 7292fd7af143SMichael Tuexen #ifdef INET 7293fd7af143SMichael Tuexen static void 7294fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED) 7295fd7af143SMichael Tuexen { 7296fd7af143SMichael Tuexen struct ip *outer_ip, *inner_ip; 7297fd7af143SMichael Tuexen struct sctphdr *sh; 7298fd7af143SMichael Tuexen struct icmp *icmp; 7299fd7af143SMichael Tuexen struct udphdr *udp; 7300fd7af143SMichael Tuexen struct sctp_inpcb *inp; 7301fd7af143SMichael Tuexen struct sctp_tcb *stcb; 7302fd7af143SMichael Tuexen struct sctp_nets *net; 7303fd7af143SMichael Tuexen struct sctp_init_chunk *ch; 7304fd7af143SMichael Tuexen struct sockaddr_in src, dst; 7305fd7af143SMichael Tuexen uint8_t type, code; 7306fd7af143SMichael Tuexen 7307fd7af143SMichael Tuexen inner_ip = (struct ip *)vip; 7308fd7af143SMichael Tuexen icmp = (struct icmp *)((caddr_t)inner_ip - 7309fd7af143SMichael Tuexen (sizeof(struct icmp) - sizeof(struct ip))); 7310fd7af143SMichael Tuexen outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); 7311fd7af143SMichael Tuexen if (ntohs(outer_ip->ip_len) < 7312fd7af143SMichael Tuexen sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { 7313fd7af143SMichael Tuexen return; 7314fd7af143SMichael Tuexen } 7315fd7af143SMichael Tuexen udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); 7316fd7af143SMichael Tuexen sh = (struct sctphdr *)(udp + 1); 7317fd7af143SMichael Tuexen memset(&src, 0, sizeof(struct sockaddr_in)); 7318fd7af143SMichael Tuexen src.sin_family = AF_INET; 7319fd7af143SMichael Tuexen src.sin_len = sizeof(struct sockaddr_in); 7320fd7af143SMichael Tuexen src.sin_port = sh->src_port; 7321fd7af143SMichael Tuexen src.sin_addr = inner_ip->ip_src; 7322fd7af143SMichael Tuexen memset(&dst, 0, sizeof(struct sockaddr_in)); 7323fd7af143SMichael Tuexen dst.sin_family = AF_INET; 7324fd7af143SMichael Tuexen dst.sin_len = sizeof(struct sockaddr_in); 7325fd7af143SMichael Tuexen dst.sin_port = sh->dest_port; 7326fd7af143SMichael Tuexen dst.sin_addr = inner_ip->ip_dst; 7327fd7af143SMichael Tuexen /* 7328fd7af143SMichael Tuexen * 'dst' holds the dest of the packet that failed to be sent. 'src' 7329fd7af143SMichael Tuexen * holds our local endpoint address. Thus we reverse the dst and the 7330fd7af143SMichael Tuexen * src in the lookup. 7331fd7af143SMichael Tuexen */ 7332fd7af143SMichael Tuexen inp = NULL; 7333fd7af143SMichael Tuexen net = NULL; 7334fd7af143SMichael Tuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, 7335fd7af143SMichael Tuexen (struct sockaddr *)&src, 7336fd7af143SMichael Tuexen &inp, &net, 1, 7337fd7af143SMichael Tuexen SCTP_DEFAULT_VRFID); 7338fd7af143SMichael Tuexen if ((stcb != NULL) && 7339fd7af143SMichael Tuexen (net != NULL) && 734055b8cd93SMichael Tuexen (inp != NULL)) { 7341fd7af143SMichael Tuexen /* Check the UDP port numbers */ 7342fd7af143SMichael Tuexen if ((udp->uh_dport != net->port) || 7343fd7af143SMichael Tuexen (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { 7344fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7345fd7af143SMichael Tuexen return; 7346fd7af143SMichael Tuexen } 7347fd7af143SMichael Tuexen /* Check the verification tag */ 7348fd7af143SMichael Tuexen if (ntohl(sh->v_tag) != 0) { 7349fd7af143SMichael Tuexen /* 7350fd7af143SMichael Tuexen * This must be the verification tag used for 7351fd7af143SMichael Tuexen * sending out packets. We don't consider packets 7352fd7af143SMichael Tuexen * reflecting the verification tag. 7353fd7af143SMichael Tuexen */ 7354fd7af143SMichael Tuexen if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { 7355fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7356fd7af143SMichael Tuexen return; 7357fd7af143SMichael Tuexen } 7358fd7af143SMichael Tuexen } else { 7359fd7af143SMichael Tuexen if (ntohs(outer_ip->ip_len) >= 7360fd7af143SMichael Tuexen sizeof(struct ip) + 7361fd7af143SMichael Tuexen 8 + (inner_ip->ip_hl << 2) + 8 + 20) { 7362fd7af143SMichael Tuexen /* 7363fd7af143SMichael Tuexen * In this case we can check if we got an 7364fd7af143SMichael Tuexen * INIT chunk and if the initiate tag 7365fd7af143SMichael Tuexen * matches. 7366fd7af143SMichael Tuexen */ 7367fd7af143SMichael Tuexen ch = (struct sctp_init_chunk *)(sh + 1); 7368fd7af143SMichael Tuexen if ((ch->ch.chunk_type != SCTP_INITIATION) || 7369fd7af143SMichael Tuexen (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { 7370fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7371fd7af143SMichael Tuexen return; 7372fd7af143SMichael Tuexen } 7373fd7af143SMichael Tuexen } else { 7374fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7375fd7af143SMichael Tuexen return; 7376fd7af143SMichael Tuexen } 7377fd7af143SMichael Tuexen } 7378fd7af143SMichael Tuexen type = icmp->icmp_type; 7379fd7af143SMichael Tuexen code = icmp->icmp_code; 73803c3f9e2aSMichael Tuexen if ((type == ICMP_UNREACH) && 73813c3f9e2aSMichael Tuexen (code == ICMP_UNREACH_PORT)) { 7382fd7af143SMichael Tuexen code = ICMP_UNREACH_PROTOCOL; 7383fd7af143SMichael Tuexen } 7384fd7af143SMichael Tuexen sctp_notify(inp, stcb, net, type, code, 7385fd7af143SMichael Tuexen ntohs(inner_ip->ip_len), 73866ebfa5eeSMichael Tuexen (uint32_t)ntohs(icmp->icmp_nextmtu)); 7387fd7af143SMichael Tuexen } else { 7388fd7af143SMichael Tuexen if ((stcb == NULL) && (inp != NULL)) { 7389fd7af143SMichael Tuexen /* reduce ref-count */ 7390fd7af143SMichael Tuexen SCTP_INP_WLOCK(inp); 7391fd7af143SMichael Tuexen SCTP_INP_DECR_REF(inp); 7392fd7af143SMichael Tuexen SCTP_INP_WUNLOCK(inp); 7393fd7af143SMichael Tuexen } 7394fd7af143SMichael Tuexen if (stcb) { 7395fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7396fd7af143SMichael Tuexen } 7397fd7af143SMichael Tuexen } 7398fd7af143SMichael Tuexen return; 7399fd7af143SMichael Tuexen } 7400fd7af143SMichael Tuexen #endif 7401fd7af143SMichael Tuexen 7402fd7af143SMichael Tuexen #ifdef INET6 7403fd7af143SMichael Tuexen static void 7404fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED) 7405fd7af143SMichael Tuexen { 7406fd7af143SMichael Tuexen struct ip6ctlparam *ip6cp; 7407fd7af143SMichael Tuexen struct sctp_inpcb *inp; 7408fd7af143SMichael Tuexen struct sctp_tcb *stcb; 7409fd7af143SMichael Tuexen struct sctp_nets *net; 7410fd7af143SMichael Tuexen struct sctphdr sh; 7411fd7af143SMichael Tuexen struct udphdr udp; 7412fd7af143SMichael Tuexen struct sockaddr_in6 src, dst; 7413fd7af143SMichael Tuexen uint8_t type, code; 7414fd7af143SMichael Tuexen 7415fd7af143SMichael Tuexen ip6cp = (struct ip6ctlparam *)d; 7416fd7af143SMichael Tuexen /* 7417fd7af143SMichael Tuexen * XXX: We assume that when IPV6 is non NULL, M and OFF are valid. 7418fd7af143SMichael Tuexen */ 7419fd7af143SMichael Tuexen if (ip6cp->ip6c_m == NULL) { 7420fd7af143SMichael Tuexen return; 7421fd7af143SMichael Tuexen } 7422fd7af143SMichael Tuexen /* 7423fd7af143SMichael Tuexen * Check if we can safely examine the ports and the verification tag 7424fd7af143SMichael Tuexen * of the SCTP common header. 7425fd7af143SMichael Tuexen */ 7426fd7af143SMichael Tuexen if (ip6cp->ip6c_m->m_pkthdr.len < 7427fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr) + offsetof(struct sctphdr, checksum)) { 7428fd7af143SMichael Tuexen return; 7429fd7af143SMichael Tuexen } 7430fd7af143SMichael Tuexen /* Copy out the UDP header. */ 7431fd7af143SMichael Tuexen memset(&udp, 0, sizeof(struct udphdr)); 7432fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7433fd7af143SMichael Tuexen ip6cp->ip6c_off, 7434fd7af143SMichael Tuexen sizeof(struct udphdr), 7435fd7af143SMichael Tuexen (caddr_t)&udp); 7436fd7af143SMichael Tuexen /* Copy out the port numbers and the verification tag. */ 7437fd7af143SMichael Tuexen memset(&sh, 0, sizeof(struct sctphdr)); 7438fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7439fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr), 7440fd7af143SMichael Tuexen sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), 7441fd7af143SMichael Tuexen (caddr_t)&sh); 7442fd7af143SMichael Tuexen memset(&src, 0, sizeof(struct sockaddr_in6)); 7443fd7af143SMichael Tuexen src.sin6_family = AF_INET6; 7444fd7af143SMichael Tuexen src.sin6_len = sizeof(struct sockaddr_in6); 7445fd7af143SMichael Tuexen src.sin6_port = sh.src_port; 7446fd7af143SMichael Tuexen src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; 7447fd7af143SMichael Tuexen if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { 7448fd7af143SMichael Tuexen return; 7449fd7af143SMichael Tuexen } 7450fd7af143SMichael Tuexen memset(&dst, 0, sizeof(struct sockaddr_in6)); 7451fd7af143SMichael Tuexen dst.sin6_family = AF_INET6; 7452fd7af143SMichael Tuexen dst.sin6_len = sizeof(struct sockaddr_in6); 7453fd7af143SMichael Tuexen dst.sin6_port = sh.dest_port; 7454fd7af143SMichael Tuexen dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; 7455fd7af143SMichael Tuexen if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { 7456fd7af143SMichael Tuexen return; 7457fd7af143SMichael Tuexen } 7458fd7af143SMichael Tuexen inp = NULL; 7459fd7af143SMichael Tuexen net = NULL; 7460fd7af143SMichael Tuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, 7461fd7af143SMichael Tuexen (struct sockaddr *)&src, 7462fd7af143SMichael Tuexen &inp, &net, 1, SCTP_DEFAULT_VRFID); 7463fd7af143SMichael Tuexen if ((stcb != NULL) && 7464fd7af143SMichael Tuexen (net != NULL) && 746555b8cd93SMichael Tuexen (inp != NULL)) { 7466fd7af143SMichael Tuexen /* Check the UDP port numbers */ 7467fd7af143SMichael Tuexen if ((udp.uh_dport != net->port) || 7468fd7af143SMichael Tuexen (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { 7469fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7470fd7af143SMichael Tuexen return; 7471fd7af143SMichael Tuexen } 7472fd7af143SMichael Tuexen /* Check the verification tag */ 7473fd7af143SMichael Tuexen if (ntohl(sh.v_tag) != 0) { 7474fd7af143SMichael Tuexen /* 7475fd7af143SMichael Tuexen * This must be the verification tag used for 7476fd7af143SMichael Tuexen * sending out packets. We don't consider packets 7477fd7af143SMichael Tuexen * reflecting the verification tag. 7478fd7af143SMichael Tuexen */ 7479fd7af143SMichael Tuexen if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { 7480fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7481fd7af143SMichael Tuexen return; 7482fd7af143SMichael Tuexen } 7483fd7af143SMichael Tuexen } else { 7484fd7af143SMichael Tuexen if (ip6cp->ip6c_m->m_pkthdr.len >= 7485fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr) + 7486fd7af143SMichael Tuexen sizeof(struct sctphdr) + 7487fd7af143SMichael Tuexen sizeof(struct sctp_chunkhdr) + 7488fd7af143SMichael Tuexen offsetof(struct sctp_init, a_rwnd)) { 7489fd7af143SMichael Tuexen /* 7490fd7af143SMichael Tuexen * In this case we can check if we got an 7491fd7af143SMichael Tuexen * INIT chunk and if the initiate tag 7492fd7af143SMichael Tuexen * matches. 7493fd7af143SMichael Tuexen */ 7494fd7af143SMichael Tuexen uint32_t initiate_tag; 7495fd7af143SMichael Tuexen uint8_t chunk_type; 7496fd7af143SMichael Tuexen 7497fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7498fd7af143SMichael Tuexen ip6cp->ip6c_off + 7499fd7af143SMichael Tuexen sizeof(struct udphdr) + 7500fd7af143SMichael Tuexen sizeof(struct sctphdr), 7501fd7af143SMichael Tuexen sizeof(uint8_t), 7502fd7af143SMichael Tuexen (caddr_t)&chunk_type); 7503fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7504fd7af143SMichael Tuexen ip6cp->ip6c_off + 7505fd7af143SMichael Tuexen sizeof(struct udphdr) + 7506fd7af143SMichael Tuexen sizeof(struct sctphdr) + 7507fd7af143SMichael Tuexen sizeof(struct sctp_chunkhdr), 7508fd7af143SMichael Tuexen sizeof(uint32_t), 7509fd7af143SMichael Tuexen (caddr_t)&initiate_tag); 7510fd7af143SMichael Tuexen if ((chunk_type != SCTP_INITIATION) || 7511fd7af143SMichael Tuexen (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { 7512fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7513fd7af143SMichael Tuexen return; 7514fd7af143SMichael Tuexen } 7515fd7af143SMichael Tuexen } else { 7516fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7517fd7af143SMichael Tuexen return; 7518fd7af143SMichael Tuexen } 7519fd7af143SMichael Tuexen } 7520fd7af143SMichael Tuexen type = ip6cp->ip6c_icmp6->icmp6_type; 7521fd7af143SMichael Tuexen code = ip6cp->ip6c_icmp6->icmp6_code; 7522fd7af143SMichael Tuexen if ((type == ICMP6_DST_UNREACH) && 7523fd7af143SMichael Tuexen (code == ICMP6_DST_UNREACH_NOPORT)) { 7524fd7af143SMichael Tuexen type = ICMP6_PARAM_PROB; 7525fd7af143SMichael Tuexen code = ICMP6_PARAMPROB_NEXTHEADER; 7526fd7af143SMichael Tuexen } 7527fd7af143SMichael Tuexen sctp6_notify(inp, stcb, net, type, code, 75286ebfa5eeSMichael Tuexen ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); 7529fd7af143SMichael Tuexen } else { 7530fd7af143SMichael Tuexen if ((stcb == NULL) && (inp != NULL)) { 7531fd7af143SMichael Tuexen /* reduce inp's ref-count */ 7532fd7af143SMichael Tuexen SCTP_INP_WLOCK(inp); 7533fd7af143SMichael Tuexen SCTP_INP_DECR_REF(inp); 7534fd7af143SMichael Tuexen SCTP_INP_WUNLOCK(inp); 7535fd7af143SMichael Tuexen } 7536fd7af143SMichael Tuexen if (stcb) { 7537fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7538fd7af143SMichael Tuexen } 7539fd7af143SMichael Tuexen } 7540fd7af143SMichael Tuexen } 7541fd7af143SMichael Tuexen #endif 7542fd7af143SMichael Tuexen 7543c54a18d2SRandall Stewart void 7544c54a18d2SRandall Stewart sctp_over_udp_stop(void) 7545c54a18d2SRandall Stewart { 7546a99b6783SRandall Stewart /* 7547a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 7548a99b6783SRandall Stewart * for writting! 7549a99b6783SRandall Stewart */ 75503a51a264SMichael Tuexen #ifdef INET 75513a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { 75523a51a264SMichael Tuexen soclose(SCTP_BASE_INFO(udp4_tun_socket)); 75533a51a264SMichael Tuexen SCTP_BASE_INFO(udp4_tun_socket) = NULL; 7554c54a18d2SRandall Stewart } 75553a51a264SMichael Tuexen #endif 75563a51a264SMichael Tuexen #ifdef INET6 75573a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { 75583a51a264SMichael Tuexen soclose(SCTP_BASE_INFO(udp6_tun_socket)); 75593a51a264SMichael Tuexen SCTP_BASE_INFO(udp6_tun_socket) = NULL; 75603a51a264SMichael Tuexen } 75613a51a264SMichael Tuexen #endif 7562a99b6783SRandall Stewart } 7563ea5eba11SMichael Tuexen 7564c54a18d2SRandall Stewart int 7565c54a18d2SRandall Stewart sctp_over_udp_start(void) 7566c54a18d2SRandall Stewart { 7567a99b6783SRandall Stewart uint16_t port; 7568a99b6783SRandall Stewart int ret; 75693a51a264SMichael Tuexen #ifdef INET 75703a51a264SMichael Tuexen struct sockaddr_in sin; 75713a51a264SMichael Tuexen #endif 75723a51a264SMichael Tuexen #ifdef INET6 75733a51a264SMichael Tuexen struct sockaddr_in6 sin6; 75743a51a264SMichael Tuexen #endif 7575a99b6783SRandall Stewart /* 7576a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 7577a99b6783SRandall Stewart * for writting! 7578a99b6783SRandall Stewart */ 7579a99b6783SRandall Stewart port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); 75803a51a264SMichael Tuexen if (ntohs(port) == 0) { 7581a99b6783SRandall Stewart /* Must have a port set */ 7582a99b6783SRandall Stewart return (EINVAL); 7583a99b6783SRandall Stewart } 75843a51a264SMichael Tuexen #ifdef INET 75853a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { 7586a99b6783SRandall Stewart /* Already running -- must stop first */ 7587a99b6783SRandall Stewart return (EALREADY); 7588a99b6783SRandall Stewart } 75893a51a264SMichael Tuexen #endif 75903a51a264SMichael Tuexen #ifdef INET6 75913a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { 75923a51a264SMichael Tuexen /* Already running -- must stop first */ 75933a51a264SMichael Tuexen return (EALREADY); 7594a99b6783SRandall Stewart } 75953a51a264SMichael Tuexen #endif 75963a51a264SMichael Tuexen #ifdef INET 75973a51a264SMichael Tuexen if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket), 75983a51a264SMichael Tuexen SOCK_DGRAM, IPPROTO_UDP, 75993a51a264SMichael Tuexen curthread->td_ucred, curthread))) { 7600a99b6783SRandall Stewart sctp_over_udp_stop(); 7601a99b6783SRandall Stewart return (ret); 7602a99b6783SRandall Stewart } 76033a51a264SMichael Tuexen /* Call the special UDP hook. */ 76043a51a264SMichael Tuexen if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket), 7605fd7af143SMichael Tuexen sctp_recv_udp_tunneled_packet, 7606fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet, 7607fd7af143SMichael Tuexen NULL))) { 76083a51a264SMichael Tuexen sctp_over_udp_stop(); 76093a51a264SMichael Tuexen return (ret); 76103a51a264SMichael Tuexen } 76113a51a264SMichael Tuexen /* Ok, we have a socket, bind it to the port. */ 76123a51a264SMichael Tuexen memset(&sin, 0, sizeof(struct sockaddr_in)); 76133a51a264SMichael Tuexen sin.sin_len = sizeof(struct sockaddr_in); 76143a51a264SMichael Tuexen sin.sin_family = AF_INET; 76153a51a264SMichael Tuexen sin.sin_port = htons(port); 76163a51a264SMichael Tuexen if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket), 76173a51a264SMichael Tuexen (struct sockaddr *)&sin, curthread))) { 76183a51a264SMichael Tuexen sctp_over_udp_stop(); 76193a51a264SMichael Tuexen return (ret); 76203a51a264SMichael Tuexen } 76213a51a264SMichael Tuexen #endif 76223a51a264SMichael Tuexen #ifdef INET6 76233a51a264SMichael Tuexen if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket), 76243a51a264SMichael Tuexen SOCK_DGRAM, IPPROTO_UDP, 76253a51a264SMichael Tuexen curthread->td_ucred, curthread))) { 76263a51a264SMichael Tuexen sctp_over_udp_stop(); 76273a51a264SMichael Tuexen return (ret); 76283a51a264SMichael Tuexen } 76293a51a264SMichael Tuexen /* Call the special UDP hook. */ 76303a51a264SMichael Tuexen if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket), 7631fd7af143SMichael Tuexen sctp_recv_udp_tunneled_packet, 7632fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet, 7633fd7af143SMichael Tuexen NULL))) { 76343a51a264SMichael Tuexen sctp_over_udp_stop(); 76353a51a264SMichael Tuexen return (ret); 76363a51a264SMichael Tuexen } 76373a51a264SMichael Tuexen /* Ok, we have a socket, bind it to the port. */ 76383a51a264SMichael Tuexen memset(&sin6, 0, sizeof(struct sockaddr_in6)); 76393a51a264SMichael Tuexen sin6.sin6_len = sizeof(struct sockaddr_in6); 76403a51a264SMichael Tuexen sin6.sin6_family = AF_INET6; 76413a51a264SMichael Tuexen sin6.sin6_port = htons(port); 76423a51a264SMichael Tuexen if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket), 76433a51a264SMichael Tuexen (struct sockaddr *)&sin6, curthread))) { 76443a51a264SMichael Tuexen sctp_over_udp_stop(); 76453a51a264SMichael Tuexen return (ret); 76463a51a264SMichael Tuexen } 76473a51a264SMichael Tuexen #endif 7648a99b6783SRandall Stewart return (0); 7649c54a18d2SRandall Stewart } 765010e0318aSMichael Tuexen 765110e0318aSMichael Tuexen /* 765210e0318aSMichael Tuexen * sctp_min_mtu ()returns the minimum of all non-zero arguments. 765310e0318aSMichael Tuexen * If all arguments are zero, zero is returned. 765410e0318aSMichael Tuexen */ 765510e0318aSMichael Tuexen uint32_t 7656b0471b4bSMichael Tuexen sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3) 7657b0471b4bSMichael Tuexen { 765810e0318aSMichael Tuexen if (mtu1 > 0) { 765910e0318aSMichael Tuexen if (mtu2 > 0) { 766010e0318aSMichael Tuexen if (mtu3 > 0) { 766110e0318aSMichael Tuexen return (min(mtu1, min(mtu2, mtu3))); 766210e0318aSMichael Tuexen } else { 766310e0318aSMichael Tuexen return (min(mtu1, mtu2)); 766410e0318aSMichael Tuexen } 766510e0318aSMichael Tuexen } else { 766610e0318aSMichael Tuexen if (mtu3 > 0) { 766710e0318aSMichael Tuexen return (min(mtu1, mtu3)); 766810e0318aSMichael Tuexen } else { 766910e0318aSMichael Tuexen return (mtu1); 767010e0318aSMichael Tuexen } 767110e0318aSMichael Tuexen } 767210e0318aSMichael Tuexen } else { 767310e0318aSMichael Tuexen if (mtu2 > 0) { 767410e0318aSMichael Tuexen if (mtu3 > 0) { 767510e0318aSMichael Tuexen return (min(mtu2, mtu3)); 767610e0318aSMichael Tuexen } else { 767710e0318aSMichael Tuexen return (mtu2); 767810e0318aSMichael Tuexen } 767910e0318aSMichael Tuexen } else { 768010e0318aSMichael Tuexen return (mtu3); 768110e0318aSMichael Tuexen } 768210e0318aSMichael Tuexen } 768310e0318aSMichael Tuexen } 768410e0318aSMichael Tuexen 768510e0318aSMichael Tuexen void 768610e0318aSMichael Tuexen sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu) 768710e0318aSMichael Tuexen { 768810e0318aSMichael Tuexen struct in_conninfo inc; 768910e0318aSMichael Tuexen 769010e0318aSMichael Tuexen memset(&inc, 0, sizeof(struct in_conninfo)); 769110e0318aSMichael Tuexen inc.inc_fibnum = fibnum; 769210e0318aSMichael Tuexen switch (addr->sa.sa_family) { 769310e0318aSMichael Tuexen #ifdef INET 769410e0318aSMichael Tuexen case AF_INET: 769510e0318aSMichael Tuexen inc.inc_faddr = addr->sin.sin_addr; 769610e0318aSMichael Tuexen break; 769710e0318aSMichael Tuexen #endif 769810e0318aSMichael Tuexen #ifdef INET6 769910e0318aSMichael Tuexen case AF_INET6: 770010e0318aSMichael Tuexen inc.inc_flags |= INC_ISIPV6; 770110e0318aSMichael Tuexen inc.inc6_faddr = addr->sin6.sin6_addr; 770210e0318aSMichael Tuexen break; 770310e0318aSMichael Tuexen #endif 770410e0318aSMichael Tuexen default: 770510e0318aSMichael Tuexen return; 770610e0318aSMichael Tuexen } 770710e0318aSMichael Tuexen tcp_hc_updatemtu(&inc, (u_long)mtu); 770810e0318aSMichael Tuexen } 770910e0318aSMichael Tuexen 771010e0318aSMichael Tuexen uint32_t 7711b0471b4bSMichael Tuexen sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum) 7712b0471b4bSMichael Tuexen { 771310e0318aSMichael Tuexen struct in_conninfo inc; 771410e0318aSMichael Tuexen 771510e0318aSMichael Tuexen memset(&inc, 0, sizeof(struct in_conninfo)); 771610e0318aSMichael Tuexen inc.inc_fibnum = fibnum; 771710e0318aSMichael Tuexen switch (addr->sa.sa_family) { 771810e0318aSMichael Tuexen #ifdef INET 771910e0318aSMichael Tuexen case AF_INET: 772010e0318aSMichael Tuexen inc.inc_faddr = addr->sin.sin_addr; 772110e0318aSMichael Tuexen break; 772210e0318aSMichael Tuexen #endif 772310e0318aSMichael Tuexen #ifdef INET6 772410e0318aSMichael Tuexen case AF_INET6: 772510e0318aSMichael Tuexen inc.inc_flags |= INC_ISIPV6; 772610e0318aSMichael Tuexen inc.inc6_faddr = addr->sin6.sin6_addr; 772710e0318aSMichael Tuexen break; 772810e0318aSMichael Tuexen #endif 772910e0318aSMichael Tuexen default: 773010e0318aSMichael Tuexen return (0); 773110e0318aSMichael Tuexen } 773210e0318aSMichael Tuexen return ((uint32_t)tcp_hc_getmtu(&inc)); 773310e0318aSMichael Tuexen } 77346ef849e6SMichael Tuexen 77351a0b0216SMichael Tuexen void 77361a0b0216SMichael Tuexen sctp_set_state(struct sctp_tcb *stcb, int new_state) 77371a0b0216SMichael Tuexen { 77381e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77391e88cc8bSMichael Tuexen int old_state = stcb->asoc.state; 77401e88cc8bSMichael Tuexen #endif 77411e88cc8bSMichael Tuexen 77421a0b0216SMichael Tuexen KASSERT((new_state & ~SCTP_STATE_MASK) == 0, 77431a0b0216SMichael Tuexen ("sctp_set_state: Can't set substate (new_state = %x)", 77441a0b0216SMichael Tuexen new_state)); 77451a0b0216SMichael Tuexen stcb->asoc.state = (stcb->asoc.state & ~SCTP_STATE_MASK) | new_state; 77461a0b0216SMichael Tuexen if ((new_state == SCTP_STATE_SHUTDOWN_RECEIVED) || 77471a0b0216SMichael Tuexen (new_state == SCTP_STATE_SHUTDOWN_SENT) || 77481a0b0216SMichael Tuexen (new_state == SCTP_STATE_SHUTDOWN_ACK_SENT)) { 77491a0b0216SMichael Tuexen SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); 77501a0b0216SMichael Tuexen } 77511e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77521e88cc8bSMichael Tuexen if (((old_state & SCTP_STATE_MASK) != new_state) && 77531e88cc8bSMichael Tuexen !(((old_state & SCTP_STATE_MASK) == SCTP_STATE_EMPTY) && 77541e88cc8bSMichael Tuexen (new_state == SCTP_STATE_INUSE))) { 77551e88cc8bSMichael Tuexen SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state); 77561e88cc8bSMichael Tuexen } 77571e88cc8bSMichael Tuexen #endif 77581a0b0216SMichael Tuexen } 77591a0b0216SMichael Tuexen 77601a0b0216SMichael Tuexen void 77611a0b0216SMichael Tuexen sctp_add_substate(struct sctp_tcb *stcb, int substate) 77621a0b0216SMichael Tuexen { 77631e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77641e88cc8bSMichael Tuexen int old_state = stcb->asoc.state; 77651e88cc8bSMichael Tuexen #endif 77661e88cc8bSMichael Tuexen 77671a0b0216SMichael Tuexen KASSERT((substate & SCTP_STATE_MASK) == 0, 77681a0b0216SMichael Tuexen ("sctp_add_substate: Can't set state (substate = %x)", 77691a0b0216SMichael Tuexen substate)); 77701a0b0216SMichael Tuexen stcb->asoc.state |= substate; 77711e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77721e88cc8bSMichael Tuexen if (((substate & SCTP_STATE_ABOUT_TO_BE_FREED) && 77731e88cc8bSMichael Tuexen ((old_state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) || 77741e88cc8bSMichael Tuexen ((substate & SCTP_STATE_SHUTDOWN_PENDING) && 77751e88cc8bSMichael Tuexen ((old_state & SCTP_STATE_SHUTDOWN_PENDING) == 0))) { 77761e88cc8bSMichael Tuexen SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state); 77771e88cc8bSMichael Tuexen } 77781e88cc8bSMichael Tuexen #endif 77791a0b0216SMichael Tuexen } 7780