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 1604a412576eSMichael Tuexen /*- 1605a412576eSMichael Tuexen * The following table shows which pointers for the inp, stcb, or net are 1606a412576eSMichael Tuexen * stored for each timer after it was started. 1607a412576eSMichael Tuexen * 1608a412576eSMichael Tuexen *|Name |Timer |inp |stcb|net | 1609a412576eSMichael Tuexen *|-----------------------------|-----------------------------|----|----|----| 1610a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SEND |net->rxt_timer |Yes |Yes |Yes | 1611a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_INIT |net->rxt_timer |Yes |Yes |Yes | 1612a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_RECV |stcb->asoc.dack_timer |Yes |Yes |No | 1613a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SHUTDOWN |net->rxt_timer |Yes |Yes |Yes | 1614a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_HEARTBEAT |net->hb_timer |Yes |Yes |Yes | 1615a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_COOKIE |net->rxt_timer |Yes |Yes |Yes | 1616a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_NEWCOOKIE |inp->sctp_ep.signature_change|Yes |No |No | 1617a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_PATHMTURAISE |net->pmtu_timer |Yes |Yes |Yes | 1618a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SHUTDOWNACK |net->rxt_timer |Yes |Yes |Yes | 1619a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_ASCONF |stcb->asoc.asconf_timer |Yes |Yes |Yes | 1620a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_SHUTDOWNGUARD|stcb->asoc.shut_guard_timer |Yes |Yes |No | 1621a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_AUTOCLOSE |stcb->asoc.autoclose_timer |Yes |Yes |No | 1622a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_STRRESET |stcb->asoc.strreset_timer |Yes |Yes |No | 1623a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_INPKILL |inp->sctp_ep.signature_change|Yes |No |No | 1624a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_ASOCKILL |stcb->asoc.strreset_timer |Yes |Yes |No | 1625a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_ADDR_WQ |SCTP_BASE_INFO(addr_wq_timer)|No |No |No | 1626a412576eSMichael Tuexen *|SCTP_TIMER_TYPE_PRIM_DELETED |stcb->asoc.delete_prim_timer |Yes |Yes |No | 1627a412576eSMichael Tuexen */ 1628a412576eSMichael Tuexen 1629f8829a4aSRandall Stewart void 1630f8829a4aSRandall Stewart sctp_timeout_handler(void *t) 1631f8829a4aSRandall Stewart { 1632868b51f2SMichael Tuexen struct epoch_tracker et; 1633a412576eSMichael 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; 1644a412576eSMichael 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... */ 1659a412576eSMichael Tuexen KASSERT(tmr->self == tmr, ("tmr->self corrupted")); 1660a412576eSMichael Tuexen KASSERT(SCTP_IS_TIMER_TYPE_VALID(tmr->type), ("Invalid timer type %d", tmr->type)); 1661a412576eSMichael 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) && 1666a412576eSMichael Tuexen ((type != SCTP_TIMER_TYPE_INPKILL) && 1667a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_INIT) && 1668a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SEND) && 1669a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_RECV) && 1670a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_HEARTBEAT) && 1671a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SHUTDOWN) && 1672a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SHUTDOWNACK) && 1673a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) && 1674a412576eSMichael Tuexen (type != SCTP_TIMER_TYPE_ASOCKILL))) { 1675f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1676a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 167723e3c088SMichael Tuexen "Timer type %d handler exiting due to closed socket.\n", 1678a412576eSMichael Tuexen type); 1679e056fafdSMichael Tuexen CURVNET_RESTORE(); 1680f8829a4aSRandall Stewart return; 1681f8829a4aSRandall Stewart } 1682f8829a4aSRandall Stewart } 1683a412576eSMichael 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 } 1691a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 169223e3c088SMichael Tuexen "Timer type %d handler exiting due to CLOSED association.\n", 1693a412576eSMichael Tuexen type); 1694e056fafdSMichael Tuexen CURVNET_RESTORE(); 1695f8829a4aSRandall Stewart return; 1696f8829a4aSRandall Stewart } 1697f8829a4aSRandall Stewart } 1698a412576eSMichael Tuexen tmr->stopped_from = 0xa003; 1699*37686ccfSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, "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 } 1707a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 170823e3c088SMichael Tuexen "Timer type %d handler exiting due to not being active.\n", 1709a412576eSMichael Tuexen type); 1710e056fafdSMichael Tuexen CURVNET_RESTORE(); 1711f8829a4aSRandall Stewart return; 1712f8829a4aSRandall Stewart } 1713a412576eSMichael 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 } 1725a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 172623e3c088SMichael Tuexen "Timer type %d handler exiting due to CLOSED association.\n", 1727a412576eSMichael Tuexen type); 1728e056fafdSMichael Tuexen CURVNET_RESTORE(); 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 } 173644b7479bSRandall Stewart 1737*37686ccfSMichael Tuexen /* Record in stopped_from which timeout occurred. */ 1738*37686ccfSMichael Tuexen tmr->stopped_from = type; 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: 1758a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1759a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1760a412576eSMichael 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: 1794a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1795a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1796a412576eSMichael 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: 1807a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1808a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1809a412576eSMichael 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 1814a412576eSMichael 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: 1819a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1820a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1821a412576eSMichael Tuexen type, inp, stcb, net)); 1822a412576eSMichael Tuexen SCTP_STAT_INCR(sctps_timoshutdown); 1823a412576eSMichael 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: 1834a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1835a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1836a412576eSMichael 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: 1852a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1853a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1854a412576eSMichael Tuexen type, inp, stcb, net)); 1855a412576eSMichael Tuexen SCTP_STAT_INCR(sctps_timocookie); 1856a412576eSMichael 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: 1871a412576eSMichael Tuexen KASSERT(inp != NULL && stcb == NULL && net == NULL, 1872a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1873a412576eSMichael 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: 1893a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1894a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1895a412576eSMichael 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: 1901a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1902a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1903a412576eSMichael 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: 1916a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net != NULL, 1917a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1918a412576eSMichael Tuexen type, inp, stcb, net)); 1919a412576eSMichael 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: 1930a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1931a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1932a412576eSMichael 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: 1940a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1941a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1942a412576eSMichael 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: 1949a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1950a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1951a412576eSMichael Tuexen type, inp, stcb, net)); 1952a412576eSMichael 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: 1960a412576eSMichael Tuexen KASSERT(inp != NULL && stcb == NULL && net == NULL, 1961a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1962a412576eSMichael 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); 1970a412576eSMichael Tuexen SCTP_INP_DECR_REF(inp); 1971a412576eSMichael 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: 1977a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 1978a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 1979a412576eSMichael 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: 2005a412576eSMichael Tuexen KASSERT(inp == NULL && stcb == NULL && net == NULL, 2006a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 2007a412576eSMichael Tuexen type, inp, stcb, net)); 20080554e01dSMichael Tuexen sctp_handle_addr_wq(); 20090554e01dSMichael Tuexen break; 20100554e01dSMichael Tuexen case SCTP_TIMER_TYPE_PRIM_DELETED: 2011a412576eSMichael Tuexen KASSERT(inp != NULL && stcb != NULL && net == NULL, 2012a412576eSMichael Tuexen ("timeout of type %d: inp = %p, stcb = %p, net = %p", 2013a412576eSMichael Tuexen type, inp, stcb, net)); 20140554e01dSMichael Tuexen SCTP_STAT_INCR(sctps_timodelprim); 2015a412576eSMichael Tuexen sctp_delete_prim_timer(inp, stcb); 20160554e01dSMichael Tuexen break; 2017f8829a4aSRandall Stewart default: 20187522682eSMichael Tuexen #ifdef INVARIANTS 2019a412576eSMichael Tuexen panic("Unknown timer type %d", type); 20207522682eSMichael Tuexen #else 20217522682eSMichael Tuexen goto get_out; 20227522682eSMichael Tuexen #endif 202360990c0cSMichael Tuexen } 2024f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 2025fa89f692SMichael Tuexen sctp_audit_log(0xF1, (uint8_t)type); 2026f8829a4aSRandall Stewart if (inp) 2027f8829a4aSRandall Stewart sctp_auditing(5, inp, stcb, net); 2028f8829a4aSRandall Stewart #endif 2029f8829a4aSRandall Stewart if ((did_output) && stcb) { 2030f8829a4aSRandall Stewart /* 2031f8829a4aSRandall Stewart * Now we need to clean up the control chunk chain if an 2032f8829a4aSRandall Stewart * ECNE is on it. It must be marked as UNSENT again so next 2033f8829a4aSRandall Stewart * call will continue to send it until such time that we get 2034f8829a4aSRandall Stewart * a CWR, to remove it. It is, however, less likely that we 2035f8829a4aSRandall Stewart * will find a ecn echo on the chain though. 2036f8829a4aSRandall Stewart */ 2037f8829a4aSRandall Stewart sctp_fix_ecn_echo(&stcb->asoc); 2038f8829a4aSRandall Stewart } 203944b7479bSRandall Stewart get_out: 2040f8829a4aSRandall Stewart if (stcb) { 2041f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 20422c62ba73SMichael Tuexen } else if (inp != NULL) { 20432c62ba73SMichael Tuexen SCTP_INP_WUNLOCK(inp); 20442c62ba73SMichael Tuexen } else { 20452c62ba73SMichael Tuexen SCTP_WQ_ADDR_UNLOCK(); 2046f8829a4aSRandall Stewart } 20472c62ba73SMichael Tuexen 2048f8829a4aSRandall Stewart out_decr: 2049f8829a4aSRandall Stewart if (inp) { 2050f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 2051f8829a4aSRandall Stewart } 20520053ed28SMichael Tuexen 2053f8829a4aSRandall Stewart out_no_decr: 205423e3c088SMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d handler finished.\n", type); 20558518270eSMichael Tuexen CURVNET_RESTORE(); 2056868b51f2SMichael Tuexen NET_EPOCH_EXIT(et); 2057f8829a4aSRandall Stewart } 2058f8829a4aSRandall Stewart 2059a412576eSMichael Tuexen /*- 2060a412576eSMichael Tuexen * The following table shows which parameters must be provided 2061a412576eSMichael Tuexen * when calling sctp_timer_start(). For parameters not being 2062a412576eSMichael Tuexen * provided, NULL must be used. 2063a412576eSMichael Tuexen * 2064a412576eSMichael Tuexen * |Name |inp |stcb|net | 2065a412576eSMichael Tuexen * |-----------------------------|----|----|----| 2066a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes | 2067a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes | 2068a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No | 2069a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes | 2070a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes | 2071a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes | 2072a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No | 2073a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes | 2074a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes | 2075a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |Yes | 2076a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No | 2077a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No | 2078a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |Yes | 2079a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No | 2080a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No | 2081a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No | 2082a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No | 2083a412576eSMichael Tuexen * 2084a412576eSMichael Tuexen */ 2085a412576eSMichael Tuexen 2086ad81507eSRandall Stewart void 2087f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2088f8829a4aSRandall Stewart struct sctp_nets *net) 2089f8829a4aSRandall Stewart { 2090f8829a4aSRandall Stewart struct sctp_timer *tmr; 2091a412576eSMichael Tuexen uint32_t to_ticks; 2092a412576eSMichael Tuexen uint32_t rndval, jitter; 2093f8829a4aSRandall Stewart 2094f8829a4aSRandall Stewart tmr = NULL; 2095a412576eSMichael Tuexen to_ticks = 0; 2096a412576eSMichael Tuexen if (stcb != NULL) { 2097f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2098a412576eSMichael Tuexen } else if (inp != NULL) { 2099a412576eSMichael Tuexen SCTP_INP_WLOCK_ASSERT(inp); 2100a412576eSMichael Tuexen } else { 2101a412576eSMichael Tuexen SCTP_WQ_ADDR_LOCK_ASSERT(); 2102a412576eSMichael Tuexen } 2103a412576eSMichael Tuexen if (stcb != NULL) { 2104a412576eSMichael Tuexen /* 2105a412576eSMichael Tuexen * Don't restart timer on association that's about to be 2106a412576eSMichael Tuexen * killed. 2107a412576eSMichael Tuexen */ 2108a412576eSMichael Tuexen if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) && 2109a412576eSMichael Tuexen (t_type != SCTP_TIMER_TYPE_ASOCKILL)) { 2110a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2111*37686ccfSMichael Tuexen "Timer type %d not started: inp=%p, stcb=%p, net=%p (stcb deleted).\n", 2112a412576eSMichael Tuexen t_type, inp, stcb, net); 2113a412576eSMichael Tuexen return; 2114f8829a4aSRandall Stewart } 21159803f01cSMichael Tuexen /* Don't restart timer on net that's been removed. */ 21169803f01cSMichael Tuexen if (net != NULL && (net->dest_state & SCTP_ADDR_BEING_DELETED)) { 2117a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2118*37686ccfSMichael Tuexen "Timer type %d not started: inp=%p, stcb=%p, net=%p (net deleted).\n", 2119a412576eSMichael Tuexen t_type, inp, stcb, net); 21209803f01cSMichael Tuexen return; 21219803f01cSMichael Tuexen } 2122a412576eSMichael Tuexen } 2123f8829a4aSRandall Stewart switch (t_type) { 2124f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2125a412576eSMichael Tuexen /* Here we use the RTO timer. */ 2126a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2127a412576eSMichael Tuexen #ifdef INVARIANTS 2128a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2129a412576eSMichael Tuexen t_type, inp, stcb, net); 2130a412576eSMichael Tuexen #else 2131ad81507eSRandall Stewart return; 2132a412576eSMichael Tuexen #endif 2133f8829a4aSRandall Stewart } 2134f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2135f8829a4aSRandall Stewart if (net->RTO == 0) { 2136a412576eSMichael Tuexen to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2137f8829a4aSRandall Stewart } else { 2138a412576eSMichael Tuexen to_ticks = MSEC_TO_TICKS(net->RTO); 2139f8829a4aSRandall Stewart } 2140f8829a4aSRandall Stewart break; 2141f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2142f8829a4aSRandall Stewart /* 2143f8829a4aSRandall Stewart * Here we use the INIT timer default usually about 1 2144a412576eSMichael Tuexen * second. 2145f8829a4aSRandall Stewart */ 2146a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2147a412576eSMichael Tuexen #ifdef INVARIANTS 2148a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2149a412576eSMichael Tuexen t_type, inp, stcb, net); 2150a412576eSMichael Tuexen #else 2151ad81507eSRandall Stewart return; 2152a412576eSMichael Tuexen #endif 2153f8829a4aSRandall Stewart } 2154f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2155f8829a4aSRandall Stewart if (net->RTO == 0) { 2156f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2157f8829a4aSRandall Stewart } else { 2158f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2159f8829a4aSRandall Stewart } 2160f8829a4aSRandall Stewart break; 2161f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2162f8829a4aSRandall Stewart /* 2163a412576eSMichael Tuexen * Here we use the Delayed-Ack timer value from the inp, 2164f8829a4aSRandall Stewart * ususually about 200ms. 2165f8829a4aSRandall Stewart */ 2166a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2167a412576eSMichael Tuexen #ifdef INVARIANTS 2168a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2169a412576eSMichael Tuexen t_type, inp, stcb, net); 2170a412576eSMichael Tuexen #else 2171ad81507eSRandall Stewart return; 2172a412576eSMichael Tuexen #endif 2173f8829a4aSRandall Stewart } 2174f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2175f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack); 2176f8829a4aSRandall Stewart break; 2177f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2178f8829a4aSRandall Stewart /* Here we use the RTO of the destination. */ 2179a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2180a412576eSMichael Tuexen #ifdef INVARIANTS 2181a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2182a412576eSMichael Tuexen t_type, inp, stcb, net); 2183a412576eSMichael Tuexen #else 2184ad81507eSRandall Stewart return; 2185a412576eSMichael Tuexen #endif 2186f8829a4aSRandall Stewart } 2187a412576eSMichael Tuexen tmr = &net->rxt_timer; 2188f8829a4aSRandall Stewart if (net->RTO == 0) { 2189f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2190f8829a4aSRandall Stewart } else { 2191f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2192f8829a4aSRandall Stewart } 2193f8829a4aSRandall Stewart break; 2194f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2195f8829a4aSRandall Stewart /* 2196a412576eSMichael Tuexen * The net is used here so that we can add in the RTO. Even 2197f8829a4aSRandall Stewart * though we use a different timer. We also add the HB timer 2198f8829a4aSRandall Stewart * PLUS a random jitter. 2199f8829a4aSRandall Stewart */ 2200a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2201a412576eSMichael Tuexen #ifdef INVARIANTS 2202a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2203a412576eSMichael Tuexen t_type, inp, stcb, net); 2204a412576eSMichael Tuexen #else 2205ad81507eSRandall Stewart return; 2206a412576eSMichael Tuexen #endif 2207a412576eSMichael Tuexen } 2208ca85e948SMichael Tuexen if ((net->dest_state & SCTP_ADDR_NOHB) && 2209ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 2210a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2211*37686ccfSMichael Tuexen "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n", 2212a412576eSMichael Tuexen t_type, inp, stcb, net); 2213ad81507eSRandall Stewart return; 2214f8829a4aSRandall Stewart } 2215a412576eSMichael Tuexen tmr = &net->hb_timer; 2216f8829a4aSRandall Stewart if (net->RTO == 0) { 2217ca85e948SMichael Tuexen to_ticks = stcb->asoc.initial_rto; 2218f8829a4aSRandall Stewart } else { 2219ca85e948SMichael Tuexen to_ticks = net->RTO; 2220f8829a4aSRandall Stewart } 2221ca85e948SMichael Tuexen rndval = sctp_select_initial_TSN(&inp->sctp_ep); 2222ca85e948SMichael Tuexen jitter = rndval % to_ticks; 2223ca85e948SMichael Tuexen if (jitter >= (to_ticks >> 1)) { 2224ca85e948SMichael Tuexen to_ticks = to_ticks + (jitter - (to_ticks >> 1)); 2225f8829a4aSRandall Stewart } else { 2226ca85e948SMichael Tuexen to_ticks = to_ticks - jitter; 2227f8829a4aSRandall Stewart } 2228ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 2229ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_PF)) { 2230ca85e948SMichael Tuexen to_ticks += net->heart_beat_delay; 2231f8829a4aSRandall Stewart } 2232f8829a4aSRandall Stewart /* 2233a412576eSMichael Tuexen * Now we must convert the to_ticks that are now in ms to 2234a412576eSMichael Tuexen * ticks. 2235f8829a4aSRandall Stewart */ 2236f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(to_ticks); 2237f8829a4aSRandall Stewart break; 2238f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2239f8829a4aSRandall Stewart /* 2240f8829a4aSRandall Stewart * Here we can use the RTO timer from the network since one 2241a412576eSMichael Tuexen * RTT was complete. If a retransmission happened then we 2242a412576eSMichael Tuexen * will be using the RTO initial value. 2243f8829a4aSRandall Stewart */ 2244a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2245a412576eSMichael Tuexen #ifdef INVARIANTS 2246a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2247a412576eSMichael Tuexen t_type, inp, stcb, net); 2248a412576eSMichael Tuexen #else 2249ad81507eSRandall Stewart return; 2250a412576eSMichael Tuexen #endif 2251f8829a4aSRandall Stewart } 2252a412576eSMichael Tuexen tmr = &net->rxt_timer; 2253f8829a4aSRandall Stewart if (net->RTO == 0) { 2254f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2255f8829a4aSRandall Stewart } else { 2256f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2257f8829a4aSRandall Stewart } 2258f8829a4aSRandall Stewart break; 2259f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2260f8829a4aSRandall Stewart /* 2261a412576eSMichael Tuexen * Nothing needed but the endpoint here ususually about 60 2262f8829a4aSRandall Stewart * minutes. 2263f8829a4aSRandall Stewart */ 2264a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2265a412576eSMichael Tuexen #ifdef INVARIANTS 2266a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2267a412576eSMichael Tuexen t_type, inp, stcb, net); 2268a412576eSMichael Tuexen #else 2269a412576eSMichael Tuexen return; 2270a412576eSMichael Tuexen #endif 2271a412576eSMichael Tuexen } 2272f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2273f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE]; 2274f8829a4aSRandall Stewart break; 2275f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2276f8829a4aSRandall Stewart /* 2277a412576eSMichael Tuexen * Here we use the value found in the EP for PMTUD, 2278a412576eSMichael Tuexen * ususually about 10 minutes. 2279f8829a4aSRandall Stewart */ 2280a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2281a412576eSMichael Tuexen #ifdef INVARIANTS 2282a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2283a412576eSMichael Tuexen t_type, inp, stcb, net); 2284a412576eSMichael Tuexen #else 2285ad81507eSRandall Stewart return; 2286a412576eSMichael Tuexen #endif 2287f8829a4aSRandall Stewart } 228880c79bbeSMichael Tuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 2289a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2290*37686ccfSMichael Tuexen "Timer type %d not started: inp=%p, stcb=%p, net=%p.\n", 2291a412576eSMichael Tuexen t_type, inp, stcb, net); 229280c79bbeSMichael Tuexen return; 229380c79bbeSMichael Tuexen } 2294f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2295a412576eSMichael Tuexen to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU]; 2296f8829a4aSRandall Stewart break; 2297f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2298a412576eSMichael Tuexen /* Here we use the RTO of the destination. */ 2299a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2300a412576eSMichael Tuexen #ifdef INVARIANTS 2301a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2302a412576eSMichael Tuexen t_type, inp, stcb, net); 2303a412576eSMichael Tuexen #else 2304ad81507eSRandall Stewart return; 2305a412576eSMichael Tuexen #endif 2306f8829a4aSRandall Stewart } 2307a412576eSMichael Tuexen tmr = &net->rxt_timer; 2308f8829a4aSRandall Stewart if (net->RTO == 0) { 2309f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2310f8829a4aSRandall Stewart } else { 2311f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2312f8829a4aSRandall Stewart } 2313f8829a4aSRandall Stewart break; 23140554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASCONF: 23150554e01dSMichael Tuexen /* 23160554e01dSMichael Tuexen * Here the timer comes from the stcb but its value is from 23170554e01dSMichael Tuexen * the net's RTO. 23180554e01dSMichael Tuexen */ 2319a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2320a412576eSMichael Tuexen #ifdef INVARIANTS 2321a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2322a412576eSMichael Tuexen t_type, inp, stcb, net); 2323a412576eSMichael Tuexen #else 23240554e01dSMichael Tuexen return; 2325a412576eSMichael Tuexen #endif 23260554e01dSMichael Tuexen } 2327a412576eSMichael Tuexen tmr = &stcb->asoc.asconf_timer; 23280554e01dSMichael Tuexen if (net->RTO == 0) { 23290554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 23300554e01dSMichael Tuexen } else { 23310554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(net->RTO); 23320554e01dSMichael Tuexen } 23330554e01dSMichael Tuexen break; 2334f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2335f8829a4aSRandall Stewart /* 2336f8829a4aSRandall Stewart * Here we use the endpoints shutdown guard timer usually 2337f8829a4aSRandall Stewart * about 3 minutes. 2338f8829a4aSRandall Stewart */ 2339a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2340a412576eSMichael Tuexen #ifdef INVARIANTS 2341a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2342a412576eSMichael Tuexen t_type, inp, stcb, net); 2343a412576eSMichael Tuexen #else 2344ad81507eSRandall Stewart return; 2345a412576eSMichael Tuexen #endif 2346f8829a4aSRandall Stewart } 2347a412576eSMichael Tuexen tmr = &stcb->asoc.shut_guard_timer; 23482e2d6794SMichael Tuexen if (inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN] == 0) { 23492e2d6794SMichael Tuexen to_ticks = 5 * MSEC_TO_TICKS(stcb->asoc.maxrto); 23502e2d6794SMichael Tuexen } else { 2351f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN]; 23522e2d6794SMichael Tuexen } 2353f8829a4aSRandall Stewart break; 23540554e01dSMichael Tuexen case SCTP_TIMER_TYPE_AUTOCLOSE: 2355a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2356a412576eSMichael Tuexen #ifdef INVARIANTS 2357a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2358a412576eSMichael Tuexen t_type, inp, stcb, net); 2359a412576eSMichael Tuexen #else 23600554e01dSMichael Tuexen return; 2361a412576eSMichael Tuexen #endif 23620554e01dSMichael Tuexen } 23630554e01dSMichael Tuexen tmr = &stcb->asoc.autoclose_timer; 2364a412576eSMichael Tuexen to_ticks = stcb->asoc.sctp_autoclose_ticks; 23650554e01dSMichael Tuexen break; 2366f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2367f8829a4aSRandall Stewart /* 23681b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 23691b649582SRandall Stewart * the net's RTO. 2370f8829a4aSRandall Stewart */ 2371a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2372a412576eSMichael Tuexen #ifdef INVARIANTS 2373a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2374a412576eSMichael Tuexen t_type, inp, stcb, net); 2375a412576eSMichael Tuexen #else 2376ad81507eSRandall Stewart return; 2377a412576eSMichael Tuexen #endif 2378f8829a4aSRandall Stewart } 2379a412576eSMichael Tuexen tmr = &stcb->asoc.strreset_timer; 2380f8829a4aSRandall Stewart if (net->RTO == 0) { 2381f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2382f8829a4aSRandall Stewart } else { 2383f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2384f8829a4aSRandall Stewart } 2385f8829a4aSRandall Stewart break; 23860554e01dSMichael Tuexen case SCTP_TIMER_TYPE_INPKILL: 2387f8829a4aSRandall Stewart /* 23880554e01dSMichael Tuexen * The inp is setup to die. We re-use the signature_chage 23890554e01dSMichael Tuexen * timer since that has stopped and we are in the GONE 23900554e01dSMichael Tuexen * state. 2391f8829a4aSRandall Stewart */ 2392a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2393a412576eSMichael Tuexen #ifdef INVARIANTS 2394a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2395a412576eSMichael Tuexen t_type, inp, stcb, net); 2396a412576eSMichael Tuexen #else 2397a412576eSMichael Tuexen return; 2398a412576eSMichael Tuexen #endif 2399a412576eSMichael Tuexen } 24000554e01dSMichael Tuexen tmr = &inp->sctp_ep.signature_change; 24010554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT); 24020554e01dSMichael Tuexen break; 24030554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASOCKILL: 2404a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2405a412576eSMichael Tuexen #ifdef INVARIANTS 2406a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2407a412576eSMichael Tuexen t_type, inp, stcb, net); 2408a412576eSMichael Tuexen #else 2409ad81507eSRandall Stewart return; 2410a412576eSMichael Tuexen #endif 2411f8829a4aSRandall Stewart } 24120554e01dSMichael Tuexen tmr = &stcb->asoc.strreset_timer; 24130554e01dSMichael Tuexen to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT); 24140554e01dSMichael Tuexen break; 24150554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ADDR_WQ: 2416a412576eSMichael Tuexen if ((inp != NULL) || (stcb != NULL) || (net != NULL)) { 2417a412576eSMichael Tuexen #ifdef INVARIANTS 2418a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2419a412576eSMichael Tuexen t_type, inp, stcb, net); 2420a412576eSMichael Tuexen #else 2421a412576eSMichael Tuexen return; 2422a412576eSMichael Tuexen #endif 2423a412576eSMichael Tuexen } 24240554e01dSMichael Tuexen /* Only 1 tick away :-) */ 24250554e01dSMichael Tuexen tmr = &SCTP_BASE_INFO(addr_wq_timer); 24260554e01dSMichael Tuexen to_ticks = SCTP_ADDRESS_TICK_DELAY; 2427f8829a4aSRandall Stewart break; 2428851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2429a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2430a412576eSMichael Tuexen #ifdef INVARIANTS 2431a412576eSMichael Tuexen panic("sctp_timer_start of type %d: inp = %p, stcb = %p, net = %p", 2432a412576eSMichael Tuexen t_type, inp, stcb, net); 2433a412576eSMichael Tuexen #else 2434851b7298SRandall Stewart return; 2435a412576eSMichael Tuexen #endif 2436851b7298SRandall Stewart } 2437851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2438a412576eSMichael Tuexen to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2439851b7298SRandall Stewart break; 2440f8829a4aSRandall Stewart default: 24417522682eSMichael Tuexen #ifdef INVARIANTS 2442a412576eSMichael Tuexen panic("Unknown timer type %d", t_type); 24437522682eSMichael Tuexen #else 24447522682eSMichael Tuexen return; 24457522682eSMichael Tuexen #endif 244660990c0cSMichael Tuexen } 2447a412576eSMichael Tuexen KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type)); 2448a412576eSMichael Tuexen KASSERT(to_ticks > 0, ("to_ticks == 0 for timer type %d", t_type)); 2449139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 2450f8829a4aSRandall Stewart /* 2451a412576eSMichael Tuexen * We do NOT allow you to have it already running. If it is, 2452a412576eSMichael Tuexen * we leave the current one up unchanged. 2453f8829a4aSRandall Stewart */ 2454a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2455*37686ccfSMichael Tuexen "Timer type %d already running: inp=%p, stcb=%p, net=%p.\n", 2456a412576eSMichael Tuexen t_type, inp, stcb, net); 2457ad81507eSRandall Stewart return; 2458f8829a4aSRandall Stewart } 2459a412576eSMichael Tuexen /* At this point we can proceed. */ 2460f8829a4aSRandall Stewart if (t_type == SCTP_TIMER_TYPE_SEND) { 2461f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up++; 2462f8829a4aSRandall Stewart } 2463a5d547adSRandall Stewart tmr->stopped_from = 0; 2464f8829a4aSRandall Stewart tmr->type = t_type; 2465f8829a4aSRandall Stewart tmr->ep = (void *)inp; 2466f8829a4aSRandall Stewart tmr->tcb = (void *)stcb; 2467a412576eSMichael Tuexen if (t_type == SCTP_TIMER_TYPE_STRRESET) { 2468a412576eSMichael Tuexen tmr->net = NULL; 2469a412576eSMichael Tuexen } else { 2470f8829a4aSRandall Stewart tmr->net = (void *)net; 2471a412576eSMichael Tuexen } 2472f8829a4aSRandall Stewart tmr->self = (void *)tmr; 24738518270eSMichael Tuexen tmr->vnet = (void *)curvnet; 2474c4739e2fSRandall Stewart tmr->ticks = sctp_get_tick_count(); 2475a412576eSMichael Tuexen if (SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr) == 0) { 2476a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2477*37686ccfSMichael Tuexen "Timer type %d started: ticks=%u, inp=%p, stcb=%p, net=%p.\n", 2478a412576eSMichael Tuexen t_type, to_ticks, inp, stcb, net); 2479a412576eSMichael Tuexen } else { 2480a412576eSMichael Tuexen /* 2481a412576eSMichael Tuexen * This should not happen, since we checked for pending 2482a412576eSMichael Tuexen * above. 2483a412576eSMichael Tuexen */ 2484a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2485*37686ccfSMichael Tuexen "Timer type %d restarted: ticks=%u, inp=%p, stcb=%p, net=%p.\n", 2486a412576eSMichael Tuexen t_type, to_ticks, inp, stcb, net); 2487a412576eSMichael Tuexen } 2488ad81507eSRandall Stewart return; 2489f8829a4aSRandall Stewart } 2490f8829a4aSRandall Stewart 2491a412576eSMichael Tuexen /*- 2492a412576eSMichael Tuexen * The following table shows which parameters must be provided 2493a412576eSMichael Tuexen * when calling sctp_timer_stop(). For parameters not being 2494a412576eSMichael Tuexen * provided, NULL must be used. 2495a412576eSMichael Tuexen * 2496a412576eSMichael Tuexen * |Name |inp |stcb|net | 2497a412576eSMichael Tuexen * |-----------------------------|----|----|----| 2498a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SEND |Yes |Yes |Yes | 2499a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INIT |Yes |Yes |Yes | 2500a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_RECV |Yes |Yes |No | 2501a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWN |Yes |Yes |Yes | 2502a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_HEARTBEAT |Yes |Yes |Yes | 2503a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_COOKIE |Yes |Yes |Yes | 2504a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_NEWCOOKIE |Yes |No |No | 2505a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PATHMTURAISE |Yes |Yes |Yes | 2506a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNACK |Yes |Yes |Yes | 2507a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASCONF |Yes |Yes |No | 2508a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_SHUTDOWNGUARD|Yes |Yes |No | 2509a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_AUTOCLOSE |Yes |Yes |No | 2510a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_STRRESET |Yes |Yes |No | 2511a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_INPKILL |Yes |No |No | 2512a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ASOCKILL |Yes |Yes |No | 2513a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_ADDR_WQ |No |No |No | 2514a412576eSMichael Tuexen * |SCTP_TIMER_TYPE_PRIM_DELETED |Yes |Yes |No | 2515a412576eSMichael Tuexen * 2516a412576eSMichael Tuexen */ 2517a412576eSMichael Tuexen 25186e55db54SRandall Stewart void 2519f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2520a5d547adSRandall Stewart struct sctp_nets *net, uint32_t from) 2521f8829a4aSRandall Stewart { 2522f8829a4aSRandall Stewart struct sctp_timer *tmr; 2523f8829a4aSRandall Stewart 2524a412576eSMichael Tuexen if (stcb != NULL) { 2525f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2526a412576eSMichael Tuexen } else if (inp != NULL) { 2527a412576eSMichael Tuexen SCTP_INP_WLOCK_ASSERT(inp); 2528a412576eSMichael Tuexen } else { 2529a412576eSMichael Tuexen SCTP_WQ_ADDR_LOCK_ASSERT(); 2530f8829a4aSRandall Stewart } 2531a412576eSMichael Tuexen tmr = NULL; 2532f8829a4aSRandall Stewart switch (t_type) { 2533f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2534a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2535a412576eSMichael Tuexen #ifdef INVARIANTS 2536a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2537a412576eSMichael Tuexen t_type, inp, stcb, net); 2538a412576eSMichael Tuexen #else 25396e55db54SRandall Stewart return; 2540a412576eSMichael Tuexen #endif 2541f8829a4aSRandall Stewart } 2542f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2543f8829a4aSRandall Stewart break; 2544f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2545a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2546a412576eSMichael Tuexen #ifdef INVARIANTS 2547a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2548a412576eSMichael Tuexen t_type, inp, stcb, net); 2549a412576eSMichael Tuexen #else 25506e55db54SRandall Stewart return; 2551a412576eSMichael Tuexen #endif 2552f8829a4aSRandall Stewart } 2553f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2554f8829a4aSRandall Stewart break; 2555f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2556a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2557a412576eSMichael Tuexen #ifdef INVARIANTS 2558a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2559a412576eSMichael Tuexen t_type, inp, stcb, net); 2560a412576eSMichael Tuexen #else 25616e55db54SRandall Stewart return; 2562a412576eSMichael Tuexen #endif 2563f8829a4aSRandall Stewart } 2564f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2565f8829a4aSRandall Stewart break; 2566f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2567a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2568a412576eSMichael Tuexen #ifdef INVARIANTS 2569a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2570a412576eSMichael Tuexen t_type, inp, stcb, net); 2571a412576eSMichael Tuexen #else 25726e55db54SRandall Stewart return; 2573a412576eSMichael Tuexen #endif 2574f8829a4aSRandall Stewart } 2575f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2576f8829a4aSRandall Stewart break; 2577f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2578a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2579a412576eSMichael Tuexen #ifdef INVARIANTS 2580a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2581a412576eSMichael Tuexen t_type, inp, stcb, net); 2582a412576eSMichael Tuexen #else 25836e55db54SRandall Stewart return; 2584a412576eSMichael Tuexen #endif 2585f8829a4aSRandall Stewart } 2586ca85e948SMichael Tuexen tmr = &net->hb_timer; 2587f8829a4aSRandall Stewart break; 2588f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2589a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2590a412576eSMichael Tuexen #ifdef INVARIANTS 2591a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2592a412576eSMichael Tuexen t_type, inp, stcb, net); 2593a412576eSMichael Tuexen #else 25946e55db54SRandall Stewart return; 2595a412576eSMichael Tuexen #endif 2596f8829a4aSRandall Stewart } 2597f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2598f8829a4aSRandall Stewart break; 2599f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2600a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2601a412576eSMichael Tuexen #ifdef INVARIANTS 2602a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2603a412576eSMichael Tuexen t_type, inp, stcb, net); 2604a412576eSMichael Tuexen #else 2605a412576eSMichael Tuexen return; 2606a412576eSMichael Tuexen #endif 2607a412576eSMichael Tuexen } 2608f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2609f8829a4aSRandall Stewart break; 2610f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2611a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2612a412576eSMichael Tuexen #ifdef INVARIANTS 2613a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2614a412576eSMichael Tuexen t_type, inp, stcb, net); 2615a412576eSMichael Tuexen #else 26166e55db54SRandall Stewart return; 2617a412576eSMichael Tuexen #endif 2618f8829a4aSRandall Stewart } 2619f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2620f8829a4aSRandall Stewart break; 2621f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2622a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 2623a412576eSMichael Tuexen #ifdef INVARIANTS 2624a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2625a412576eSMichael Tuexen t_type, inp, stcb, net); 2626a412576eSMichael Tuexen #else 26276e55db54SRandall Stewart return; 2628a412576eSMichael Tuexen #endif 2629f8829a4aSRandall Stewart } 2630f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2631f8829a4aSRandall Stewart break; 26320554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASCONF: 2633a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2634a412576eSMichael Tuexen #ifdef INVARIANTS 2635a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2636a412576eSMichael Tuexen t_type, inp, stcb, net); 2637a412576eSMichael Tuexen #else 26380554e01dSMichael Tuexen return; 2639a412576eSMichael Tuexen #endif 26400554e01dSMichael Tuexen } 26410554e01dSMichael Tuexen tmr = &stcb->asoc.asconf_timer; 26420554e01dSMichael Tuexen break; 2643f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2644a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2645a412576eSMichael Tuexen #ifdef INVARIANTS 2646a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2647a412576eSMichael Tuexen t_type, inp, stcb, net); 2648a412576eSMichael Tuexen #else 26496e55db54SRandall Stewart return; 2650a412576eSMichael Tuexen #endif 2651f8829a4aSRandall Stewart } 2652f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2653f8829a4aSRandall Stewart break; 26540554e01dSMichael Tuexen case SCTP_TIMER_TYPE_AUTOCLOSE: 2655a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2656a412576eSMichael Tuexen #ifdef INVARIANTS 2657a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2658a412576eSMichael Tuexen t_type, inp, stcb, net); 2659a412576eSMichael Tuexen #else 26600554e01dSMichael Tuexen return; 2661a412576eSMichael Tuexen #endif 26620554e01dSMichael Tuexen } 26630554e01dSMichael Tuexen tmr = &stcb->asoc.autoclose_timer; 26640554e01dSMichael Tuexen break; 2665f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2666a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2667a412576eSMichael Tuexen #ifdef INVARIANTS 2668a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2669a412576eSMichael Tuexen t_type, inp, stcb, net); 2670a412576eSMichael Tuexen #else 26716e55db54SRandall Stewart return; 2672a412576eSMichael Tuexen #endif 2673f8829a4aSRandall Stewart } 2674f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2675f8829a4aSRandall Stewart break; 26760554e01dSMichael Tuexen case SCTP_TIMER_TYPE_INPKILL: 26770554e01dSMichael Tuexen /* 26780554e01dSMichael Tuexen * The inp is setup to die. We re-use the signature_chage 26790554e01dSMichael Tuexen * timer since that has stopped and we are in the GONE 26800554e01dSMichael Tuexen * state. 26810554e01dSMichael Tuexen */ 2682a412576eSMichael Tuexen if ((inp == NULL) || (stcb != NULL) || (net != NULL)) { 2683a412576eSMichael Tuexen #ifdef INVARIANTS 2684a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2685a412576eSMichael Tuexen t_type, inp, stcb, net); 2686a412576eSMichael Tuexen #else 2687a412576eSMichael Tuexen return; 2688a412576eSMichael Tuexen #endif 2689a412576eSMichael Tuexen } 26900554e01dSMichael Tuexen tmr = &inp->sctp_ep.signature_change; 26910554e01dSMichael Tuexen break; 26920554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ASOCKILL: 2693a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2694a412576eSMichael Tuexen #ifdef INVARIANTS 2695a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2696a412576eSMichael Tuexen t_type, inp, stcb, net); 2697a412576eSMichael Tuexen #else 26986e55db54SRandall Stewart return; 2699a412576eSMichael Tuexen #endif 2700f8829a4aSRandall Stewart } 27010554e01dSMichael Tuexen tmr = &stcb->asoc.strreset_timer; 27020554e01dSMichael Tuexen break; 27030554e01dSMichael Tuexen case SCTP_TIMER_TYPE_ADDR_WQ: 2704a412576eSMichael Tuexen if ((inp != NULL) || (stcb != NULL) || (net != NULL)) { 2705a412576eSMichael Tuexen #ifdef INVARIANTS 2706a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2707a412576eSMichael Tuexen t_type, inp, stcb, net); 2708a412576eSMichael Tuexen #else 2709a412576eSMichael Tuexen return; 2710a412576eSMichael Tuexen #endif 2711a412576eSMichael Tuexen } 27120554e01dSMichael Tuexen tmr = &SCTP_BASE_INFO(addr_wq_timer); 2713f8829a4aSRandall Stewart break; 2714851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2715a412576eSMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net != NULL)) { 2716a412576eSMichael Tuexen #ifdef INVARIANTS 2717a412576eSMichael Tuexen panic("sctp_timer_stop of type %d: inp = %p, stcb = %p, net = %p", 2718a412576eSMichael Tuexen t_type, inp, stcb, net); 2719a412576eSMichael Tuexen #else 2720851b7298SRandall Stewart return; 2721a412576eSMichael Tuexen #endif 2722851b7298SRandall Stewart } 2723851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2724851b7298SRandall Stewart break; 2725f8829a4aSRandall Stewart default: 27267522682eSMichael Tuexen #ifdef INVARIANTS 2727a412576eSMichael Tuexen panic("Unknown timer type %d", t_type); 27287522682eSMichael Tuexen #else 27297522682eSMichael Tuexen return; 27307522682eSMichael Tuexen #endif 273160990c0cSMichael Tuexen } 2732a412576eSMichael Tuexen KASSERT(tmr != NULL, ("tmr is NULL for timer type %d", t_type)); 2733a412576eSMichael Tuexen if ((tmr->type != SCTP_TIMER_TYPE_NONE) && 2734a412576eSMichael Tuexen (tmr->type != t_type)) { 2735f8829a4aSRandall Stewart /* 2736f8829a4aSRandall Stewart * Ok we have a timer that is under joint use. Cookie timer 2737f8829a4aSRandall Stewart * per chance with the SEND timer. We therefore are NOT 2738f8829a4aSRandall Stewart * running the timer that the caller wants stopped. So just 2739f8829a4aSRandall Stewart * return. 2740f8829a4aSRandall Stewart */ 2741a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2742*37686ccfSMichael Tuexen "Shared timer type %d not running: inp=%p, stcb=%p, net=%p.\n", 2743a412576eSMichael Tuexen t_type, inp, stcb, net); 27446e55db54SRandall Stewart return; 2745f8829a4aSRandall Stewart } 2746ad81507eSRandall Stewart if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) { 2747f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 2748f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 2749f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 2750f8829a4aSRandall Stewart } 2751f8829a4aSRandall Stewart } 2752f8829a4aSRandall Stewart tmr->self = NULL; 2753a5d547adSRandall Stewart tmr->stopped_from = from; 2754a412576eSMichael Tuexen if (SCTP_OS_TIMER_STOP(&tmr->timer) == 1) { 2755a412576eSMichael Tuexen KASSERT(tmr->ep == inp, 2756a412576eSMichael Tuexen ("sctp_timer_stop of type %d: inp = %p, tmr->inp = %p", 2757a412576eSMichael Tuexen t_type, inp, tmr->ep)); 2758a412576eSMichael Tuexen KASSERT(tmr->tcb == stcb, 2759a412576eSMichael Tuexen ("sctp_timer_stop of type %d: stcb = %p, tmr->stcb = %p", 2760a412576eSMichael Tuexen t_type, stcb, tmr->tcb)); 2761a412576eSMichael Tuexen KASSERT(((t_type == SCTP_TIMER_TYPE_ASCONF) && (tmr->net != NULL)) || 2762a412576eSMichael Tuexen ((t_type != SCTP_TIMER_TYPE_ASCONF) && (tmr->net == net)), 2763a412576eSMichael Tuexen ("sctp_timer_stop of type %d: net = %p, tmr->net = %p", 2764a412576eSMichael Tuexen t_type, net, tmr->net)); 2765a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2766*37686ccfSMichael Tuexen "Timer type %d stopped: inp=%p, stcb=%p, net=%p.\n", 2767a412576eSMichael Tuexen t_type, inp, stcb, net); 2768a412576eSMichael Tuexen tmr->ep = NULL; 2769a412576eSMichael Tuexen tmr->tcb = NULL; 2770a412576eSMichael Tuexen tmr->net = NULL; 2771a412576eSMichael Tuexen } else { 2772a412576eSMichael Tuexen SCTPDBG(SCTP_DEBUG_TIMER2, 2773*37686ccfSMichael Tuexen "Timer type %d not stopped: inp=%p, stcb=%p, net=%p.\n", 2774a412576eSMichael Tuexen t_type, inp, stcb, net); 2775a412576eSMichael Tuexen } 27766e55db54SRandall Stewart return; 2777f8829a4aSRandall Stewart } 2778f8829a4aSRandall Stewart 2779f8829a4aSRandall Stewart uint32_t 2780b0471b4bSMichael Tuexen sctp_calculate_len(struct mbuf *m) 2781b0471b4bSMichael Tuexen { 2782f8829a4aSRandall Stewart uint32_t tlen = 0; 2783f8829a4aSRandall Stewart struct mbuf *at; 2784f8829a4aSRandall Stewart 2785f8829a4aSRandall Stewart at = m; 2786f8829a4aSRandall Stewart while (at) { 2787139bc87fSRandall Stewart tlen += SCTP_BUF_LEN(at); 2788139bc87fSRandall Stewart at = SCTP_BUF_NEXT(at); 2789f8829a4aSRandall Stewart } 2790f8829a4aSRandall Stewart return (tlen); 2791f8829a4aSRandall Stewart } 2792f8829a4aSRandall Stewart 2793f8829a4aSRandall Stewart void 2794f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp, 279544b7479bSRandall Stewart struct sctp_association *asoc, uint32_t mtu) 2796f8829a4aSRandall Stewart { 2797f8829a4aSRandall Stewart /* 2798f8829a4aSRandall Stewart * Reset the P-MTU size on this association, this involves changing 2799f8829a4aSRandall Stewart * the asoc MTU, going through ANY chunk+overhead larger than mtu to 2800f8829a4aSRandall Stewart * allow the DF flag to be cleared. 2801f8829a4aSRandall Stewart */ 2802f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 2803f8829a4aSRandall Stewart unsigned int eff_mtu, ovh; 2804f8829a4aSRandall Stewart 2805f8829a4aSRandall Stewart asoc->smallest_mtu = mtu; 2806f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2807f8829a4aSRandall Stewart ovh = SCTP_MIN_OVERHEAD; 2808f8829a4aSRandall Stewart } else { 2809f8829a4aSRandall Stewart ovh = SCTP_MIN_V4_OVERHEAD; 2810f8829a4aSRandall Stewart } 2811f8829a4aSRandall Stewart eff_mtu = mtu - ovh; 2812f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 2813f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2814f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2815f8829a4aSRandall Stewart } 2816f8829a4aSRandall Stewart } 2817f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 2818f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2819f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2820f8829a4aSRandall Stewart } 2821f8829a4aSRandall Stewart } 2822f8829a4aSRandall Stewart } 2823f8829a4aSRandall Stewart 2824f8829a4aSRandall Stewart 2825f8829a4aSRandall Stewart /* 282644f2a327SMichael Tuexen * Given an association and starting time of the current RTT period, update 282744f2a327SMichael Tuexen * RTO in number of msecs. net should point to the current network. 282844f2a327SMichael Tuexen * Return 1, if an RTO update was performed, return 0 if no update was 282944f2a327SMichael Tuexen * performed due to invalid starting point. 2830f8829a4aSRandall Stewart */ 2831899288aeSRandall Stewart 283244f2a327SMichael Tuexen int 2833f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb, 2834f8829a4aSRandall Stewart struct sctp_association *asoc, 2835f8829a4aSRandall Stewart struct sctp_nets *net, 28368c8e10b7SMichael Tuexen struct timeval *old, 2837b0471b4bSMichael Tuexen int rtt_from_sack) 2838b0471b4bSMichael Tuexen { 283944f2a327SMichael Tuexen struct timeval now; 284044f2a327SMichael Tuexen uint64_t rtt_us; /* RTT in us */ 2841be1d9176SMichael Tuexen int32_t rtt; /* RTT in ms */ 2842be1d9176SMichael Tuexen uint32_t new_rto; 2843f8829a4aSRandall Stewart int first_measure = 0; 2844f8829a4aSRandall Stewart 2845f8829a4aSRandall Stewart /************************/ 2846f8829a4aSRandall Stewart /* 1. calculate new RTT */ 2847f8829a4aSRandall Stewart /************************/ 2848f8829a4aSRandall Stewart /* get the current time */ 2849299108c5SRandall Stewart if (stcb->asoc.use_precise_time) { 2850299108c5SRandall Stewart (void)SCTP_GETPTIME_TIMEVAL(&now); 2851299108c5SRandall Stewart } else { 28526e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 2853299108c5SRandall Stewart } 285444f2a327SMichael Tuexen if ((old->tv_sec > now.tv_sec) || 285544f2a327SMichael Tuexen ((old->tv_sec == now.tv_sec) && (old->tv_sec > now.tv_sec))) { 285644f2a327SMichael Tuexen /* The starting point is in the future. */ 285744f2a327SMichael Tuexen return (0); 285844f2a327SMichael Tuexen } 2859be1d9176SMichael Tuexen timevalsub(&now, old); 286044f2a327SMichael Tuexen rtt_us = (uint64_t)1000000 * (uint64_t)now.tv_sec + (uint64_t)now.tv_usec; 286144f2a327SMichael Tuexen if (rtt_us > SCTP_RTO_UPPER_BOUND * 1000) { 286244f2a327SMichael Tuexen /* The RTT is larger than a sane value. */ 286344f2a327SMichael Tuexen return (0); 286444f2a327SMichael Tuexen } 2865be1d9176SMichael Tuexen /* store the current RTT in us */ 286644f2a327SMichael Tuexen net->rtt = rtt_us; 2867b60b0fe6SMichael Tuexen /* compute rtt in ms */ 2868b60b0fe6SMichael Tuexen rtt = (int32_t)(net->rtt / 1000); 2869f79aab18SRandall Stewart if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) { 2870b7b84c0eSMichael Tuexen /* 2871b7b84c0eSMichael Tuexen * Tell the CC module that a new update has just occurred 2872b7b84c0eSMichael Tuexen * from a sack 2873b7b84c0eSMichael Tuexen */ 2874f79aab18SRandall Stewart (*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now); 2875f79aab18SRandall Stewart } 2876f79aab18SRandall Stewart /* 2877f79aab18SRandall Stewart * Do we need to determine the lan? We do this only on sacks i.e. 2878f79aab18SRandall Stewart * RTT being determined from data not non-data (HB/INIT->INITACK). 2879f79aab18SRandall Stewart */ 2880f79aab18SRandall Stewart if ((rtt_from_sack == SCTP_RTT_FROM_DATA) && 2881be1d9176SMichael Tuexen (net->lan_type == SCTP_LAN_UNKNOWN)) { 2882be1d9176SMichael Tuexen if (net->rtt > SCTP_LOCAL_LAN_RTT) { 2883899288aeSRandall Stewart net->lan_type = SCTP_LAN_INTERNET; 2884899288aeSRandall Stewart } else { 2885899288aeSRandall Stewart net->lan_type = SCTP_LAN_LOCAL; 2886899288aeSRandall Stewart } 2887899288aeSRandall Stewart } 28880053ed28SMichael Tuexen 2889f8829a4aSRandall Stewart /***************************/ 2890f8829a4aSRandall Stewart /* 2. update RTTVAR & SRTT */ 2891f8829a4aSRandall Stewart /***************************/ 2892be1d9176SMichael Tuexen /*- 2893be1d9176SMichael Tuexen * Compute the scaled average lastsa and the 2894be1d9176SMichael Tuexen * scaled variance lastsv as described in van Jacobson 2895be1d9176SMichael Tuexen * Paper "Congestion Avoidance and Control", Annex A. 2896be1d9176SMichael Tuexen * 2897be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt 289844f2a327SMichael Tuexen * (net->lastsv >> SCTP_RTT_VAR_SHIFT) is the rttvar 2899be1d9176SMichael Tuexen */ 29009a972525SRandall Stewart if (net->RTO_measured) { 2901be1d9176SMichael Tuexen rtt -= (net->lastsa >> SCTP_RTT_SHIFT); 2902be1d9176SMichael Tuexen net->lastsa += rtt; 2903be1d9176SMichael Tuexen if (rtt < 0) { 2904be1d9176SMichael Tuexen rtt = -rtt; 2905be1d9176SMichael Tuexen } 2906be1d9176SMichael Tuexen rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); 2907be1d9176SMichael Tuexen net->lastsv += rtt; 2908b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2909f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_RTTVAR); 291080fefe0aSRandall Stewart } 2911f8829a4aSRandall Stewart } else { 2912f8829a4aSRandall Stewart /* First RTO measurment */ 29139a972525SRandall Stewart net->RTO_measured = 1; 2914f8829a4aSRandall Stewart first_measure = 1; 2915be1d9176SMichael Tuexen net->lastsa = rtt << SCTP_RTT_SHIFT; 2916be1d9176SMichael Tuexen net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT; 2917b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2918f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_INITIAL_RTT); 291980fefe0aSRandall Stewart } 2920f8829a4aSRandall Stewart } 2921be1d9176SMichael Tuexen if (net->lastsv == 0) { 2922be1d9176SMichael Tuexen net->lastsv = SCTP_CLOCK_GRANULARITY; 2923be1d9176SMichael Tuexen } 2924108df27cSRandall Stewart new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 2925f8829a4aSRandall Stewart if ((new_rto > SCTP_SAT_NETWORK_MIN) && 2926f8829a4aSRandall Stewart (stcb->asoc.sat_network_lockout == 0)) { 2927f8829a4aSRandall Stewart stcb->asoc.sat_network = 1; 2928f8829a4aSRandall Stewart } else if ((!first_measure) && stcb->asoc.sat_network) { 2929f8829a4aSRandall Stewart stcb->asoc.sat_network = 0; 2930f8829a4aSRandall Stewart stcb->asoc.sat_network_lockout = 1; 2931f8829a4aSRandall Stewart } 2932f8829a4aSRandall Stewart /* bound it, per C6/C7 in Section 5.3.1 */ 2933f8829a4aSRandall Stewart if (new_rto < stcb->asoc.minrto) { 2934f8829a4aSRandall Stewart new_rto = stcb->asoc.minrto; 2935f8829a4aSRandall Stewart } 2936f8829a4aSRandall Stewart if (new_rto > stcb->asoc.maxrto) { 2937f8829a4aSRandall Stewart new_rto = stcb->asoc.maxrto; 2938f8829a4aSRandall Stewart } 293944f2a327SMichael Tuexen net->RTO = new_rto; 294044f2a327SMichael Tuexen return (1); 2941f8829a4aSRandall Stewart } 2942f8829a4aSRandall Stewart 2943f8829a4aSRandall Stewart /* 2944f8829a4aSRandall Stewart * return a pointer to a contiguous piece of data from the given mbuf chain 2945f8829a4aSRandall Stewart * starting at 'off' for 'len' bytes. If the desired piece spans more than 2946f8829a4aSRandall Stewart * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size 2947f8829a4aSRandall Stewart * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain. 2948f8829a4aSRandall Stewart */ 294972fb6fdbSRandall Stewart caddr_t 2950f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t *in_ptr) 2951f8829a4aSRandall Stewart { 2952f8829a4aSRandall Stewart uint32_t count; 2953f8829a4aSRandall Stewart uint8_t *ptr; 2954f8829a4aSRandall Stewart 2955f8829a4aSRandall Stewart ptr = in_ptr; 2956f8829a4aSRandall Stewart if ((off < 0) || (len <= 0)) 2957f8829a4aSRandall Stewart return (NULL); 2958f8829a4aSRandall Stewart 2959f8829a4aSRandall Stewart /* find the desired start location */ 2960f8829a4aSRandall Stewart while ((m != NULL) && (off > 0)) { 2961139bc87fSRandall Stewart if (off < SCTP_BUF_LEN(m)) 2962f8829a4aSRandall Stewart break; 2963139bc87fSRandall Stewart off -= SCTP_BUF_LEN(m); 2964139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2965f8829a4aSRandall Stewart } 2966f8829a4aSRandall Stewart if (m == NULL) 2967f8829a4aSRandall Stewart return (NULL); 2968f8829a4aSRandall Stewart 2969f8829a4aSRandall Stewart /* is the current mbuf large enough (eg. contiguous)? */ 2970139bc87fSRandall Stewart if ((SCTP_BUF_LEN(m) - off) >= len) { 2971f8829a4aSRandall Stewart return (mtod(m, caddr_t)+off); 2972f8829a4aSRandall Stewart } else { 2973f8829a4aSRandall Stewart /* else, it spans more than one mbuf, so save a temp copy... */ 2974f8829a4aSRandall Stewart while ((m != NULL) && (len > 0)) { 2975139bc87fSRandall Stewart count = min(SCTP_BUF_LEN(m) - off, len); 29765ba7f91fSMichael Tuexen memcpy(ptr, mtod(m, caddr_t)+off, count); 2977f8829a4aSRandall Stewart len -= count; 2978f8829a4aSRandall Stewart ptr += count; 2979f8829a4aSRandall Stewart off = 0; 2980139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2981f8829a4aSRandall Stewart } 2982f8829a4aSRandall Stewart if ((m == NULL) && (len > 0)) 2983f8829a4aSRandall Stewart return (NULL); 2984f8829a4aSRandall Stewart else 2985f8829a4aSRandall Stewart return ((caddr_t)in_ptr); 2986f8829a4aSRandall Stewart } 2987f8829a4aSRandall Stewart } 2988f8829a4aSRandall Stewart 2989f8829a4aSRandall Stewart 299044b7479bSRandall Stewart 2991f8829a4aSRandall Stewart struct sctp_paramhdr * 2992f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m, 2993f8829a4aSRandall Stewart int offset, 2994f8829a4aSRandall Stewart struct sctp_paramhdr *pull, 2995f8829a4aSRandall Stewart int pull_limit) 2996f8829a4aSRandall Stewart { 2997f8829a4aSRandall Stewart /* This just provides a typed signature to Peter's Pull routine */ 2998f8829a4aSRandall Stewart return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit, 2999f8829a4aSRandall Stewart (uint8_t *)pull)); 3000f8829a4aSRandall Stewart } 3001f8829a4aSRandall Stewart 3002f8829a4aSRandall Stewart 3003ce11b842SMichael Tuexen struct mbuf * 3004f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen) 3005f8829a4aSRandall Stewart { 3006ce11b842SMichael Tuexen struct mbuf *m_last; 3007ce11b842SMichael Tuexen caddr_t dp; 3008f8829a4aSRandall Stewart 3009f8829a4aSRandall Stewart if (padlen > 3) { 3010ce11b842SMichael Tuexen return (NULL); 3011f8829a4aSRandall Stewart } 301241eee555SRandall Stewart if (padlen <= M_TRAILINGSPACE(m)) { 3013f8829a4aSRandall Stewart /* 3014f8829a4aSRandall Stewart * The easy way. We hope the majority of the time we hit 3015f8829a4aSRandall Stewart * here :) 3016f8829a4aSRandall Stewart */ 3017ce11b842SMichael Tuexen m_last = m; 3018f8829a4aSRandall Stewart } else { 3019ce11b842SMichael Tuexen /* Hard way we must grow the mbuf chain */ 3020ce11b842SMichael Tuexen m_last = sctp_get_mbuf_for_msg(padlen, 0, M_NOWAIT, 1, MT_DATA); 3021ce11b842SMichael Tuexen if (m_last == NULL) { 3022ce11b842SMichael Tuexen return (NULL); 3023f8829a4aSRandall Stewart } 3024ce11b842SMichael Tuexen SCTP_BUF_LEN(m_last) = 0; 3025ce11b842SMichael Tuexen SCTP_BUF_NEXT(m_last) = NULL; 3026ce11b842SMichael Tuexen SCTP_BUF_NEXT(m) = m_last; 3027f8829a4aSRandall Stewart } 3028ce11b842SMichael Tuexen dp = mtod(m_last, caddr_t)+SCTP_BUF_LEN(m_last); 3029ce11b842SMichael Tuexen SCTP_BUF_LEN(m_last) += padlen; 3030ce11b842SMichael Tuexen memset(dp, 0, padlen); 3031ce11b842SMichael Tuexen return (m_last); 3032f8829a4aSRandall Stewart } 3033f8829a4aSRandall Stewart 3034ce11b842SMichael Tuexen struct mbuf * 3035f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) 3036f8829a4aSRandall Stewart { 3037f8829a4aSRandall Stewart /* find the last mbuf in chain and pad it */ 3038f8829a4aSRandall Stewart struct mbuf *m_at; 3039f8829a4aSRandall Stewart 3040ce11b842SMichael Tuexen if (last_mbuf != NULL) { 3041f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(last_mbuf, padval)); 3042f8829a4aSRandall Stewart } else { 304317267b32SMichael Tuexen for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) { 3044139bc87fSRandall Stewart if (SCTP_BUF_NEXT(m_at) == NULL) { 3045f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(m_at, padval)); 3046f8829a4aSRandall Stewart } 3047f8829a4aSRandall Stewart } 3048f8829a4aSRandall Stewart } 3049ce11b842SMichael Tuexen return (NULL); 3050f8829a4aSRandall Stewart } 3051f8829a4aSRandall Stewart 3052f8829a4aSRandall Stewart static void 3053c5b5675dSMichael Tuexen sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, 3054410a3b1eSMichael Tuexen uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked 3055ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3056ceaad40aSRandall Stewart SCTP_UNUSED 3057ceaad40aSRandall Stewart #endif 3058ceaad40aSRandall Stewart ) 3059f8829a4aSRandall Stewart { 3060f8829a4aSRandall Stewart struct mbuf *m_notify; 3061f8829a4aSRandall Stewart struct sctp_assoc_change *sac; 3062f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 30639a8e3088SMichael Tuexen unsigned int notif_len; 30649a8e3088SMichael Tuexen uint16_t abort_len; 3065e06b67c7SMichael Tuexen unsigned int i; 3066ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3067ceaad40aSRandall Stewart struct socket *so; 3068ceaad40aSRandall Stewart #endif 3069ceaad40aSRandall Stewart 307059713bbfSMichael Tuexen if (stcb == NULL) { 307159713bbfSMichael Tuexen return; 307259713bbfSMichael Tuexen } 307358411b08SMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { 30749a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_assoc_change); 3075a2b42326SMichael Tuexen if (abort != NULL) { 3076c9eb4473SMichael Tuexen abort_len = ntohs(abort->ch.chunk_length); 30779669e724SMichael Tuexen /* 30789669e724SMichael Tuexen * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be 307945d41de5SMichael Tuexen * contiguous. 30809669e724SMichael Tuexen */ 30819669e724SMichael Tuexen if (abort_len > SCTP_CHUNK_BUFFER_SIZE) { 30829669e724SMichael Tuexen abort_len = SCTP_CHUNK_BUFFER_SIZE; 30839669e724SMichael Tuexen } 3084a2b42326SMichael Tuexen } else { 3085a2b42326SMichael Tuexen abort_len = 0; 3086c5b5675dSMichael Tuexen } 3087a2b42326SMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 3088a2b42326SMichael Tuexen notif_len += SCTP_ASSOC_SUPPORTS_MAX; 3089a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 3090a2b42326SMichael Tuexen notif_len += abort_len; 3091a2b42326SMichael Tuexen } 3092eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3093a2b42326SMichael Tuexen if (m_notify == NULL) { 3094a2b42326SMichael Tuexen /* Retry with smaller value. */ 30959a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_assoc_change); 3096eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 3097a2b42326SMichael Tuexen if (m_notify == NULL) { 309858411b08SMichael Tuexen goto set_error; 3099a2b42326SMichael Tuexen } 3100a2b42326SMichael Tuexen } 3101a2b42326SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 3102f8829a4aSRandall Stewart sac = mtod(m_notify, struct sctp_assoc_change *); 3103e432298aSXin LI memset(sac, 0, notif_len); 3104f8829a4aSRandall Stewart sac->sac_type = SCTP_ASSOC_CHANGE; 3105f8829a4aSRandall Stewart sac->sac_flags = 0; 3106f8829a4aSRandall Stewart sac->sac_length = sizeof(struct sctp_assoc_change); 3107c5b5675dSMichael Tuexen sac->sac_state = state; 3108f8829a4aSRandall Stewart sac->sac_error = error; 3109f8829a4aSRandall Stewart /* XXX verify these stream counts */ 3110f8829a4aSRandall Stewart sac->sac_outbound_streams = stcb->asoc.streamoutcnt; 3111f8829a4aSRandall Stewart sac->sac_inbound_streams = stcb->asoc.streamincnt; 3112f8829a4aSRandall Stewart sac->sac_assoc_id = sctp_get_associd(stcb); 3113a2b42326SMichael Tuexen if (notif_len > sizeof(struct sctp_assoc_change)) { 3114c5b5675dSMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 3115e06b67c7SMichael Tuexen i = 0; 3116c79bec9cSMichael Tuexen if (stcb->asoc.prsctp_supported == 1) { 3117e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR; 3118e06b67c7SMichael Tuexen } 3119c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 1) { 3120e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH; 3121e06b67c7SMichael Tuexen } 3122c79bec9cSMichael Tuexen if (stcb->asoc.asconf_supported == 1) { 3123e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; 3124e06b67c7SMichael Tuexen } 312544249214SRandall Stewart if (stcb->asoc.idata_supported == 1) { 312644249214SRandall Stewart sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_INTERLEAVING; 312744249214SRandall Stewart } 3128e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; 3129c79bec9cSMichael Tuexen if (stcb->asoc.reconfig_supported == 1) { 3130e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; 3131e06b67c7SMichael Tuexen } 3132e06b67c7SMichael Tuexen sac->sac_length += i; 3133a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 3134a2b42326SMichael Tuexen memcpy(sac->sac_info, abort, abort_len); 3135a2b42326SMichael Tuexen sac->sac_length += abort_len; 3136a2b42326SMichael Tuexen } 3137c5b5675dSMichael Tuexen } 3138e06b67c7SMichael Tuexen SCTP_BUF_LEN(m_notify) = sac->sac_length; 3139f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 31407215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3141f8829a4aSRandall Stewart m_notify); 314258411b08SMichael Tuexen if (control != NULL) { 3143139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 314428cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3145f8829a4aSRandall Stewart /* not that we need this */ 3146f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3147f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3148f8829a4aSRandall Stewart control, 3149cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, 3150cfde3ff7SRandall Stewart so_locked); 315158411b08SMichael Tuexen } else { 315258411b08SMichael Tuexen sctp_m_freem(m_notify); 315358411b08SMichael Tuexen } 315458411b08SMichael Tuexen } 315558411b08SMichael Tuexen /* 315658411b08SMichael Tuexen * For 1-to-1 style sockets, we send up and error when an ABORT 315758411b08SMichael Tuexen * comes in. 315858411b08SMichael Tuexen */ 315958411b08SMichael Tuexen set_error: 316058411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 316158411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 316258411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 3163e045904fSMichael Tuexen SOCK_LOCK(stcb->sctp_socket); 3164410a3b1eSMichael Tuexen if (from_peer) { 3165839d21d6SMichael Tuexen if (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) { 316658411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); 316758411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNREFUSED; 316858411b08SMichael Tuexen } else { 316958411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 317058411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNRESET; 317158411b08SMichael Tuexen } 3172410a3b1eSMichael Tuexen } else { 3173839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 3174839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 3175553bb068SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ETIMEDOUT); 3176553bb068SMichael Tuexen stcb->sctp_socket->so_error = ETIMEDOUT; 3177553bb068SMichael Tuexen } else { 3178410a3b1eSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED); 3179410a3b1eSMichael Tuexen stcb->sctp_socket->so_error = ECONNABORTED; 3180410a3b1eSMichael Tuexen } 318158411b08SMichael Tuexen } 31823acfe1e1SGleb Smirnoff SOCK_UNLOCK(stcb->sctp_socket); 3183553bb068SMichael Tuexen } 318458411b08SMichael Tuexen /* Wake ANY sleepers */ 3185ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3186ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3187ceaad40aSRandall Stewart if (!so_locked) { 3188ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3189ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3190ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3191ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3192ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3193ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3194ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3195ceaad40aSRandall Stewart return; 3196ceaad40aSRandall Stewart } 3197ceaad40aSRandall Stewart } 3198ceaad40aSRandall Stewart #endif 319958411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 320058411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 320158411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 32023acfe1e1SGleb Smirnoff socantrcvmore(stcb->sctp_socket); 320358411b08SMichael Tuexen } 320458411b08SMichael Tuexen sorwakeup(stcb->sctp_socket); 320558411b08SMichael Tuexen sowwakeup(stcb->sctp_socket); 3206ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3207ceaad40aSRandall Stewart if (!so_locked) { 3208ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3209ceaad40aSRandall Stewart } 3210ceaad40aSRandall Stewart #endif 3211f8829a4aSRandall Stewart } 3212f8829a4aSRandall Stewart 3213f8829a4aSRandall Stewart static void 3214f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, 32153cb3567dSMichael Tuexen struct sockaddr *sa, uint32_t error, int so_locked 32163cb3567dSMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 32173cb3567dSMichael Tuexen SCTP_UNUSED 32183cb3567dSMichael Tuexen #endif 32193cb3567dSMichael Tuexen ) 3220f8829a4aSRandall Stewart { 3221f8829a4aSRandall Stewart struct mbuf *m_notify; 3222f8829a4aSRandall Stewart struct sctp_paddr_change *spc; 3223f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3224f8829a4aSRandall Stewart 322560990c0cSMichael Tuexen if ((stcb == NULL) || 322660990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { 3227f8829a4aSRandall Stewart /* event not enabled */ 3228f8829a4aSRandall Stewart return; 3229830d754dSRandall Stewart } 3230eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_NOWAIT, 1, MT_DATA); 3231f8829a4aSRandall Stewart if (m_notify == NULL) 3232f8829a4aSRandall Stewart return; 3233139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3234f8829a4aSRandall Stewart spc = mtod(m_notify, struct sctp_paddr_change *); 323556711f94SMichael Tuexen memset(spc, 0, sizeof(struct sctp_paddr_change)); 3236f8829a4aSRandall Stewart spc->spc_type = SCTP_PEER_ADDR_CHANGE; 3237f8829a4aSRandall Stewart spc->spc_flags = 0; 3238f8829a4aSRandall Stewart spc->spc_length = sizeof(struct sctp_paddr_change); 32395e2c2d87SRandall Stewart switch (sa->sa_family) { 3240ea5eba11SMichael Tuexen #ifdef INET 32415e2c2d87SRandall Stewart case AF_INET: 3242d59107f7SMichael Tuexen #ifdef INET6 3243d59107f7SMichael Tuexen if (sctp_is_feature_on(stcb->sctp_ep, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 3244d59107f7SMichael Tuexen in6_sin_2_v4mapsin6((struct sockaddr_in *)sa, 3245d59107f7SMichael Tuexen (struct sockaddr_in6 *)&spc->spc_aaddr); 3246d59107f7SMichael Tuexen } else { 3247f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 3248d59107f7SMichael Tuexen } 3249d59107f7SMichael Tuexen #else 3250d59107f7SMichael Tuexen memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 3251d59107f7SMichael Tuexen #endif 32525e2c2d87SRandall Stewart break; 3253ea5eba11SMichael Tuexen #endif 32545e2c2d87SRandall Stewart #ifdef INET6 32555e2c2d87SRandall Stewart case AF_INET6: 32565e2c2d87SRandall Stewart { 3257f42a358aSRandall Stewart struct sockaddr_in6 *sin6; 3258f42a358aSRandall Stewart 3259f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6)); 3260f42a358aSRandall Stewart 3261f42a358aSRandall Stewart sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; 3262f42a358aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 326342551e99SRandall Stewart if (sin6->sin6_scope_id == 0) { 326442551e99SRandall Stewart /* recover scope_id for user */ 3265f42a358aSRandall Stewart (void)sa6_recoverscope(sin6); 326642551e99SRandall Stewart } else { 326742551e99SRandall Stewart /* clear embedded scope_id for user */ 326842551e99SRandall Stewart in6_clearscope(&sin6->sin6_addr); 326942551e99SRandall Stewart } 3270f42a358aSRandall Stewart } 32715e2c2d87SRandall Stewart break; 32725e2c2d87SRandall Stewart } 32735e2c2d87SRandall Stewart #endif 32745e2c2d87SRandall Stewart default: 32755e2c2d87SRandall Stewart /* TSNH */ 32765e2c2d87SRandall Stewart break; 3277f8829a4aSRandall Stewart } 3278f8829a4aSRandall Stewart spc->spc_state = state; 3279f8829a4aSRandall Stewart spc->spc_error = error; 3280f8829a4aSRandall Stewart spc->spc_assoc_id = sctp_get_associd(stcb); 3281f8829a4aSRandall Stewart 3282139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change); 3283139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3284f8829a4aSRandall Stewart 3285f8829a4aSRandall Stewart /* append to socket */ 3286f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 32877215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3288f8829a4aSRandall Stewart m_notify); 3289f8829a4aSRandall Stewart if (control == NULL) { 3290f8829a4aSRandall Stewart /* no memory */ 3291f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3292f8829a4aSRandall Stewart return; 3293f8829a4aSRandall Stewart } 3294139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3295139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3296f8829a4aSRandall Stewart /* not that we need this */ 3297f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3298f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3299f8829a4aSRandall Stewart control, 3300cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 3301cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 33023cb3567dSMichael Tuexen so_locked); 3303f8829a4aSRandall Stewart } 3304f8829a4aSRandall Stewart 3305f8829a4aSRandall Stewart 3306f8829a4aSRandall Stewart static void 33071edc9dbaSMichael Tuexen sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, 3308ceaad40aSRandall Stewart struct sctp_tmit_chunk *chk, int so_locked 3309ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3310ceaad40aSRandall Stewart SCTP_UNUSED 3311ceaad40aSRandall Stewart #endif 3312ceaad40aSRandall Stewart ) 3313f8829a4aSRandall Stewart { 3314830d754dSRandall Stewart struct mbuf *m_notify; 3315f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 33169935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 3317f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3318ab337314SMichael Tuexen struct sctp_chunkhdr *chkhdr; 3319ab337314SMichael Tuexen int notifhdr_len, chk_len, chkhdr_len, padding_len, payload_len; 3320f8829a4aSRandall Stewart 332160990c0cSMichael Tuexen if ((stcb == NULL) || 33229935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 33239935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 3324f8829a4aSRandall Stewart /* event not enabled */ 3325f8829a4aSRandall Stewart return; 3326830d754dSRandall Stewart } 33270053ed28SMichael Tuexen 33289935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 3329ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed_event); 33309935403aSMichael Tuexen } else { 3331ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed); 33329935403aSMichael Tuexen } 3333ab337314SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); 3334f8829a4aSRandall Stewart if (m_notify == NULL) 3335f8829a4aSRandall Stewart /* no space left */ 3336f8829a4aSRandall Stewart return; 3337ab337314SMichael Tuexen SCTP_BUF_LEN(m_notify) = notifhdr_len; 3338ab337314SMichael Tuexen if (stcb->asoc.idata_supported) { 3339ab337314SMichael Tuexen chkhdr_len = sizeof(struct sctp_idata_chunk); 3340ab337314SMichael Tuexen } else { 3341ab337314SMichael Tuexen chkhdr_len = sizeof(struct sctp_data_chunk); 3342ab337314SMichael Tuexen } 3343ab337314SMichael Tuexen /* Use some defaults in case we can't access the chunk header */ 3344ab337314SMichael Tuexen if (chk->send_size >= chkhdr_len) { 3345ab337314SMichael Tuexen payload_len = chk->send_size - chkhdr_len; 3346ab337314SMichael Tuexen } else { 3347ab337314SMichael Tuexen payload_len = 0; 3348ab337314SMichael Tuexen } 3349ab337314SMichael Tuexen padding_len = 0; 3350ab337314SMichael Tuexen if (chk->data != NULL) { 3351ab337314SMichael Tuexen chkhdr = mtod(chk->data, struct sctp_chunkhdr *); 3352ab337314SMichael Tuexen if (chkhdr != NULL) { 3353ab337314SMichael Tuexen chk_len = ntohs(chkhdr->chunk_length); 3354ab337314SMichael Tuexen if ((chk_len >= chkhdr_len) && 3355ab337314SMichael Tuexen (chk->send_size >= chk_len) && 3356ab337314SMichael Tuexen (chk->send_size - chk_len < 4)) { 3357ab337314SMichael Tuexen padding_len = chk->send_size - chk_len; 3358ab337314SMichael Tuexen payload_len = chk->send_size - chkhdr_len - padding_len; 3359ab337314SMichael Tuexen } 3360ab337314SMichael Tuexen } 3361ab337314SMichael Tuexen } 33629935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 33639935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 3364ab337314SMichael Tuexen memset(ssfe, 0, notifhdr_len); 33659935403aSMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 33661edc9dbaSMichael Tuexen if (sent) { 33679935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_SENT; 33681edc9dbaSMichael Tuexen } else { 33691edc9dbaSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 33701edc9dbaSMichael Tuexen } 3371ab337314SMichael Tuexen ssfe->ssfe_length = (uint32_t)(notifhdr_len + payload_len); 33729935403aSMichael Tuexen ssfe->ssfe_error = error; 33739935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 337449656eefSMichael Tuexen ssfe->ssfe_info.snd_sid = chk->rec.data.sid; 33759935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags; 337649656eefSMichael Tuexen ssfe->ssfe_info.snd_ppid = chk->rec.data.ppid; 33779935403aSMichael Tuexen ssfe->ssfe_info.snd_context = chk->rec.data.context; 33789935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 33799935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 33809935403aSMichael Tuexen } else { 3381f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 3382ab337314SMichael Tuexen memset(ssf, 0, notifhdr_len); 3383f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 33841edc9dbaSMichael Tuexen if (sent) { 3385f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_SENT; 33861edc9dbaSMichael Tuexen } else { 33871edc9dbaSMichael Tuexen ssf->ssf_flags = SCTP_DATA_UNSENT; 33881edc9dbaSMichael Tuexen } 3389ab337314SMichael Tuexen ssf->ssf_length = (uint32_t)(notifhdr_len + payload_len); 3390f8829a4aSRandall Stewart ssf->ssf_error = error; 3391f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 339249656eefSMichael Tuexen ssf->ssf_info.sinfo_stream = chk->rec.data.sid; 339349656eefSMichael Tuexen ssf->ssf_info.sinfo_ssn = (uint16_t)chk->rec.data.mid; 3394f8829a4aSRandall Stewart ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; 339549656eefSMichael Tuexen ssf->ssf_info.sinfo_ppid = chk->rec.data.ppid; 3396f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = chk->rec.data.context; 3397f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 3398f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 33999935403aSMichael Tuexen } 3400ab337314SMichael Tuexen if (chk->data != NULL) { 3401ab337314SMichael Tuexen /* Trim off the sctp chunk header (it should be there) */ 3402ab337314SMichael Tuexen if (chk->send_size == chkhdr_len + payload_len + padding_len) { 3403ab337314SMichael Tuexen m_adj(chk->data, chkhdr_len); 3404ab337314SMichael Tuexen m_adj(chk->data, -padding_len); 3405830d754dSRandall Stewart sctp_mbuf_crush(chk->data); 3406ab337314SMichael Tuexen chk->send_size -= (chkhdr_len + padding_len); 3407830d754dSRandall Stewart } 3408830d754dSRandall Stewart } 3409810ec536SMichael Tuexen SCTP_BUF_NEXT(m_notify) = chk->data; 3410f8829a4aSRandall Stewart /* Steal off the mbuf */ 3411f8829a4aSRandall Stewart chk->data = NULL; 3412f8829a4aSRandall Stewart /* 3413f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 3414f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 3415f8829a4aSRandall Stewart * non-reader 3416f8829a4aSRandall Stewart */ 3417139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3418f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3419f8829a4aSRandall Stewart return; 3420f8829a4aSRandall Stewart } 3421f8829a4aSRandall Stewart /* append to socket */ 3422f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 34237215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3424f8829a4aSRandall Stewart m_notify); 3425f8829a4aSRandall Stewart if (control == NULL) { 3426f8829a4aSRandall Stewart /* no memory */ 3427f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3428f8829a4aSRandall Stewart return; 3429f8829a4aSRandall Stewart } 343028cd0699SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3431139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 343228cd0699SMichael Tuexen /* not that we need this */ 343328cd0699SMichael Tuexen control->tail_mbuf = m_notify; 3434f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3435f8829a4aSRandall Stewart control, 3436cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 3437cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 3438cfde3ff7SRandall Stewart so_locked); 3439f8829a4aSRandall Stewart } 3440f8829a4aSRandall Stewart 3441f8829a4aSRandall Stewart 3442f8829a4aSRandall Stewart static void 3443f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, 3444ceaad40aSRandall Stewart struct sctp_stream_queue_pending *sp, int so_locked 3445ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3446ceaad40aSRandall Stewart SCTP_UNUSED 3447ceaad40aSRandall Stewart #endif 3448ceaad40aSRandall Stewart ) 3449f8829a4aSRandall Stewart { 3450f8829a4aSRandall Stewart struct mbuf *m_notify; 3451f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 34529935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 3453f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3454ab337314SMichael Tuexen int notifhdr_len; 3455f8829a4aSRandall Stewart 345660990c0cSMichael Tuexen if ((stcb == NULL) || 34579935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 34589935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 3459f8829a4aSRandall Stewart /* event not enabled */ 3460f8829a4aSRandall Stewart return; 3461830d754dSRandall Stewart } 34629935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 3463ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed_event); 34649935403aSMichael Tuexen } else { 3465ab337314SMichael Tuexen notifhdr_len = sizeof(struct sctp_send_failed); 34669935403aSMichael Tuexen } 3467ab337314SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notifhdr_len, 0, M_NOWAIT, 1, MT_DATA); 34689935403aSMichael Tuexen if (m_notify == NULL) { 3469f8829a4aSRandall Stewart /* no space left */ 3470f8829a4aSRandall Stewart return; 34719935403aSMichael Tuexen } 3472ab337314SMichael Tuexen SCTP_BUF_LEN(m_notify) = notifhdr_len; 34739935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 34749935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 3475ab337314SMichael Tuexen memset(ssfe, 0, notifhdr_len); 3476ad83c8a5SMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 34779935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 3478ab337314SMichael Tuexen ssfe->ssfe_length = (uint32_t)(notifhdr_len + sp->length); 34799935403aSMichael Tuexen ssfe->ssfe_error = error; 34809935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 348149656eefSMichael Tuexen ssfe->ssfe_info.snd_sid = sp->sid; 34829935403aSMichael Tuexen if (sp->some_taken) { 34839935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG; 34849935403aSMichael Tuexen } else { 34859935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG; 34869935403aSMichael Tuexen } 34879935403aSMichael Tuexen ssfe->ssfe_info.snd_ppid = sp->ppid; 34889935403aSMichael Tuexen ssfe->ssfe_info.snd_context = sp->context; 34899935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 34909935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 34919935403aSMichael Tuexen } else { 3492f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 3493ab337314SMichael Tuexen memset(ssf, 0, notifhdr_len); 3494f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 3495f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_UNSENT; 3496ab337314SMichael Tuexen ssf->ssf_length = (uint32_t)(notifhdr_len + sp->length); 3497f8829a4aSRandall Stewart ssf->ssf_error = error; 3498f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 349949656eefSMichael Tuexen ssf->ssf_info.sinfo_stream = sp->sid; 3500f3b05218SMichael Tuexen ssf->ssf_info.sinfo_ssn = 0; 3501fc14de76SRandall Stewart if (sp->some_taken) { 3502fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG; 3503fc14de76SRandall Stewart } else { 3504fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG; 3505fc14de76SRandall Stewart } 3506f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = sp->ppid; 3507f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = sp->context; 3508f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 3509f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 35109935403aSMichael Tuexen } 35119935403aSMichael Tuexen SCTP_BUF_NEXT(m_notify) = sp->data; 3512f8829a4aSRandall Stewart 3513f8829a4aSRandall Stewart /* Steal off the mbuf */ 3514f8829a4aSRandall Stewart sp->data = NULL; 3515f8829a4aSRandall Stewart /* 3516f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 3517f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 3518f8829a4aSRandall Stewart * non-reader 3519f8829a4aSRandall Stewart */ 3520139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3521f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3522f8829a4aSRandall Stewart return; 3523f8829a4aSRandall Stewart } 3524f8829a4aSRandall Stewart /* append to socket */ 3525f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 35267215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3527f8829a4aSRandall Stewart m_notify); 3528f8829a4aSRandall Stewart if (control == NULL) { 3529f8829a4aSRandall Stewart /* no memory */ 3530f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3531f8829a4aSRandall Stewart return; 3532f8829a4aSRandall Stewart } 353328cd0699SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3534139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 353528cd0699SMichael Tuexen /* not that we need this */ 353628cd0699SMichael Tuexen control->tail_mbuf = m_notify; 3537f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3538f8829a4aSRandall Stewart control, 3539cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3540f8829a4aSRandall Stewart } 3541f8829a4aSRandall Stewart 3542f8829a4aSRandall Stewart 3543f8829a4aSRandall Stewart 3544f8829a4aSRandall Stewart static void 35457215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb) 3546f8829a4aSRandall Stewart { 3547f8829a4aSRandall Stewart struct mbuf *m_notify; 3548f8829a4aSRandall Stewart struct sctp_adaptation_event *sai; 3549f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3550f8829a4aSRandall Stewart 355160990c0cSMichael Tuexen if ((stcb == NULL) || 355260990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { 3553f8829a4aSRandall Stewart /* event not enabled */ 3554f8829a4aSRandall Stewart return; 3555830d754dSRandall Stewart } 35560053ed28SMichael Tuexen 3557eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_NOWAIT, 1, MT_DATA); 3558f8829a4aSRandall Stewart if (m_notify == NULL) 3559f8829a4aSRandall Stewart /* no space left */ 3560f8829a4aSRandall Stewart return; 3561139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3562f8829a4aSRandall Stewart sai = mtod(m_notify, struct sctp_adaptation_event *); 3563e432298aSXin LI memset(sai, 0, sizeof(struct sctp_adaptation_event)); 3564f8829a4aSRandall Stewart sai->sai_type = SCTP_ADAPTATION_INDICATION; 3565f8829a4aSRandall Stewart sai->sai_flags = 0; 3566f8829a4aSRandall Stewart sai->sai_length = sizeof(struct sctp_adaptation_event); 35672afb3e84SRandall Stewart sai->sai_adaptation_ind = stcb->asoc.peers_adaptation; 3568f8829a4aSRandall Stewart sai->sai_assoc_id = sctp_get_associd(stcb); 3569f8829a4aSRandall Stewart 3570139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event); 3571139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3572f8829a4aSRandall Stewart 3573f8829a4aSRandall Stewart /* append to socket */ 3574f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 35757215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3576f8829a4aSRandall Stewart m_notify); 3577f8829a4aSRandall Stewart if (control == NULL) { 3578f8829a4aSRandall Stewart /* no memory */ 3579f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3580f8829a4aSRandall Stewart return; 3581f8829a4aSRandall Stewart } 3582139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3583139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3584f8829a4aSRandall Stewart /* not that we need this */ 3585f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3586f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3587f8829a4aSRandall Stewart control, 3588cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3589f8829a4aSRandall Stewart } 3590f8829a4aSRandall Stewart 359103b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */ 3592810ec536SMichael Tuexen static void 35932dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, 3594810ec536SMichael Tuexen uint32_t val, int so_locked 3595810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3596810ec536SMichael Tuexen SCTP_UNUSED 3597810ec536SMichael Tuexen #endif 3598810ec536SMichael Tuexen ) 3599f8829a4aSRandall Stewart { 3600f8829a4aSRandall Stewart struct mbuf *m_notify; 3601f8829a4aSRandall Stewart struct sctp_pdapi_event *pdapi; 3602f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 360303b0b021SRandall Stewart struct sockbuf *sb; 3604f8829a4aSRandall Stewart 360560990c0cSMichael Tuexen if ((stcb == NULL) || 360660990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { 3607f8829a4aSRandall Stewart /* event not enabled */ 3608f8829a4aSRandall Stewart return; 3609830d754dSRandall Stewart } 3610cd1386abSMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 3611cd1386abSMichael Tuexen return; 3612cd1386abSMichael Tuexen } 36130053ed28SMichael Tuexen 3614eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_NOWAIT, 1, MT_DATA); 3615f8829a4aSRandall Stewart if (m_notify == NULL) 3616f8829a4aSRandall Stewart /* no space left */ 3617f8829a4aSRandall Stewart return; 3618139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3619f8829a4aSRandall Stewart pdapi = mtod(m_notify, struct sctp_pdapi_event *); 3620e432298aSXin LI memset(pdapi, 0, sizeof(struct sctp_pdapi_event)); 3621f8829a4aSRandall Stewart pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; 3622f8829a4aSRandall Stewart pdapi->pdapi_flags = 0; 3623f8829a4aSRandall Stewart pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); 3624f8829a4aSRandall Stewart pdapi->pdapi_indication = error; 36259a6142d8SRandall Stewart pdapi->pdapi_stream = (val >> 16); 36269a6142d8SRandall Stewart pdapi->pdapi_seq = (val & 0x0000ffff); 3627f8829a4aSRandall Stewart pdapi->pdapi_assoc_id = sctp_get_associd(stcb); 3628f8829a4aSRandall Stewart 3629139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); 3630139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3631f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 36327215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3633f8829a4aSRandall Stewart m_notify); 3634f8829a4aSRandall Stewart if (control == NULL) { 3635f8829a4aSRandall Stewart /* no memory */ 3636f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3637f8829a4aSRandall Stewart return; 3638f8829a4aSRandall Stewart } 3639139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 364028cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3641f8829a4aSRandall Stewart /* not that we need this */ 3642f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 364303b0b021SRandall Stewart sb = &stcb->sctp_socket->so_rcv; 3644b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 3645139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify)); 364680fefe0aSRandall Stewart } 364703b0b021SRandall Stewart sctp_sballoc(stcb, sb, m_notify); 3648b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 364903b0b021SRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 365080fefe0aSRandall Stewart } 365103b0b021SRandall Stewart control->end_added = 1; 365203b0b021SRandall Stewart if (stcb->asoc.control_pdapi) 365303b0b021SRandall Stewart TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); 365403b0b021SRandall Stewart else { 365503b0b021SRandall Stewart /* we really should not see this case */ 365603b0b021SRandall Stewart TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); 365703b0b021SRandall Stewart } 365803b0b021SRandall Stewart if (stcb->sctp_ep && stcb->sctp_socket) { 365903b0b021SRandall Stewart /* This should always be the case */ 3660810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3661810ec536SMichael Tuexen struct socket *so; 3662810ec536SMichael Tuexen 3663810ec536SMichael Tuexen so = SCTP_INP_SO(stcb->sctp_ep); 3664810ec536SMichael Tuexen if (!so_locked) { 3665810ec536SMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, 1); 3666810ec536SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 3667810ec536SMichael Tuexen SCTP_SOCKET_LOCK(so, 1); 3668810ec536SMichael Tuexen SCTP_TCB_LOCK(stcb); 3669810ec536SMichael Tuexen atomic_subtract_int(&stcb->asoc.refcnt, 1); 3670810ec536SMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3671810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3672810ec536SMichael Tuexen return; 3673810ec536SMichael Tuexen } 3674810ec536SMichael Tuexen } 3675810ec536SMichael Tuexen #endif 367603b0b021SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 3677810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3678810ec536SMichael Tuexen if (!so_locked) { 3679810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3680810ec536SMichael Tuexen } 3681810ec536SMichael Tuexen #endif 3682f8829a4aSRandall Stewart } 3683f8829a4aSRandall Stewart } 3684f8829a4aSRandall Stewart 3685f8829a4aSRandall Stewart static void 3686f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb) 3687f8829a4aSRandall Stewart { 3688f8829a4aSRandall Stewart struct mbuf *m_notify; 3689f8829a4aSRandall Stewart struct sctp_shutdown_event *sse; 3690f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3691f8829a4aSRandall Stewart 3692f8829a4aSRandall Stewart /* 3693f8829a4aSRandall Stewart * For TCP model AND UDP connected sockets we will send an error up 3694f8829a4aSRandall Stewart * when an SHUTDOWN completes 3695f8829a4aSRandall Stewart */ 3696f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3697f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3698f8829a4aSRandall Stewart /* mark socket closed for read/write and wakeup! */ 3699ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3700ceaad40aSRandall Stewart struct socket *so; 3701ceaad40aSRandall Stewart 3702ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3703ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3704ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3705ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3706ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3707ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3708ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3709ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3710ceaad40aSRandall Stewart return; 3711ceaad40aSRandall Stewart } 3712ceaad40aSRandall Stewart #endif 3713f8829a4aSRandall Stewart socantsendmore(stcb->sctp_socket); 3714ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3715ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3716ceaad40aSRandall Stewart #endif 3717f8829a4aSRandall Stewart } 3718e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { 3719f8829a4aSRandall Stewart /* event not enabled */ 3720f8829a4aSRandall Stewart return; 3721830d754dSRandall Stewart } 37220053ed28SMichael Tuexen 3723eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_NOWAIT, 1, MT_DATA); 3724f8829a4aSRandall Stewart if (m_notify == NULL) 3725f8829a4aSRandall Stewart /* no space left */ 3726f8829a4aSRandall Stewart return; 3727f8829a4aSRandall Stewart sse = mtod(m_notify, struct sctp_shutdown_event *); 3728e432298aSXin LI memset(sse, 0, sizeof(struct sctp_shutdown_event)); 3729f8829a4aSRandall Stewart sse->sse_type = SCTP_SHUTDOWN_EVENT; 3730f8829a4aSRandall Stewart sse->sse_flags = 0; 3731f8829a4aSRandall Stewart sse->sse_length = sizeof(struct sctp_shutdown_event); 3732f8829a4aSRandall Stewart sse->sse_assoc_id = sctp_get_associd(stcb); 3733f8829a4aSRandall Stewart 3734139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event); 3735139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3736f8829a4aSRandall Stewart 3737f8829a4aSRandall Stewart /* append to socket */ 3738f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 37397215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3740f8829a4aSRandall Stewart m_notify); 3741f8829a4aSRandall Stewart if (control == NULL) { 3742f8829a4aSRandall Stewart /* no memory */ 3743f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3744f8829a4aSRandall Stewart return; 3745f8829a4aSRandall Stewart } 3746139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 374728cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3748f8829a4aSRandall Stewart /* not that we need this */ 3749f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3750f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3751f8829a4aSRandall Stewart control, 3752cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3753f8829a4aSRandall Stewart } 3754f8829a4aSRandall Stewart 3755f8829a4aSRandall Stewart static void 3756830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb, 3757830d754dSRandall Stewart int so_locked 3758830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3759830d754dSRandall Stewart SCTP_UNUSED 3760830d754dSRandall Stewart #endif 3761830d754dSRandall Stewart ) 3762830d754dSRandall Stewart { 3763830d754dSRandall Stewart struct mbuf *m_notify; 3764830d754dSRandall Stewart struct sctp_sender_dry_event *event; 3765830d754dSRandall Stewart struct sctp_queued_to_read *control; 3766830d754dSRandall Stewart 376760990c0cSMichael Tuexen if ((stcb == NULL) || 376860990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { 3769830d754dSRandall Stewart /* event not enabled */ 3770830d754dSRandall Stewart return; 3771830d754dSRandall Stewart } 37720053ed28SMichael Tuexen 3773eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_NOWAIT, 1, MT_DATA); 3774830d754dSRandall Stewart if (m_notify == NULL) { 3775830d754dSRandall Stewart /* no space left */ 3776830d754dSRandall Stewart return; 3777830d754dSRandall Stewart } 3778830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3779830d754dSRandall Stewart event = mtod(m_notify, struct sctp_sender_dry_event *); 3780e432298aSXin LI memset(event, 0, sizeof(struct sctp_sender_dry_event)); 3781830d754dSRandall Stewart event->sender_dry_type = SCTP_SENDER_DRY_EVENT; 3782830d754dSRandall Stewart event->sender_dry_flags = 0; 3783830d754dSRandall Stewart event->sender_dry_length = sizeof(struct sctp_sender_dry_event); 3784830d754dSRandall Stewart event->sender_dry_assoc_id = sctp_get_associd(stcb); 3785830d754dSRandall Stewart 3786830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event); 3787830d754dSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3788830d754dSRandall Stewart 3789830d754dSRandall Stewart /* append to socket */ 3790830d754dSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 37917215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 37927215cc1bSMichael Tuexen m_notify); 3793830d754dSRandall Stewart if (control == NULL) { 3794830d754dSRandall Stewart /* no memory */ 3795830d754dSRandall Stewart sctp_m_freem(m_notify); 3796830d754dSRandall Stewart return; 3797830d754dSRandall Stewart } 3798830d754dSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3799830d754dSRandall Stewart control->spec_flags = M_NOTIFICATION; 3800830d754dSRandall Stewart /* not that we need this */ 3801830d754dSRandall Stewart control->tail_mbuf = m_notify; 3802830d754dSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control, 3803cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3804830d754dSRandall Stewart } 3805830d754dSRandall Stewart 3806ea44232bSRandall Stewart 3807c4e848b7SRandall Stewart void 3808c4e848b7SRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag) 3809ea44232bSRandall Stewart { 3810ea44232bSRandall Stewart struct mbuf *m_notify; 3811ea44232bSRandall Stewart struct sctp_queued_to_read *control; 3812c4e848b7SRandall Stewart struct sctp_stream_change_event *stradd; 3813ea44232bSRandall Stewart 38148c501e51SMichael Tuexen if ((stcb == NULL) || 38158c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) { 3816ea44232bSRandall Stewart /* event not enabled */ 3817ea44232bSRandall Stewart return; 3818ea44232bSRandall Stewart } 3819c4e848b7SRandall Stewart if ((stcb->asoc.peer_req_out) && flag) { 3820c4e848b7SRandall Stewart /* Peer made the request, don't tell the local user */ 3821c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3822c4e848b7SRandall Stewart return; 3823c4e848b7SRandall Stewart } 3824c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3825e432298aSXin LI m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_stream_change_event), 0, M_NOWAIT, 1, MT_DATA); 3826ea44232bSRandall Stewart if (m_notify == NULL) 3827ea44232bSRandall Stewart /* no space left */ 3828ea44232bSRandall Stewart return; 3829ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3830c4e848b7SRandall Stewart stradd = mtod(m_notify, struct sctp_stream_change_event *); 3831e432298aSXin LI memset(stradd, 0, sizeof(struct sctp_stream_change_event)); 3832c4e848b7SRandall Stewart stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT; 3833c4e848b7SRandall Stewart stradd->strchange_flags = flag; 3834e432298aSXin LI stradd->strchange_length = sizeof(struct sctp_stream_change_event); 3835c4e848b7SRandall Stewart stradd->strchange_assoc_id = sctp_get_associd(stcb); 3836c4e848b7SRandall Stewart stradd->strchange_instrms = numberin; 3837c4e848b7SRandall Stewart stradd->strchange_outstrms = numberout; 3838e432298aSXin LI SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_stream_change_event); 3839ea44232bSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3840ea44232bSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3841ea44232bSRandall Stewart /* no space */ 3842ea44232bSRandall Stewart sctp_m_freem(m_notify); 3843ea44232bSRandall Stewart return; 3844ea44232bSRandall Stewart } 3845ea44232bSRandall Stewart /* append to socket */ 3846ea44232bSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 38477215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3848ea44232bSRandall Stewart m_notify); 3849ea44232bSRandall Stewart if (control == NULL) { 3850ea44232bSRandall Stewart /* no memory */ 3851ea44232bSRandall Stewart sctp_m_freem(m_notify); 3852ea44232bSRandall Stewart return; 3853ea44232bSRandall Stewart } 3854ea44232bSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 385528cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3856ea44232bSRandall Stewart /* not that we need this */ 3857ea44232bSRandall Stewart control->tail_mbuf = m_notify; 3858ea44232bSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3859ea44232bSRandall Stewart control, 3860cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3861ea44232bSRandall Stewart } 3862ea44232bSRandall Stewart 3863c4e848b7SRandall Stewart void 3864c4e848b7SRandall Stewart sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag) 3865c4e848b7SRandall Stewart { 3866c4e848b7SRandall Stewart struct mbuf *m_notify; 3867c4e848b7SRandall Stewart struct sctp_queued_to_read *control; 3868c4e848b7SRandall Stewart struct sctp_assoc_reset_event *strasoc; 3869c4e848b7SRandall Stewart 38708c501e51SMichael Tuexen if ((stcb == NULL) || 38718c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) { 3872c4e848b7SRandall Stewart /* event not enabled */ 3873c4e848b7SRandall Stewart return; 3874c4e848b7SRandall Stewart } 3875e432298aSXin LI m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_reset_event), 0, M_NOWAIT, 1, MT_DATA); 3876c4e848b7SRandall Stewart if (m_notify == NULL) 3877c4e848b7SRandall Stewart /* no space left */ 3878c4e848b7SRandall Stewart return; 3879c4e848b7SRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3880c4e848b7SRandall Stewart strasoc = mtod(m_notify, struct sctp_assoc_reset_event *); 3881e432298aSXin LI memset(strasoc, 0, sizeof(struct sctp_assoc_reset_event)); 3882c4e848b7SRandall Stewart strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT; 3883c4e848b7SRandall Stewart strasoc->assocreset_flags = flag; 3884e432298aSXin LI strasoc->assocreset_length = sizeof(struct sctp_assoc_reset_event); 3885c4e848b7SRandall Stewart strasoc->assocreset_assoc_id = sctp_get_associd(stcb); 3886c4e848b7SRandall Stewart strasoc->assocreset_local_tsn = sending_tsn; 3887c4e848b7SRandall Stewart strasoc->assocreset_remote_tsn = recv_tsn; 3888e432298aSXin LI SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_reset_event); 3889c4e848b7SRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3890c4e848b7SRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3891c4e848b7SRandall Stewart /* no space */ 3892c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3893c4e848b7SRandall Stewart return; 3894c4e848b7SRandall Stewart } 3895c4e848b7SRandall Stewart /* append to socket */ 3896c4e848b7SRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3897c4e848b7SRandall Stewart 0, 0, stcb->asoc.context, 0, 0, 0, 3898c4e848b7SRandall Stewart m_notify); 3899c4e848b7SRandall Stewart if (control == NULL) { 3900c4e848b7SRandall Stewart /* no memory */ 3901c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3902c4e848b7SRandall Stewart return; 3903c4e848b7SRandall Stewart } 3904c4e848b7SRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 390528cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3906c4e848b7SRandall Stewart /* not that we need this */ 3907c4e848b7SRandall Stewart control->tail_mbuf = m_notify; 3908c4e848b7SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3909c4e848b7SRandall Stewart control, 3910c4e848b7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3911c4e848b7SRandall Stewart } 3912c4e848b7SRandall Stewart 3913c4e848b7SRandall Stewart 3914ea44232bSRandall Stewart 3915830d754dSRandall Stewart static void 3916f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb, 3917f8829a4aSRandall Stewart int number_entries, uint16_t *list, int flag) 3918f8829a4aSRandall Stewart { 3919f8829a4aSRandall Stewart struct mbuf *m_notify; 3920f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3921f8829a4aSRandall Stewart struct sctp_stream_reset_event *strreset; 3922f8829a4aSRandall Stewart int len; 3923f8829a4aSRandall Stewart 39248c501e51SMichael Tuexen if ((stcb == NULL) || 39258c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) { 3926f8829a4aSRandall Stewart /* event not enabled */ 3927f8829a4aSRandall Stewart return; 3928830d754dSRandall Stewart } 39290053ed28SMichael Tuexen 3930eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_NOWAIT, 1, MT_DATA); 3931f8829a4aSRandall Stewart if (m_notify == NULL) 3932f8829a4aSRandall Stewart /* no space left */ 3933f8829a4aSRandall Stewart return; 3934139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3935f8829a4aSRandall Stewart len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); 3936f8829a4aSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3937f8829a4aSRandall Stewart /* never enough room */ 3938f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3939f8829a4aSRandall Stewart return; 3940f8829a4aSRandall Stewart } 3941f8829a4aSRandall Stewart strreset = mtod(m_notify, struct sctp_stream_reset_event *); 3942e432298aSXin LI memset(strreset, 0, len); 3943f8829a4aSRandall Stewart strreset->strreset_type = SCTP_STREAM_RESET_EVENT; 3944c4e848b7SRandall Stewart strreset->strreset_flags = flag; 3945f8829a4aSRandall Stewart strreset->strreset_length = len; 3946f8829a4aSRandall Stewart strreset->strreset_assoc_id = sctp_get_associd(stcb); 3947f8829a4aSRandall Stewart if (number_entries) { 3948f8829a4aSRandall Stewart int i; 3949f8829a4aSRandall Stewart 3950f8829a4aSRandall Stewart for (i = 0; i < number_entries; i++) { 3951c4e848b7SRandall Stewart strreset->strreset_stream_list[i] = ntohs(list[i]); 3952f8829a4aSRandall Stewart } 3953f8829a4aSRandall Stewart } 3954139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3955139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3956139bc87fSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3957f8829a4aSRandall Stewart /* no space */ 3958f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3959f8829a4aSRandall Stewart return; 3960f8829a4aSRandall Stewart } 3961f8829a4aSRandall Stewart /* append to socket */ 3962f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 39637215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3964f8829a4aSRandall Stewart m_notify); 3965f8829a4aSRandall Stewart if (control == NULL) { 3966f8829a4aSRandall Stewart /* no memory */ 3967f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3968f8829a4aSRandall Stewart return; 3969f8829a4aSRandall Stewart } 3970139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 397128cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3972f8829a4aSRandall Stewart /* not that we need this */ 3973f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3974f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3975f8829a4aSRandall Stewart control, 3976cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3977f8829a4aSRandall Stewart } 3978f8829a4aSRandall Stewart 3979f8829a4aSRandall Stewart 3980389b1b11SMichael Tuexen static void 3981389b1b11SMichael Tuexen sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk) 3982389b1b11SMichael Tuexen { 3983389b1b11SMichael Tuexen struct mbuf *m_notify; 3984389b1b11SMichael Tuexen struct sctp_remote_error *sre; 3985389b1b11SMichael Tuexen struct sctp_queued_to_read *control; 39869a8e3088SMichael Tuexen unsigned int notif_len; 39879a8e3088SMichael Tuexen uint16_t chunk_len; 3988389b1b11SMichael Tuexen 3989389b1b11SMichael Tuexen if ((stcb == NULL) || 3990389b1b11SMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { 3991389b1b11SMichael Tuexen return; 3992389b1b11SMichael Tuexen } 3993389b1b11SMichael Tuexen if (chunk != NULL) { 3994c9eb4473SMichael Tuexen chunk_len = ntohs(chunk->ch.chunk_length); 39959669e724SMichael Tuexen /* 39969669e724SMichael Tuexen * Only SCTP_CHUNK_BUFFER_SIZE are guaranteed to be 399745d41de5SMichael Tuexen * contiguous. 39989669e724SMichael Tuexen */ 39999669e724SMichael Tuexen if (chunk_len > SCTP_CHUNK_BUFFER_SIZE) { 40009669e724SMichael Tuexen chunk_len = SCTP_CHUNK_BUFFER_SIZE; 40019669e724SMichael Tuexen } 4002389b1b11SMichael Tuexen } else { 4003389b1b11SMichael Tuexen chunk_len = 0; 4004389b1b11SMichael Tuexen } 40059a8e3088SMichael Tuexen notif_len = (unsigned int)(sizeof(struct sctp_remote_error) + chunk_len); 4006eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 4007389b1b11SMichael Tuexen if (m_notify == NULL) { 4008389b1b11SMichael Tuexen /* Retry with smaller value. */ 40099a8e3088SMichael Tuexen notif_len = (unsigned int)sizeof(struct sctp_remote_error); 4010eb1b1807SGleb Smirnoff m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_NOWAIT, 1, MT_DATA); 4011389b1b11SMichael Tuexen if (m_notify == NULL) { 4012389b1b11SMichael Tuexen return; 4013389b1b11SMichael Tuexen } 4014389b1b11SMichael Tuexen } 4015389b1b11SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 4016389b1b11SMichael Tuexen sre = mtod(m_notify, struct sctp_remote_error *); 401756711f94SMichael Tuexen memset(sre, 0, notif_len); 4018389b1b11SMichael Tuexen sre->sre_type = SCTP_REMOTE_ERROR; 4019389b1b11SMichael Tuexen sre->sre_flags = 0; 4020389b1b11SMichael Tuexen sre->sre_length = sizeof(struct sctp_remote_error); 4021389b1b11SMichael Tuexen sre->sre_error = error; 4022389b1b11SMichael Tuexen sre->sre_assoc_id = sctp_get_associd(stcb); 4023389b1b11SMichael Tuexen if (notif_len > sizeof(struct sctp_remote_error)) { 4024389b1b11SMichael Tuexen memcpy(sre->sre_data, chunk, chunk_len); 4025389b1b11SMichael Tuexen sre->sre_length += chunk_len; 4026389b1b11SMichael Tuexen } 4027389b1b11SMichael Tuexen SCTP_BUF_LEN(m_notify) = sre->sre_length; 4028389b1b11SMichael Tuexen control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 4029389b1b11SMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 4030389b1b11SMichael Tuexen m_notify); 4031389b1b11SMichael Tuexen if (control != NULL) { 4032389b1b11SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 403328cd0699SMichael Tuexen control->spec_flags = M_NOTIFICATION; 4034389b1b11SMichael Tuexen /* not that we need this */ 4035389b1b11SMichael Tuexen control->tail_mbuf = m_notify; 4036389b1b11SMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, 4037389b1b11SMichael Tuexen control, 4038389b1b11SMichael Tuexen &stcb->sctp_socket->so_rcv, 1, 4039389b1b11SMichael Tuexen SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 4040389b1b11SMichael Tuexen } else { 4041389b1b11SMichael Tuexen sctp_m_freem(m_notify); 4042389b1b11SMichael Tuexen } 4043389b1b11SMichael Tuexen } 4044389b1b11SMichael Tuexen 4045389b1b11SMichael Tuexen 4046f8829a4aSRandall Stewart void 4047f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, 4048ceaad40aSRandall Stewart uint32_t error, void *data, int so_locked 4049ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4050ceaad40aSRandall Stewart SCTP_UNUSED 4051ceaad40aSRandall Stewart #endif 4052ceaad40aSRandall Stewart ) 4053f8829a4aSRandall Stewart { 4054830d754dSRandall Stewart if ((stcb == NULL) || 4055830d754dSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4056f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 4057830d754dSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 4058830d754dSRandall Stewart /* If the socket is gone we are out of here */ 4059f8829a4aSRandall Stewart return; 4060f8829a4aSRandall Stewart } 4061a99b6783SRandall Stewart if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { 4062a99b6783SRandall Stewart return; 4063a99b6783SRandall Stewart } 4064839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 4065839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 406617205eccSRandall Stewart if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || 406717205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_UP) || 406817205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { 406917205eccSRandall Stewart /* Don't report these in front states */ 407017205eccSRandall Stewart return; 407117205eccSRandall Stewart } 407217205eccSRandall Stewart } 4073f8829a4aSRandall Stewart switch (notification) { 4074f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_UP: 4075f8829a4aSRandall Stewart if (stcb->asoc.assoc_up_sent == 0) { 4076410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked); 4077f8829a4aSRandall Stewart stcb->asoc.assoc_up_sent = 1; 4078f8829a4aSRandall Stewart } 40792afb3e84SRandall Stewart if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { 40807215cc1bSMichael Tuexen sctp_notify_adaptation_layer(stcb); 40812afb3e84SRandall Stewart } 4082c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 0) { 4083830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 4084830d754dSRandall Stewart NULL, so_locked); 4085830d754dSRandall Stewart } 4086f8829a4aSRandall Stewart break; 4087f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_DOWN: 4088410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked); 4089f8829a4aSRandall Stewart break; 4090f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_DOWN: 4091f8829a4aSRandall Stewart { 4092f8829a4aSRandall Stewart struct sctp_nets *net; 4093f8829a4aSRandall Stewart 4094f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 4095f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, 40963cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 4097f8829a4aSRandall Stewart break; 4098f8829a4aSRandall Stewart } 4099f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_UP: 4100f8829a4aSRandall Stewart { 4101f8829a4aSRandall Stewart struct sctp_nets *net; 4102f8829a4aSRandall Stewart 4103f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 4104f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, 41053cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 4106f8829a4aSRandall Stewart break; 4107f8829a4aSRandall Stewart } 4108f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_CONFIRMED: 4109f8829a4aSRandall Stewart { 4110f8829a4aSRandall Stewart struct sctp_nets *net; 4111f8829a4aSRandall Stewart 4112f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 4113f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, 41143cb3567dSMichael Tuexen (struct sockaddr *)&net->ro._l_addr, error, so_locked); 4115f8829a4aSRandall Stewart break; 4116f8829a4aSRandall Stewart } 4117f8829a4aSRandall Stewart case SCTP_NOTIFY_SPECIAL_SP_FAIL: 4118f8829a4aSRandall Stewart sctp_notify_send_failed2(stcb, error, 4119ceaad40aSRandall Stewart (struct sctp_stream_queue_pending *)data, so_locked); 4120f8829a4aSRandall Stewart break; 41211edc9dbaSMichael Tuexen case SCTP_NOTIFY_SENT_DG_FAIL: 41221edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 1, error, 41231edc9dbaSMichael Tuexen (struct sctp_tmit_chunk *)data, so_locked); 41241edc9dbaSMichael Tuexen break; 41251edc9dbaSMichael Tuexen case SCTP_NOTIFY_UNSENT_DG_FAIL: 41261edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 0, error, 4127ceaad40aSRandall Stewart (struct sctp_tmit_chunk *)data, so_locked); 4128f8829a4aSRandall Stewart break; 4129f8829a4aSRandall Stewart case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: 41309a6142d8SRandall Stewart { 41319a6142d8SRandall Stewart uint32_t val; 41329a6142d8SRandall Stewart 41339a6142d8SRandall Stewart val = *((uint32_t *)data); 41349a6142d8SRandall Stewart 4135810ec536SMichael Tuexen sctp_notify_partial_delivery_indication(stcb, error, val, so_locked); 4136f8829a4aSRandall Stewart break; 4137810ec536SMichael Tuexen } 4138410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_LOC_ABORTED: 4139839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 4140839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 4141410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked); 4142c105859eSRandall Stewart } else { 4143410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked); 4144410a3b1eSMichael Tuexen } 4145410a3b1eSMichael Tuexen break; 4146410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_REM_ABORTED: 4147839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) || 4148839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) { 4149410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked); 4150410a3b1eSMichael Tuexen } else { 4151410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked); 4152c105859eSRandall Stewart } 4153f8829a4aSRandall Stewart break; 4154f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_RESTART: 4155410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked); 4156c79bec9cSMichael Tuexen if (stcb->asoc.auth_supported == 0) { 4157830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 4158830d754dSRandall Stewart NULL, so_locked); 4159830d754dSRandall Stewart } 4160f8829a4aSRandall Stewart break; 4161f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_SEND: 4162d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_OUTGOING_SSN); 4163f8829a4aSRandall Stewart break; 4164f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_RECV: 4165d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), SCTP_STREAM_RESET_INCOMING); 4166f8829a4aSRandall Stewart break; 4167f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_OUT: 4168c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4169d7714577SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED)); 4170f8829a4aSRandall Stewart break; 4171d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_OUT: 4172d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4173d4260646SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED)); 4174d4260646SMichael Tuexen break; 4175f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_IN: 4176c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4177d7714577SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED)); 4178f8829a4aSRandall Stewart break; 4179d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_IN: 4180d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *)data), 4181d4260646SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED)); 4182d4260646SMichael Tuexen break; 4183f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_ADD_IP: 4184f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, 41853cb3567dSMichael Tuexen error, so_locked); 4186f8829a4aSRandall Stewart break; 4187f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_DELETE_IP: 4188f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, 41893cb3567dSMichael Tuexen error, so_locked); 4190f8829a4aSRandall Stewart break; 4191f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_SET_PRIMARY: 4192f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data, 41933cb3567dSMichael Tuexen error, so_locked); 4194f8829a4aSRandall Stewart break; 4195f8829a4aSRandall Stewart case SCTP_NOTIFY_PEER_SHUTDOWN: 4196f8829a4aSRandall Stewart sctp_notify_shutdown_event(stcb); 4197f8829a4aSRandall Stewart break; 4198f8829a4aSRandall Stewart case SCTP_NOTIFY_AUTH_NEW_KEY: 419978f28045SMichael Tuexen sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error, 4200830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 4201830d754dSRandall Stewart so_locked); 4202f8829a4aSRandall Stewart break; 4203830d754dSRandall Stewart case SCTP_NOTIFY_AUTH_FREE_KEY: 4204830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, 4205830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 4206830d754dSRandall Stewart so_locked); 4207f8829a4aSRandall Stewart break; 4208830d754dSRandall Stewart case SCTP_NOTIFY_NO_PEER_AUTH: 4209830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, 4210830d754dSRandall Stewart (uint16_t)(uintptr_t)data, 4211830d754dSRandall Stewart so_locked); 4212830d754dSRandall Stewart break; 4213830d754dSRandall Stewart case SCTP_NOTIFY_SENDER_DRY: 4214830d754dSRandall Stewart sctp_notify_sender_dry_event(stcb, so_locked); 4215830d754dSRandall Stewart break; 4216389b1b11SMichael Tuexen case SCTP_NOTIFY_REMOTE_ERROR: 4217389b1b11SMichael Tuexen sctp_notify_remote_error(stcb, error, data); 4218389b1b11SMichael Tuexen break; 4219f8829a4aSRandall Stewart default: 4220ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", 42216e9c45e0SMichael Tuexen __func__, notification, notification); 4222f8829a4aSRandall Stewart break; 4223f8829a4aSRandall Stewart } /* end switch */ 4224f8829a4aSRandall Stewart } 4225f8829a4aSRandall Stewart 4226f8829a4aSRandall Stewart void 42271edc9dbaSMichael Tuexen sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked 4228ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4229ceaad40aSRandall Stewart SCTP_UNUSED 4230ceaad40aSRandall Stewart #endif 4231ceaad40aSRandall Stewart ) 4232f8829a4aSRandall Stewart { 4233f8829a4aSRandall Stewart struct sctp_association *asoc; 4234f8829a4aSRandall Stewart struct sctp_stream_out *outs; 42354a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk; 42364a9ef3f8SMichael Tuexen struct sctp_stream_queue_pending *sp, *nsp; 42377f34832bSRandall Stewart int i; 4238f8829a4aSRandall Stewart 4239ad81507eSRandall Stewart if (stcb == NULL) { 4240ad81507eSRandall Stewart return; 4241ad81507eSRandall Stewart } 42424a9ef3f8SMichael Tuexen asoc = &stcb->asoc; 42434a9ef3f8SMichael Tuexen if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { 4244478fbccbSRandall Stewart /* already being freed */ 4245478fbccbSRandall Stewart return; 4246478fbccbSRandall Stewart } 4247f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4248f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 42494a9ef3f8SMichael Tuexen (asoc->state & SCTP_STATE_CLOSED_SOCKET)) { 4250f8829a4aSRandall Stewart return; 4251f8829a4aSRandall Stewart } 4252f8829a4aSRandall Stewart /* now through all the gunk freeing chunks */ 4253ad81507eSRandall Stewart if (holds_lock == 0) { 42547f34832bSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 4255ad81507eSRandall Stewart } 4256d00aff5dSRandall Stewart /* sent queue SHOULD be empty */ 42574a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { 4258d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); 4259d00aff5dSRandall Stewart asoc->sent_queue_cnt--; 4260325c8c46SMichael Tuexen if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { 426149656eefSMichael Tuexen if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { 426249656eefSMichael Tuexen asoc->strmout[chk->rec.data.sid].chunks_on_queues--; 4263a7ad6026SMichael Tuexen #ifdef INVARIANTS 4264a7ad6026SMichael Tuexen } else { 426549656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.sid); 4266a7ad6026SMichael Tuexen #endif 4267a7ad6026SMichael Tuexen } 4268a7ad6026SMichael Tuexen } 42690c0982b8SRandall Stewart if (chk->data != NULL) { 4270d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 42711edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 42721edc9dbaSMichael Tuexen error, chk, so_locked); 4273810ec536SMichael Tuexen if (chk->data) { 4274d00aff5dSRandall Stewart sctp_m_freem(chk->data); 4275d00aff5dSRandall Stewart chk->data = NULL; 4276d00aff5dSRandall Stewart } 4277810ec536SMichael Tuexen } 4278689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 4279d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 4280d00aff5dSRandall Stewart } 4281d00aff5dSRandall Stewart /* pending send queue SHOULD be empty */ 42824a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { 4283d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); 4284d00aff5dSRandall Stewart asoc->send_queue_cnt--; 428549656eefSMichael Tuexen if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { 428649656eefSMichael Tuexen asoc->strmout[chk->rec.data.sid].chunks_on_queues--; 4287a7ad6026SMichael Tuexen #ifdef INVARIANTS 4288a7ad6026SMichael Tuexen } else { 428949656eefSMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.sid); 4290a7ad6026SMichael Tuexen #endif 4291a7ad6026SMichael Tuexen } 42920c0982b8SRandall Stewart if (chk->data != NULL) { 4293d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 42941edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 42951edc9dbaSMichael Tuexen error, chk, so_locked); 4296810ec536SMichael Tuexen if (chk->data) { 4297d00aff5dSRandall Stewart sctp_m_freem(chk->data); 4298d00aff5dSRandall Stewart chk->data = NULL; 4299d00aff5dSRandall Stewart } 4300810ec536SMichael Tuexen } 4301689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 4302d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 4303d00aff5dSRandall Stewart } 43044a9ef3f8SMichael Tuexen for (i = 0; i < asoc->streamoutcnt; i++) { 43057f34832bSRandall Stewart /* For each stream */ 43064a9ef3f8SMichael Tuexen outs = &asoc->strmout[i]; 43077f34832bSRandall Stewart /* clean up any sends there */ 43084a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { 43094d58b0c3SMichael Tuexen atomic_subtract_int(&asoc->stream_queue_cnt, 1); 4310f8829a4aSRandall Stewart TAILQ_REMOVE(&outs->outqueue, sp, next); 4311d9707e43SMichael Tuexen stcb->asoc.ss_functions.sctp_ss_remove_from_stream(stcb, asoc, outs, sp, 1); 4312f8829a4aSRandall Stewart sctp_free_spbufspace(stcb, asoc, sp); 4313478fbccbSRandall Stewart if (sp->data) { 4314f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 43151edc9dbaSMichael Tuexen error, (void *)sp, so_locked); 4316f8829a4aSRandall Stewart if (sp->data) { 4317f8829a4aSRandall Stewart sctp_m_freem(sp->data); 4318f8829a4aSRandall Stewart sp->data = NULL; 4319d07b2ac6SMichael Tuexen sp->tail_mbuf = NULL; 4320d07b2ac6SMichael Tuexen sp->length = 0; 4321f8829a4aSRandall Stewart } 4322478fbccbSRandall Stewart } 43239eea4a2dSMichael Tuexen if (sp->net) { 4324f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 4325f8829a4aSRandall Stewart sp->net = NULL; 43269eea4a2dSMichael Tuexen } 4327f8829a4aSRandall Stewart /* Free the chunk */ 4328689e6a5fSMichael Tuexen sctp_free_a_strmoq(stcb, sp, so_locked); 43293c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 4330f8829a4aSRandall Stewart } 4331f8829a4aSRandall Stewart } 4332f8829a4aSRandall Stewart 4333ad81507eSRandall Stewart if (holds_lock == 0) { 43347f34832bSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 4335f8829a4aSRandall Stewart } 4336ad81507eSRandall Stewart } 4337f8829a4aSRandall Stewart 4338f8829a4aSRandall Stewart void 4339410a3b1eSMichael Tuexen sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error, 4340a2b42326SMichael Tuexen struct sctp_abort_chunk *abort, int so_locked 4341ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4342ceaad40aSRandall Stewart SCTP_UNUSED 4343ceaad40aSRandall Stewart #endif 4344ceaad40aSRandall Stewart ) 4345f8829a4aSRandall Stewart { 4346ad81507eSRandall Stewart if (stcb == NULL) { 4347ad81507eSRandall Stewart return; 4348ad81507eSRandall Stewart } 4349c55b70ceSMichael Tuexen if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 4350c55b70ceSMichael Tuexen ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 4351c55b70ceSMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { 4352c55b70ceSMichael Tuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; 4353c55b70ceSMichael Tuexen } 4354f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4355f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 4356f8829a4aSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 4357f8829a4aSRandall Stewart return; 4358f8829a4aSRandall Stewart } 4359f8829a4aSRandall Stewart /* Tell them we lost the asoc */ 43606982c0faSMichael Tuexen sctp_report_all_outbound(stcb, error, 0, so_locked); 4361410a3b1eSMichael Tuexen if (from_peer) { 4362410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); 4363410a3b1eSMichael Tuexen } else { 4364410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); 4365410a3b1eSMichael Tuexen } 4366f8829a4aSRandall Stewart } 4367f8829a4aSRandall Stewart 4368f8829a4aSRandall Stewart void 4369f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 4370b1754ad1SMichael Tuexen struct mbuf *m, int iphlen, 4371b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4372b1754ad1SMichael Tuexen struct sctphdr *sh, struct mbuf *op_err, 4373457b4b88SMichael Tuexen uint8_t mflowtype, uint32_t mflowid, 4374c54a18d2SRandall Stewart uint32_t vrf_id, uint16_t port) 4375f8829a4aSRandall Stewart { 4376f8829a4aSRandall Stewart uint32_t vtag; 4377ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4378ceaad40aSRandall Stewart struct socket *so; 4379ceaad40aSRandall Stewart #endif 4380ceaad40aSRandall Stewart 4381f8829a4aSRandall Stewart vtag = 0; 4382f8829a4aSRandall Stewart if (stcb != NULL) { 4383f8829a4aSRandall Stewart vtag = stcb->asoc.peer_vtag; 438417205eccSRandall Stewart vrf_id = stcb->asoc.vrf_id; 4385f8829a4aSRandall Stewart } 4386b1754ad1SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, 4387d089f9b9SMichael Tuexen mflowtype, mflowid, inp->fibnum, 4388f30ac432SMichael Tuexen vrf_id, port); 4389f8829a4aSRandall Stewart if (stcb != NULL) { 4390884d8c53SMichael Tuexen /* We have a TCB to abort, send notification too */ 4391884d8c53SMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); 4392839d21d6SMichael Tuexen SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED); 4393f8829a4aSRandall Stewart /* Ok, now lets free it */ 4394ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4395ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4396ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4397ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4398ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4399ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4400ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4401ceaad40aSRandall Stewart #endif 44020271d0cdSMichael Tuexen SCTP_STAT_INCR_COUNTER32(sctps_aborted); 4403839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || 4404839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 44050271d0cdSMichael Tuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 44060271d0cdSMichael Tuexen } 4407ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 4408ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_4); 4409ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4410ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4411ceaad40aSRandall Stewart #endif 4412f8829a4aSRandall Stewart } 4413f8829a4aSRandall Stewart } 4414f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 4415f1f73e57SRandall Stewart void 4416f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb) 4417f1f73e57SRandall Stewart { 441818e198d3SRandall Stewart #ifdef NOSIY_PRINTS 4419f1f73e57SRandall Stewart int i; 4420f1f73e57SRandall Stewart 4421ad81507eSRandall Stewart SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code); 4422ad81507eSRandall Stewart SCTP_PRINTF("IN bound TSN log-aaa\n"); 4423f1f73e57SRandall Stewart if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) { 4424ad81507eSRandall Stewart SCTP_PRINTF("None rcvd\n"); 4425f1f73e57SRandall Stewart goto none_in; 4426f1f73e57SRandall Stewart } 4427f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_wrapped) { 4428f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) { 4429ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4430f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 4431f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 4432f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 4433f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 4434f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 4435f1f73e57SRandall Stewart } 4436f1f73e57SRandall Stewart } 4437f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_at) { 4438f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_in_at; i++) { 4439ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4440f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 4441f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 4442f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 4443f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 4444f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 4445f1f73e57SRandall Stewart } 4446f1f73e57SRandall Stewart } 4447f1f73e57SRandall Stewart none_in: 4448ad81507eSRandall Stewart SCTP_PRINTF("OUT bound TSN log-aaa\n"); 4449ad81507eSRandall Stewart if ((stcb->asoc.tsn_out_at == 0) && 4450ad81507eSRandall Stewart (stcb->asoc.tsn_out_wrapped == 0)) { 4451ad81507eSRandall Stewart SCTP_PRINTF("None sent\n"); 4452f1f73e57SRandall Stewart } 4453f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_wrapped) { 4454f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) { 4455ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4456f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 4457f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 4458f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 4459f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 4460f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 4461f1f73e57SRandall Stewart } 4462f1f73e57SRandall Stewart } 4463f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_at) { 4464f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_out_at; i++) { 4465ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 4466f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 4467f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 4468f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 4469f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 4470f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 4471f1f73e57SRandall Stewart } 4472f1f73e57SRandall Stewart } 447318e198d3SRandall Stewart #endif 4474f1f73e57SRandall Stewart } 4475f1f73e57SRandall Stewart #endif 4476f1f73e57SRandall Stewart 4477f8829a4aSRandall Stewart void 4478f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 4479a2b42326SMichael Tuexen struct mbuf *op_err, 4480ceaad40aSRandall Stewart int so_locked 4481ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4482ceaad40aSRandall Stewart SCTP_UNUSED 4483ceaad40aSRandall Stewart #endif 4484ceaad40aSRandall Stewart ) 4485f8829a4aSRandall Stewart { 4486ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4487ceaad40aSRandall Stewart struct socket *so; 4488ceaad40aSRandall Stewart #endif 4489ceaad40aSRandall Stewart 4490ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4491ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4492ceaad40aSRandall Stewart #endif 4493f8829a4aSRandall Stewart if (stcb == NULL) { 4494f8829a4aSRandall Stewart /* Got to have a TCB */ 4495f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4496fe1831e0SMichael Tuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 4497b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4498b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4499f8829a4aSRandall Stewart } 4500f8829a4aSRandall Stewart } 4501f8829a4aSRandall Stewart return; 450263981c2bSRandall Stewart } else { 4503839d21d6SMichael Tuexen SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_WAS_ABORTED); 4504f8829a4aSRandall Stewart } 4505f8829a4aSRandall Stewart /* notify the peer */ 4506ceaad40aSRandall Stewart sctp_send_abort_tcb(stcb, op_err, so_locked); 4507f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_aborted); 4508839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) || 4509839d21d6SMichael Tuexen (SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 4510f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 4511f8829a4aSRandall Stewart } 4512884d8c53SMichael Tuexen /* notify the ulp */ 4513884d8c53SMichael Tuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 4514884d8c53SMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, so_locked); 4515884d8c53SMichael Tuexen } 4516f8829a4aSRandall Stewart /* now free the asoc */ 4517f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 4518f1f73e57SRandall Stewart sctp_print_out_track_log(stcb); 4519f1f73e57SRandall Stewart #endif 4520ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4521ceaad40aSRandall Stewart if (!so_locked) { 4522ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4523ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4524ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4525ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4526ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4527ceaad40aSRandall Stewart } 4528ceaad40aSRandall Stewart #endif 4529ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 4530ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_5); 4531ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4532ceaad40aSRandall Stewart if (!so_locked) { 4533ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4534ceaad40aSRandall Stewart } 4535ceaad40aSRandall Stewart #endif 4536f8829a4aSRandall Stewart } 4537f8829a4aSRandall Stewart 4538f8829a4aSRandall Stewart void 4539b1754ad1SMichael Tuexen sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, 4540b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4541b1754ad1SMichael Tuexen struct sctphdr *sh, struct sctp_inpcb *inp, 4542ff1ffd74SMichael Tuexen struct mbuf *cause, 4543d089f9b9SMichael Tuexen uint8_t mflowtype, uint32_t mflowid, uint16_t fibnum, 4544f30ac432SMichael Tuexen uint32_t vrf_id, uint16_t port) 4545f8829a4aSRandall Stewart { 4546f8829a4aSRandall Stewart struct sctp_chunkhdr *ch, chunk_buf; 4547f8829a4aSRandall Stewart unsigned int chk_length; 4548c58e60beSMichael Tuexen int contains_init_chunk; 4549f8829a4aSRandall Stewart 4550f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue); 4551f8829a4aSRandall Stewart /* Generate a TO address for future reference */ 4552f8829a4aSRandall Stewart if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 4553fe1831e0SMichael Tuexen if (LIST_EMPTY(&inp->sctp_asoc_list)) { 4554b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4555b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4556f8829a4aSRandall Stewart } 4557f8829a4aSRandall Stewart } 4558c58e60beSMichael Tuexen contains_init_chunk = 0; 4559f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4560f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4561f8829a4aSRandall Stewart while (ch != NULL) { 4562f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4563f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4564f8829a4aSRandall Stewart /* break to abort land */ 4565f8829a4aSRandall Stewart break; 4566f8829a4aSRandall Stewart } 4567f8829a4aSRandall Stewart switch (ch->chunk_type) { 4568c58e60beSMichael Tuexen case SCTP_INIT: 4569c58e60beSMichael Tuexen contains_init_chunk = 1; 4570c58e60beSMichael Tuexen break; 4571f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED: 4572f8829a4aSRandall Stewart /* we don't respond to pkt-dropped */ 4573f8829a4aSRandall Stewart return; 4574f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION: 4575f8829a4aSRandall Stewart /* we don't respond with an ABORT to an ABORT */ 4576f8829a4aSRandall Stewart return; 4577f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE: 4578f8829a4aSRandall Stewart /* 4579f8829a4aSRandall Stewart * we ignore it since we are not waiting for it and 4580f8829a4aSRandall Stewart * peer is gone 4581f8829a4aSRandall Stewart */ 4582f8829a4aSRandall Stewart return; 4583f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK: 4584b1754ad1SMichael Tuexen sctp_send_shutdown_complete2(src, dst, sh, 4585d089f9b9SMichael Tuexen mflowtype, mflowid, fibnum, 4586f30ac432SMichael Tuexen vrf_id, port); 4587f8829a4aSRandall Stewart return; 4588f8829a4aSRandall Stewart default: 4589f8829a4aSRandall Stewart break; 4590f8829a4aSRandall Stewart } 4591f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4592f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4593f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4594f8829a4aSRandall Stewart } 4595c58e60beSMichael Tuexen if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || 4596c58e60beSMichael Tuexen ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && 4597c58e60beSMichael Tuexen (contains_init_chunk == 0))) { 4598ff1ffd74SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, 0, cause, 4599d089f9b9SMichael Tuexen mflowtype, mflowid, fibnum, 4600f30ac432SMichael Tuexen vrf_id, port); 4601f8829a4aSRandall Stewart } 4602c58e60beSMichael Tuexen } 4603f8829a4aSRandall Stewart 4604f8829a4aSRandall Stewart /* 4605f8829a4aSRandall Stewart * check the inbound datagram to make sure there is not an abort inside it, 4606f8829a4aSRandall Stewart * if there is return 1, else return 0. 4607f8829a4aSRandall Stewart */ 4608f8829a4aSRandall Stewart int 4609f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t *vtagfill) 4610f8829a4aSRandall Stewart { 4611f8829a4aSRandall Stewart struct sctp_chunkhdr *ch; 4612f8829a4aSRandall Stewart struct sctp_init_chunk *init_chk, chunk_buf; 4613f8829a4aSRandall Stewart int offset; 4614f8829a4aSRandall Stewart unsigned int chk_length; 4615f8829a4aSRandall Stewart 4616f8829a4aSRandall Stewart offset = iphlen + sizeof(struct sctphdr); 4617f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), 4618f8829a4aSRandall Stewart (uint8_t *)&chunk_buf); 4619f8829a4aSRandall Stewart while (ch != NULL) { 4620f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4621f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4622f8829a4aSRandall Stewart /* packet is probably corrupt */ 4623f8829a4aSRandall Stewart break; 4624f8829a4aSRandall Stewart } 4625f8829a4aSRandall Stewart /* we seem to be ok, is it an abort? */ 4626f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) { 4627f8829a4aSRandall Stewart /* yep, tell them */ 4628f8829a4aSRandall Stewart return (1); 4629f8829a4aSRandall Stewart } 4630f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_INITIATION) { 4631f8829a4aSRandall Stewart /* need to update the Vtag */ 4632f8829a4aSRandall Stewart init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 4633f8829a4aSRandall Stewart offset, sizeof(*init_chk), (uint8_t *)&chunk_buf); 4634f8829a4aSRandall Stewart if (init_chk != NULL) { 4635f8829a4aSRandall Stewart *vtagfill = ntohl(init_chk->init.initiate_tag); 4636f8829a4aSRandall Stewart } 4637f8829a4aSRandall Stewart } 4638f8829a4aSRandall Stewart /* Nope, move to the next chunk */ 4639f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4640f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4641f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *)&chunk_buf); 4642f8829a4aSRandall Stewart } 4643f8829a4aSRandall Stewart return (0); 4644f8829a4aSRandall Stewart } 4645f8829a4aSRandall Stewart 4646f8829a4aSRandall Stewart /* 4647f8829a4aSRandall Stewart * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id 4648f8829a4aSRandall Stewart * set (i.e. it's 0) so, create this function to compare link local scopes 4649f8829a4aSRandall Stewart */ 46505e2c2d87SRandall Stewart #ifdef INET6 4651f8829a4aSRandall Stewart uint32_t 4652b0471b4bSMichael Tuexen sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2) 4653b0471b4bSMichael Tuexen { 4654f8829a4aSRandall Stewart struct sockaddr_in6 a, b; 4655f8829a4aSRandall Stewart 4656f8829a4aSRandall Stewart /* save copies */ 4657f8829a4aSRandall Stewart a = *addr1; 4658f8829a4aSRandall Stewart b = *addr2; 4659f8829a4aSRandall Stewart 4660f8829a4aSRandall Stewart if (a.sin6_scope_id == 0) 4661f8829a4aSRandall Stewart if (sa6_recoverscope(&a)) { 4662f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4663f8829a4aSRandall Stewart return (0); 4664f8829a4aSRandall Stewart } 4665f8829a4aSRandall Stewart if (b.sin6_scope_id == 0) 4666f8829a4aSRandall Stewart if (sa6_recoverscope(&b)) { 4667f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4668f8829a4aSRandall Stewart return (0); 4669f8829a4aSRandall Stewart } 4670f8829a4aSRandall Stewart if (a.sin6_scope_id != b.sin6_scope_id) 4671f8829a4aSRandall Stewart return (0); 4672f8829a4aSRandall Stewart 4673f8829a4aSRandall Stewart return (1); 4674f8829a4aSRandall Stewart } 4675f8829a4aSRandall Stewart 4676f8829a4aSRandall Stewart /* 4677f8829a4aSRandall Stewart * returns a sockaddr_in6 with embedded scope recovered and removed 4678f8829a4aSRandall Stewart */ 4679f8829a4aSRandall Stewart struct sockaddr_in6 * 4680f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store) 4681f8829a4aSRandall Stewart { 4682f8829a4aSRandall Stewart /* check and strip embedded scope junk */ 4683f8829a4aSRandall Stewart if (addr->sin6_family == AF_INET6) { 4684f8829a4aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) { 4685f8829a4aSRandall Stewart if (addr->sin6_scope_id == 0) { 4686f8829a4aSRandall Stewart *store = *addr; 4687f8829a4aSRandall Stewart if (!sa6_recoverscope(store)) { 4688f8829a4aSRandall Stewart /* use the recovered scope */ 4689f8829a4aSRandall Stewart addr = store; 4690f8829a4aSRandall Stewart } 4691f42a358aSRandall Stewart } else { 4692f8829a4aSRandall Stewart /* else, return the original "to" addr */ 4693f42a358aSRandall Stewart in6_clearscope(&addr->sin6_addr); 4694f8829a4aSRandall Stewart } 4695f8829a4aSRandall Stewart } 4696f8829a4aSRandall Stewart } 4697f8829a4aSRandall Stewart return (addr); 4698f8829a4aSRandall Stewart } 46995e2c2d87SRandall Stewart #endif 47005e2c2d87SRandall Stewart 4701f8829a4aSRandall Stewart /* 4702f8829a4aSRandall Stewart * are the two addresses the same? currently a "scopeless" check returns: 1 4703f8829a4aSRandall Stewart * if same, 0 if not 4704f8829a4aSRandall Stewart */ 470572fb6fdbSRandall Stewart int 4706f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2) 4707f8829a4aSRandall Stewart { 4708f8829a4aSRandall Stewart 4709f8829a4aSRandall Stewart /* must be valid */ 4710f8829a4aSRandall Stewart if (sa1 == NULL || sa2 == NULL) 4711f8829a4aSRandall Stewart return (0); 4712f8829a4aSRandall Stewart 4713f8829a4aSRandall Stewart /* must be the same family */ 4714f8829a4aSRandall Stewart if (sa1->sa_family != sa2->sa_family) 4715f8829a4aSRandall Stewart return (0); 4716f8829a4aSRandall Stewart 47175e2c2d87SRandall Stewart switch (sa1->sa_family) { 47185e2c2d87SRandall Stewart #ifdef INET6 47195e2c2d87SRandall Stewart case AF_INET6: 47205e2c2d87SRandall Stewart { 4721f8829a4aSRandall Stewart /* IPv6 addresses */ 4722f8829a4aSRandall Stewart struct sockaddr_in6 *sin6_1, *sin6_2; 4723f8829a4aSRandall Stewart 4724f8829a4aSRandall Stewart sin6_1 = (struct sockaddr_in6 *)sa1; 4725f8829a4aSRandall Stewart sin6_2 = (struct sockaddr_in6 *)sa2; 4726c54a18d2SRandall Stewart return (SCTP6_ARE_ADDR_EQUAL(sin6_1, 4727c54a18d2SRandall Stewart sin6_2)); 47285e2c2d87SRandall Stewart } 47295e2c2d87SRandall Stewart #endif 4730ea5eba11SMichael Tuexen #ifdef INET 47315e2c2d87SRandall Stewart case AF_INET: 47325e2c2d87SRandall Stewart { 4733f8829a4aSRandall Stewart /* IPv4 addresses */ 4734f8829a4aSRandall Stewart struct sockaddr_in *sin_1, *sin_2; 4735f8829a4aSRandall Stewart 4736f8829a4aSRandall Stewart sin_1 = (struct sockaddr_in *)sa1; 4737f8829a4aSRandall Stewart sin_2 = (struct sockaddr_in *)sa2; 4738f8829a4aSRandall Stewart return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr); 47395e2c2d87SRandall Stewart } 4740ea5eba11SMichael Tuexen #endif 47415e2c2d87SRandall Stewart default: 4742f8829a4aSRandall Stewart /* we don't do these... */ 4743f8829a4aSRandall Stewart return (0); 4744f8829a4aSRandall Stewart } 4745f8829a4aSRandall Stewart } 4746f8829a4aSRandall Stewart 4747f8829a4aSRandall Stewart void 4748f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa) 4749f8829a4aSRandall Stewart { 47505e2c2d87SRandall Stewart #ifdef INET6 47517d32aa0cSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 47525e2c2d87SRandall Stewart #endif 47535e2c2d87SRandall Stewart 47545e2c2d87SRandall Stewart switch (sa->sa_family) { 47555e2c2d87SRandall Stewart #ifdef INET6 47565e2c2d87SRandall Stewart case AF_INET6: 47575e2c2d87SRandall Stewart { 4758ad81507eSRandall Stewart struct sockaddr_in6 *sin6; 4759ad81507eSRandall Stewart 4760f8829a4aSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 4761ad81507eSRandall Stewart SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", 47627d32aa0cSBjoern A. Zeeb ip6_sprintf(ip6buf, &sin6->sin6_addr), 47637d32aa0cSBjoern A. Zeeb ntohs(sin6->sin6_port), 4764f8829a4aSRandall Stewart sin6->sin6_scope_id); 47655e2c2d87SRandall Stewart break; 47665e2c2d87SRandall Stewart } 47675e2c2d87SRandall Stewart #endif 4768ea5eba11SMichael Tuexen #ifdef INET 47695e2c2d87SRandall Stewart case AF_INET: 47705e2c2d87SRandall Stewart { 4771f8829a4aSRandall Stewart struct sockaddr_in *sin; 4772f8829a4aSRandall Stewart unsigned char *p; 4773f8829a4aSRandall Stewart 4774f8829a4aSRandall Stewart sin = (struct sockaddr_in *)sa; 4775f8829a4aSRandall Stewart p = (unsigned char *)&sin->sin_addr; 4776ad81507eSRandall Stewart SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n", 4777f8829a4aSRandall Stewart p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); 47785e2c2d87SRandall Stewart break; 47795e2c2d87SRandall Stewart } 4780ea5eba11SMichael Tuexen #endif 47815e2c2d87SRandall Stewart default: 4782ad81507eSRandall Stewart SCTP_PRINTF("?\n"); 47835e2c2d87SRandall Stewart break; 4784f8829a4aSRandall Stewart } 4785f8829a4aSRandall Stewart } 4786f8829a4aSRandall Stewart 4787f8829a4aSRandall Stewart void 4788f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, 4789f8829a4aSRandall Stewart struct sctp_inpcb *new_inp, 4790d06c82f1SRandall Stewart struct sctp_tcb *stcb, 4791d06c82f1SRandall Stewart int waitflags) 4792f8829a4aSRandall Stewart { 4793f8829a4aSRandall Stewart /* 4794f8829a4aSRandall Stewart * go through our old INP and pull off any control structures that 4795f8829a4aSRandall Stewart * belong to stcb and move then to the new inp. 4796f8829a4aSRandall Stewart */ 4797f8829a4aSRandall Stewart struct socket *old_so, *new_so; 4798f8829a4aSRandall Stewart struct sctp_queued_to_read *control, *nctl; 4799f8829a4aSRandall Stewart struct sctp_readhead tmp_queue; 4800f8829a4aSRandall Stewart struct mbuf *m; 4801bff64a4dSRandall Stewart int error = 0; 4802f8829a4aSRandall Stewart 4803f8829a4aSRandall Stewart old_so = old_inp->sctp_socket; 4804f8829a4aSRandall Stewart new_so = new_inp->sctp_socket; 4805f8829a4aSRandall Stewart TAILQ_INIT(&tmp_queue); 4806d06c82f1SRandall Stewart error = sblock(&old_so->so_rcv, waitflags); 4807f8829a4aSRandall Stewart if (error) { 4808f8829a4aSRandall Stewart /* 4809f8829a4aSRandall Stewart * Gak, can't get sblock, we have a problem. data will be 4810f8829a4aSRandall Stewart * left stranded.. and we don't dare look at it since the 4811f8829a4aSRandall Stewart * other thread may be reading something. Oh well, its a 4812f8829a4aSRandall Stewart * screwed up app that does a peeloff OR a accept while 4813f8829a4aSRandall Stewart * reading from the main socket... actually its only the 4814f8829a4aSRandall Stewart * peeloff() case, since I think read will fail on a 4815f8829a4aSRandall Stewart * listening socket.. 4816f8829a4aSRandall Stewart */ 4817f8829a4aSRandall Stewart return; 4818f8829a4aSRandall Stewart } 4819f8829a4aSRandall Stewart /* lock the socket buffers */ 4820f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(old_inp); 48214a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) { 4822f8829a4aSRandall Stewart /* Pull off all for out target stcb */ 4823f8829a4aSRandall Stewart if (control->stcb == stcb) { 4824f8829a4aSRandall Stewart /* remove it we want it */ 4825f8829a4aSRandall Stewart TAILQ_REMOVE(&old_inp->read_queue, control, next); 4826f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&tmp_queue, control, next); 4827f8829a4aSRandall Stewart m = control->data; 4828f8829a4aSRandall Stewart while (m) { 4829b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4830139bc87fSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 483180fefe0aSRandall Stewart } 4832f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &old_so->so_rcv, m); 4833b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4834f8829a4aSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 483580fefe0aSRandall Stewart } 4836139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4837f8829a4aSRandall Stewart } 4838f8829a4aSRandall Stewart } 4839f8829a4aSRandall Stewart } 4840f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(old_inp); 4841f8829a4aSRandall Stewart /* Remove the sb-lock on the old socket */ 4842f8829a4aSRandall Stewart 4843f8829a4aSRandall Stewart sbunlock(&old_so->so_rcv); 4844f8829a4aSRandall Stewart /* Now we move them over to the new socket buffer */ 4845f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(new_inp); 48464a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) { 4847f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next); 4848f8829a4aSRandall Stewart m = control->data; 4849f8829a4aSRandall Stewart while (m) { 4850b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4851139bc87fSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 485280fefe0aSRandall Stewart } 4853f8829a4aSRandall Stewart sctp_sballoc(stcb, &new_so->so_rcv, m); 4854b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4855f8829a4aSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 485680fefe0aSRandall Stewart } 4857139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4858f8829a4aSRandall Stewart } 4859f8829a4aSRandall Stewart } 4860f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(new_inp); 4861f8829a4aSRandall Stewart } 4862f8829a4aSRandall Stewart 4863f8829a4aSRandall Stewart void 4864b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(struct sctp_inpcb *inp, 4865b1deed45SMichael Tuexen struct sctp_tcb *stcb, 4866b1deed45SMichael Tuexen int so_locked 4867b1deed45SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4868b1deed45SMichael Tuexen SCTP_UNUSED 4869b1deed45SMichael Tuexen #endif 4870b1deed45SMichael Tuexen ) 487144249214SRandall Stewart { 4872b1deed45SMichael Tuexen if ((inp != NULL) && (inp->sctp_socket != NULL)) { 487344249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 487444249214SRandall Stewart struct socket *so; 487544249214SRandall Stewart 487644249214SRandall Stewart so = SCTP_INP_SO(inp); 487744249214SRandall Stewart if (!so_locked) { 487844249214SRandall Stewart if (stcb) { 487944249214SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 488044249214SRandall Stewart SCTP_TCB_UNLOCK(stcb); 488144249214SRandall Stewart } 488244249214SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 488344249214SRandall Stewart if (stcb) { 488444249214SRandall Stewart SCTP_TCB_LOCK(stcb); 488544249214SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 488644249214SRandall Stewart } 488744249214SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 488844249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 488944249214SRandall Stewart return; 489044249214SRandall Stewart } 489144249214SRandall Stewart } 489244249214SRandall Stewart #endif 489344249214SRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 489444249214SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 489544249214SRandall Stewart if (!so_locked) { 489644249214SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 489744249214SRandall Stewart } 489844249214SRandall Stewart #endif 489944249214SRandall Stewart } 490044249214SRandall Stewart } 490144249214SRandall Stewart 490244249214SRandall Stewart void 4903f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp, 4904f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4905f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4906f8829a4aSRandall Stewart struct sockbuf *sb, 4907ceaad40aSRandall Stewart int end, 4908cfde3ff7SRandall Stewart int inp_read_lock_held, 4909ceaad40aSRandall Stewart int so_locked 4910ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4911ceaad40aSRandall Stewart SCTP_UNUSED 4912ceaad40aSRandall Stewart #endif 4913ceaad40aSRandall Stewart ) 4914f8829a4aSRandall Stewart { 4915f8829a4aSRandall Stewart /* 4916f8829a4aSRandall Stewart * Here we must place the control on the end of the socket read 49174e88d37aSMichael Tuexen * queue AND increment sb_cc so that select will work properly on 4918f8829a4aSRandall Stewart * read. 4919f8829a4aSRandall Stewart */ 4920f8829a4aSRandall Stewart struct mbuf *m, *prev = NULL; 4921f8829a4aSRandall Stewart 492203b0b021SRandall Stewart if (inp == NULL) { 492303b0b021SRandall Stewart /* Gak, TSNH!! */ 4924a5d547adSRandall Stewart #ifdef INVARIANTS 492503b0b021SRandall Stewart panic("Gak, inp NULL on add_to_readq"); 492603b0b021SRandall Stewart #endif 492703b0b021SRandall Stewart return; 492803b0b021SRandall Stewart } 4929cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4930f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4931cd1386abSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 49328a3cfbffSMichael Tuexen if (!control->on_strm_q) { 4933cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4934cd1386abSMichael Tuexen if (control->data) { 4935cd1386abSMichael Tuexen sctp_m_freem(control->data); 4936cd1386abSMichael Tuexen control->data = NULL; 4937cd1386abSMichael Tuexen } 493844249214SRandall Stewart sctp_free_a_readq(stcb, control); 49398a3cfbffSMichael Tuexen } 4940cd1386abSMichael Tuexen if (inp_read_lock_held == 0) 4941cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4942cd1386abSMichael Tuexen return; 4943cd1386abSMichael Tuexen } 494442551e99SRandall Stewart if (!(control->spec_flags & M_NOTIFICATION)) { 4945a5d547adSRandall Stewart atomic_add_int(&inp->total_recvs, 1); 494642551e99SRandall Stewart if (!control->do_not_ref_stcb) { 4947a5d547adSRandall Stewart atomic_add_int(&stcb->total_recvs, 1); 494842551e99SRandall Stewart } 494942551e99SRandall Stewart } 4950f8829a4aSRandall Stewart m = control->data; 4951f8829a4aSRandall Stewart control->held_length = 0; 4952f8829a4aSRandall Stewart control->length = 0; 4953f8829a4aSRandall Stewart while (m) { 4954139bc87fSRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 4955f8829a4aSRandall Stewart /* Skip mbufs with NO length */ 4956f8829a4aSRandall Stewart if (prev == NULL) { 4957f8829a4aSRandall Stewart /* First one */ 4958f8829a4aSRandall Stewart control->data = sctp_m_free(m); 4959f8829a4aSRandall Stewart m = control->data; 4960f8829a4aSRandall Stewart } else { 4961139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 4962139bc87fSRandall Stewart m = SCTP_BUF_NEXT(prev); 4963f8829a4aSRandall Stewart } 4964f8829a4aSRandall Stewart if (m == NULL) { 4965c2ede4b3SMartin Blapp control->tail_mbuf = prev; 4966f8829a4aSRandall Stewart } 4967f8829a4aSRandall Stewart continue; 4968f8829a4aSRandall Stewart } 4969f8829a4aSRandall Stewart prev = m; 4970b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4971139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 497280fefe0aSRandall Stewart } 4973f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, m); 4974b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4975f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 497680fefe0aSRandall Stewart } 4977139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 4978139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4979f8829a4aSRandall Stewart } 4980f8829a4aSRandall Stewart if (prev != NULL) { 4981f8829a4aSRandall Stewart control->tail_mbuf = prev; 4982f8829a4aSRandall Stewart } else { 4983139bc87fSRandall Stewart /* Everything got collapsed out?? */ 49848a3cfbffSMichael Tuexen if (!control->on_strm_q) { 4985cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 498644249214SRandall Stewart sctp_free_a_readq(stcb, control); 49878a3cfbffSMichael Tuexen } 4988cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 498947a490cbSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4990f8829a4aSRandall Stewart return; 4991f8829a4aSRandall Stewart } 4992f8829a4aSRandall Stewart if (end) { 4993f8829a4aSRandall Stewart control->end_added = 1; 4994f8829a4aSRandall Stewart } 4995f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&inp->read_queue, control, next); 499644249214SRandall Stewart control->on_read_q = 1; 4997cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4998f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4999f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 5000b1deed45SMichael Tuexen sctp_wakeup_the_read_socket(inp, stcb, so_locked); 5001f8829a4aSRandall Stewart } 5002f8829a4aSRandall Stewart } 5003f8829a4aSRandall Stewart 5004f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF 5005f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 5006f8829a4aSRandall Stewart */ 5007f8829a4aSRandall Stewart 5008f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF 5009f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 5010f8829a4aSRandall Stewart */ 5011f8829a4aSRandall Stewart 5012f8829a4aSRandall Stewart struct mbuf * 5013ff1ffd74SMichael Tuexen sctp_generate_cause(uint16_t code, char *info) 5014f8829a4aSRandall Stewart { 5015f8829a4aSRandall Stewart struct mbuf *m; 5016ff1ffd74SMichael Tuexen struct sctp_gen_error_cause *cause; 50179a8e3088SMichael Tuexen size_t info_len; 50189a8e3088SMichael Tuexen uint16_t len; 5019f8829a4aSRandall Stewart 5020ff1ffd74SMichael Tuexen if ((code == 0) || (info == NULL)) { 5021ff1ffd74SMichael Tuexen return (NULL); 5022ff1ffd74SMichael Tuexen } 5023ff1ffd74SMichael Tuexen info_len = strlen(info); 50249a8e3088SMichael Tuexen if (info_len > (SCTP_MAX_CAUSE_LENGTH - sizeof(struct sctp_paramhdr))) { 50259a8e3088SMichael Tuexen return (NULL); 50269a8e3088SMichael Tuexen } 50279a8e3088SMichael Tuexen len = (uint16_t)(sizeof(struct sctp_paramhdr) + info_len); 5028ff1ffd74SMichael Tuexen m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); 5029ff1ffd74SMichael Tuexen if (m != NULL) { 5030ff1ffd74SMichael Tuexen SCTP_BUF_LEN(m) = len; 5031ff1ffd74SMichael Tuexen cause = mtod(m, struct sctp_gen_error_cause *); 5032ff1ffd74SMichael Tuexen cause->code = htons(code); 50339a8e3088SMichael Tuexen cause->length = htons(len); 5034ff1ffd74SMichael Tuexen memcpy(cause->info, info, info_len); 5035f8829a4aSRandall Stewart } 5036f8829a4aSRandall Stewart return (m); 5037f8829a4aSRandall Stewart } 5038f8829a4aSRandall Stewart 503932451da4SMichael Tuexen struct mbuf * 504032451da4SMichael Tuexen sctp_generate_no_user_data_cause(uint32_t tsn) 504132451da4SMichael Tuexen { 504232451da4SMichael Tuexen struct mbuf *m; 504332451da4SMichael Tuexen struct sctp_error_no_user_data *no_user_data_cause; 50449a8e3088SMichael Tuexen uint16_t len; 504532451da4SMichael Tuexen 50469a8e3088SMichael Tuexen len = (uint16_t)sizeof(struct sctp_error_no_user_data); 504732451da4SMichael Tuexen m = sctp_get_mbuf_for_msg(len, 0, M_NOWAIT, 1, MT_DATA); 504832451da4SMichael Tuexen if (m != NULL) { 504932451da4SMichael Tuexen SCTP_BUF_LEN(m) = len; 505032451da4SMichael Tuexen no_user_data_cause = mtod(m, struct sctp_error_no_user_data *); 505132451da4SMichael Tuexen no_user_data_cause->cause.code = htons(SCTP_CAUSE_NO_USER_DATA); 50529a8e3088SMichael Tuexen no_user_data_cause->cause.length = htons(len); 50538b9c95f4SMichael Tuexen no_user_data_cause->tsn = htonl(tsn); 505432451da4SMichael Tuexen } 505532451da4SMichael Tuexen return (m); 505632451da4SMichael Tuexen } 505732451da4SMichael Tuexen 5058f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING 5059f8829a4aSRandall Stewart void 5060f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, 5061f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, int chk_cnt) 5062f8829a4aSRandall Stewart { 5063f8829a4aSRandall Stewart if (tp1->data == NULL) { 5064f8829a4aSRandall Stewart return; 5065f8829a4aSRandall Stewart } 5066f8829a4aSRandall Stewart asoc->chunks_on_out_queue -= chk_cnt; 5067b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { 5068f8829a4aSRandall Stewart sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, 5069f8829a4aSRandall Stewart asoc->total_output_queue_size, 5070f8829a4aSRandall Stewart tp1->book_size, 5071f8829a4aSRandall Stewart 0, 5072f8829a4aSRandall Stewart tp1->mbcnt); 507380fefe0aSRandall Stewart } 5074f8829a4aSRandall Stewart if (asoc->total_output_queue_size >= tp1->book_size) { 507544b7479bSRandall Stewart atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size); 5076f8829a4aSRandall Stewart } else { 5077f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 5078f8829a4aSRandall Stewart } 5079f8829a4aSRandall Stewart 5080f8829a4aSRandall Stewart if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || 5081f8829a4aSRandall Stewart ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { 50824e88d37aSMichael Tuexen if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { 50834e88d37aSMichael Tuexen stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size; 5084f8829a4aSRandall Stewart } else { 50854e88d37aSMichael Tuexen stcb->sctp_socket->so_snd.sb_cc = 0; 5086f8829a4aSRandall Stewart 5087f8829a4aSRandall Stewart } 5088f8829a4aSRandall Stewart } 5089f8829a4aSRandall Stewart } 5090f8829a4aSRandall Stewart 5091f8829a4aSRandall Stewart #endif 5092f8829a4aSRandall Stewart 5093f8829a4aSRandall Stewart int 5094f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, 50951edc9dbaSMichael Tuexen uint8_t sent, int so_locked 5096ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 5097ceaad40aSRandall Stewart SCTP_UNUSED 5098ceaad40aSRandall Stewart #endif 5099ceaad40aSRandall Stewart ) 5100f8829a4aSRandall Stewart { 51010c0982b8SRandall Stewart struct sctp_stream_out *strq; 51024a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk = NULL, *tp2; 51030c0982b8SRandall Stewart struct sctp_stream_queue_pending *sp; 510449656eefSMichael Tuexen uint32_t mid; 510549656eefSMichael Tuexen uint16_t sid; 51060c0982b8SRandall Stewart uint8_t foundeom = 0; 5107f8829a4aSRandall Stewart int ret_sz = 0; 5108f8829a4aSRandall Stewart int notdone; 51090c0982b8SRandall Stewart int do_wakeup_routine = 0; 5110f8829a4aSRandall Stewart 511149656eefSMichael Tuexen sid = tp1->rec.data.sid; 511249656eefSMichael Tuexen mid = tp1->rec.data.mid; 5113f0396ad1SMichael Tuexen if (sent || !(tp1->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG)) { 5114f0396ad1SMichael Tuexen stcb->asoc.abandoned_sent[0]++; 5115f0396ad1SMichael Tuexen stcb->asoc.abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; 511649656eefSMichael Tuexen stcb->asoc.strmout[sid].abandoned_sent[0]++; 5117f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 5118ad15e154SMichael Tuexen stcb->asoc.strmout[sid].abandoned_sent[PR_SCTP_POLICY(tp1->flags)]++; 5119f0396ad1SMichael Tuexen #endif 5120f0396ad1SMichael Tuexen } else { 5121f0396ad1SMichael Tuexen stcb->asoc.abandoned_unsent[0]++; 5122f0396ad1SMichael Tuexen stcb->asoc.abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; 512349656eefSMichael Tuexen stcb->asoc.strmout[sid].abandoned_unsent[0]++; 5124f0396ad1SMichael Tuexen #if defined(SCTP_DETAILED_STR_STATS) 5125ad15e154SMichael Tuexen stcb->asoc.strmout[sid].abandoned_unsent[PR_SCTP_POLICY(tp1->flags)]++; 5126f0396ad1SMichael Tuexen #endif 5127f0396ad1SMichael Tuexen } 5128f8829a4aSRandall Stewart do { 5129f8829a4aSRandall Stewart ret_sz += tp1->book_size; 51300c0982b8SRandall Stewart if (tp1->data != NULL) { 51318933fa13SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 5132830d754dSRandall Stewart sctp_flight_size_decrease(tp1); 5133830d754dSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 51348933fa13SRandall Stewart } 51358933fa13SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 51360c0982b8SRandall Stewart stcb->asoc.peers_rwnd += tp1->send_size; 51370c0982b8SRandall Stewart stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); 51381edc9dbaSMichael Tuexen if (sent) { 51391edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 51401edc9dbaSMichael Tuexen } else { 51411edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 51421edc9dbaSMichael Tuexen } 51432f99457bSMichael Tuexen if (tp1->data) { 5144f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 5145f8829a4aSRandall Stewart tp1->data = NULL; 51462f99457bSMichael Tuexen } 51470c0982b8SRandall Stewart do_wakeup_routine = 1; 5148f8829a4aSRandall Stewart if (PR_SCTP_BUF_ENABLED(tp1->flags)) { 5149f8829a4aSRandall Stewart stcb->asoc.sent_queue_cnt_removeable--; 5150f8829a4aSRandall Stewart } 5151f8829a4aSRandall Stewart } 51528933fa13SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 5153f8829a4aSRandall Stewart if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 5154f8829a4aSRandall Stewart SCTP_DATA_NOT_FRAG) { 5155f8829a4aSRandall Stewart /* not frag'ed we ae done */ 5156f8829a4aSRandall Stewart notdone = 0; 5157f8829a4aSRandall Stewart foundeom = 1; 5158f8829a4aSRandall Stewart } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 5159f8829a4aSRandall Stewart /* end of frag, we are done */ 5160f8829a4aSRandall Stewart notdone = 0; 5161f8829a4aSRandall Stewart foundeom = 1; 5162f8829a4aSRandall Stewart } else { 5163f8829a4aSRandall Stewart /* 5164f8829a4aSRandall Stewart * Its a begin or middle piece, we must mark all of 5165f8829a4aSRandall Stewart * it 5166f8829a4aSRandall Stewart */ 5167f8829a4aSRandall Stewart notdone = 1; 5168f8829a4aSRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next); 5169f8829a4aSRandall Stewart } 5170f8829a4aSRandall Stewart } while (tp1 && notdone); 51710c0982b8SRandall Stewart if (foundeom == 0) { 5172f8829a4aSRandall Stewart /* 5173f8829a4aSRandall Stewart * The multi-part message was scattered across the send and 5174f8829a4aSRandall Stewart * sent queue. 5175f8829a4aSRandall Stewart */ 51764a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) { 517749656eefSMichael Tuexen if ((tp1->rec.data.sid != sid) || 517849656eefSMichael Tuexen (!SCTP_MID_EQ(stcb->asoc.idata_supported, tp1->rec.data.mid, mid))) { 51794a9ef3f8SMichael Tuexen break; 51804a9ef3f8SMichael Tuexen } 51810c0982b8SRandall Stewart /* 51820c0982b8SRandall Stewart * save to chk in case we have some on stream out 51830c0982b8SRandall Stewart * queue. If so and we have an un-transmitted one we 51840c0982b8SRandall Stewart * don't have to fudge the TSN. 51850c0982b8SRandall Stewart */ 51860c0982b8SRandall Stewart chk = tp1; 51870c0982b8SRandall Stewart ret_sz += tp1->book_size; 51880c0982b8SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 51891edc9dbaSMichael Tuexen if (sent) { 51901edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 51911edc9dbaSMichael Tuexen } else { 51921edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 51931edc9dbaSMichael Tuexen } 51942f99457bSMichael Tuexen if (tp1->data) { 51950c0982b8SRandall Stewart sctp_m_freem(tp1->data); 51962f99457bSMichael Tuexen tp1->data = NULL; 51972f99457bSMichael Tuexen } 51988933fa13SRandall Stewart /* No flight involved here book the size to 0 */ 51998933fa13SRandall Stewart tp1->book_size = 0; 52000c0982b8SRandall Stewart if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 52010c0982b8SRandall Stewart foundeom = 1; 5202f8829a4aSRandall Stewart } 52030c0982b8SRandall Stewart do_wakeup_routine = 1; 52040c0982b8SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 52050c0982b8SRandall Stewart TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next); 5206b7b84c0eSMichael Tuexen /* 5207b7b84c0eSMichael Tuexen * on to the sent queue so we can wait for it to be 5208b7b84c0eSMichael Tuexen * passed by. 5209b7b84c0eSMichael Tuexen */ 52100c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1, 52110c0982b8SRandall Stewart sctp_next); 52120c0982b8SRandall Stewart stcb->asoc.send_queue_cnt--; 52130c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 52140c0982b8SRandall Stewart } 52150c0982b8SRandall Stewart } 52160c0982b8SRandall Stewart if (foundeom == 0) { 52170c0982b8SRandall Stewart /* 52180c0982b8SRandall Stewart * Still no eom found. That means there is stuff left on the 52190c0982b8SRandall Stewart * stream out queue.. yuck. 52200c0982b8SRandall Stewart */ 52210c0982b8SRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 522249656eefSMichael Tuexen strq = &stcb->asoc.strmout[sid]; 5223f3b05218SMichael Tuexen sp = TAILQ_FIRST(&strq->outqueue); 5224f3b05218SMichael Tuexen if (sp != NULL) { 52250c0982b8SRandall Stewart sp->discard_rest = 1; 52260c0982b8SRandall Stewart /* 5227f3b05218SMichael Tuexen * We may need to put a chunk on the queue that 5228f3b05218SMichael Tuexen * holds the TSN that would have been sent with the 5229f3b05218SMichael Tuexen * LAST bit. 52300c0982b8SRandall Stewart */ 52310c0982b8SRandall Stewart if (chk == NULL) { 52320c0982b8SRandall Stewart /* Yep, we have to */ 52330c0982b8SRandall Stewart sctp_alloc_a_chunk(stcb, chk); 52340c0982b8SRandall Stewart if (chk == NULL) { 52350c0982b8SRandall Stewart /* 5236f3b05218SMichael Tuexen * we are hosed. All we can do is 5237f3b05218SMichael Tuexen * nothing.. which will cause an 5238f3b05218SMichael Tuexen * abort if the peer is paying 52390c0982b8SRandall Stewart * attention. 52400c0982b8SRandall Stewart */ 52410c0982b8SRandall Stewart goto oh_well; 52420c0982b8SRandall Stewart } 52430c0982b8SRandall Stewart memset(chk, 0, sizeof(*chk)); 524463d5b568SMichael Tuexen chk->rec.data.rcv_flags = 0; 52450c0982b8SRandall Stewart chk->sent = SCTP_FORWARD_TSN_SKIP; 52460c0982b8SRandall Stewart chk->asoc = &stcb->asoc; 524763d5b568SMichael Tuexen if (stcb->asoc.idata_supported == 0) { 524863d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 524949656eefSMichael Tuexen chk->rec.data.mid = 0; 525063d5b568SMichael Tuexen } else { 525149656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_ordered; 525263d5b568SMichael Tuexen } 525363d5b568SMichael Tuexen } else { 525463d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 525549656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_unordered; 525663d5b568SMichael Tuexen } else { 525749656eefSMichael Tuexen chk->rec.data.mid = strq->next_mid_ordered; 525863d5b568SMichael Tuexen } 525963d5b568SMichael Tuexen } 526049656eefSMichael Tuexen chk->rec.data.sid = sp->sid; 526149656eefSMichael Tuexen chk->rec.data.ppid = sp->ppid; 52620c0982b8SRandall Stewart chk->rec.data.context = sp->context; 52630c0982b8SRandall Stewart chk->flags = sp->act_flags; 52647fd5b436SMichael Tuexen chk->whoTo = NULL; 526549656eefSMichael Tuexen chk->rec.data.tsn = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); 52667fd5b436SMichael Tuexen strq->chunks_on_queues++; 52670c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); 52680c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 52698933fa13SRandall Stewart stcb->asoc.pr_sctp_cnt++; 52700c0982b8SRandall Stewart } 527163d5b568SMichael Tuexen chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; 5272d1ea5fa9SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 5273d1ea5fa9SMichael Tuexen chk->rec.data.rcv_flags |= SCTP_DATA_UNORDERED; 5274d1ea5fa9SMichael Tuexen } 527563d5b568SMichael Tuexen if (stcb->asoc.idata_supported == 0) { 527663d5b568SMichael Tuexen if ((sp->sinfo_flags & SCTP_UNORDERED) == 0) { 527763d5b568SMichael Tuexen strq->next_mid_ordered++; 527863d5b568SMichael Tuexen } 527963d5b568SMichael Tuexen } else { 528063d5b568SMichael Tuexen if (sp->sinfo_flags & SCTP_UNORDERED) { 528163d5b568SMichael Tuexen strq->next_mid_unordered++; 528263d5b568SMichael Tuexen } else { 528363d5b568SMichael Tuexen strq->next_mid_ordered++; 528463d5b568SMichael Tuexen } 528563d5b568SMichael Tuexen } 52860c0982b8SRandall Stewart oh_well: 52870c0982b8SRandall Stewart if (sp->data) { 52880c0982b8SRandall Stewart /* 5289f3b05218SMichael Tuexen * Pull any data to free up the SB and allow 5290f3b05218SMichael Tuexen * sender to "add more" while we will throw 5291f3b05218SMichael Tuexen * away :-) 52920c0982b8SRandall Stewart */ 5293f3b05218SMichael Tuexen sctp_free_spbufspace(stcb, &stcb->asoc, sp); 52940c0982b8SRandall Stewart ret_sz += sp->length; 52950c0982b8SRandall Stewart do_wakeup_routine = 1; 52960c0982b8SRandall Stewart sp->some_taken = 1; 52970c0982b8SRandall Stewart sctp_m_freem(sp->data); 52980c0982b8SRandall Stewart sp->data = NULL; 52990c0982b8SRandall Stewart sp->tail_mbuf = NULL; 5300d07b2ac6SMichael Tuexen sp->length = 0; 53010c0982b8SRandall Stewart } 53020c0982b8SRandall Stewart } 53030c0982b8SRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 53040c0982b8SRandall Stewart } 53050c0982b8SRandall Stewart if (do_wakeup_routine) { 53060c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 53078933fa13SRandall Stewart struct socket *so; 53088933fa13SRandall Stewart 53090c0982b8SRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 53100c0982b8SRandall Stewart if (!so_locked) { 53110c0982b8SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 53120c0982b8SRandall Stewart SCTP_TCB_UNLOCK(stcb); 53130c0982b8SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 53140c0982b8SRandall Stewart SCTP_TCB_LOCK(stcb); 53150c0982b8SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 53160c0982b8SRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 53170c0982b8SRandall Stewart /* assoc was freed while we were unlocked */ 53180c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 53190c0982b8SRandall Stewart return (ret_sz); 53200c0982b8SRandall Stewart } 53210c0982b8SRandall Stewart } 53220c0982b8SRandall Stewart #endif 53230c0982b8SRandall Stewart sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 53240c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 53250c0982b8SRandall Stewart if (!so_locked) { 53260c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 53270c0982b8SRandall Stewart } 53280c0982b8SRandall Stewart #endif 5329f8829a4aSRandall Stewart } 5330f8829a4aSRandall Stewart return (ret_sz); 5331f8829a4aSRandall Stewart } 5332f8829a4aSRandall Stewart 5333f8829a4aSRandall Stewart /* 5334f8829a4aSRandall Stewart * checks to see if the given address, sa, is one that is currently known by 5335f8829a4aSRandall Stewart * the kernel note: can't distinguish the same address on multiple interfaces 5336f8829a4aSRandall Stewart * and doesn't handle multiple addresses with different zone/scope id's note: 5337f8829a4aSRandall Stewart * ifa_ifwithaddr() compares the entire sockaddr struct 5338f8829a4aSRandall Stewart */ 533942551e99SRandall Stewart struct sctp_ifa * 534080fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, 534180fefe0aSRandall Stewart int holds_lock) 5342f8829a4aSRandall Stewart { 534342551e99SRandall Stewart struct sctp_laddr *laddr; 5344f8829a4aSRandall Stewart 5345ad81507eSRandall Stewart if (holds_lock == 0) { 534642551e99SRandall Stewart SCTP_INP_RLOCK(inp); 5347ad81507eSRandall Stewart } 53480053ed28SMichael Tuexen 534942551e99SRandall Stewart LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 535042551e99SRandall Stewart if (laddr->ifa == NULL) 5351f8829a4aSRandall Stewart continue; 535242551e99SRandall Stewart if (addr->sa_family != laddr->ifa->address.sa.sa_family) 535342551e99SRandall Stewart continue; 5354e6194c2eSMichael Tuexen #ifdef INET 535542551e99SRandall Stewart if (addr->sa_family == AF_INET) { 535642551e99SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 535742551e99SRandall Stewart laddr->ifa->address.sin.sin_addr.s_addr) { 535842551e99SRandall Stewart /* found him. */ 5359ad81507eSRandall Stewart if (holds_lock == 0) { 536042551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5361ad81507eSRandall Stewart } 536242551e99SRandall Stewart return (laddr->ifa); 536342551e99SRandall Stewart break; 536442551e99SRandall Stewart } 53655e2c2d87SRandall Stewart } 5366e6194c2eSMichael Tuexen #endif 53675e2c2d87SRandall Stewart #ifdef INET6 53685e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 5369c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 5370c54a18d2SRandall Stewart &laddr->ifa->address.sin6)) { 537142551e99SRandall Stewart /* found him. */ 5372ad81507eSRandall Stewart if (holds_lock == 0) { 537342551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5374ad81507eSRandall Stewart } 537542551e99SRandall Stewart return (laddr->ifa); 537642551e99SRandall Stewart break; 537742551e99SRandall Stewart } 537842551e99SRandall Stewart } 53795e2c2d87SRandall Stewart #endif 538042551e99SRandall Stewart } 5381ad81507eSRandall Stewart if (holds_lock == 0) { 538242551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 5383ad81507eSRandall Stewart } 538442551e99SRandall Stewart return (NULL); 538542551e99SRandall Stewart } 5386f8829a4aSRandall Stewart 53876a27c376SRandall Stewart uint32_t 5388b0471b4bSMichael Tuexen sctp_get_ifa_hash_val(struct sockaddr *addr) 5389b0471b4bSMichael Tuexen { 5390ea5eba11SMichael Tuexen switch (addr->sa_family) { 5391ea5eba11SMichael Tuexen #ifdef INET 5392ea5eba11SMichael Tuexen case AF_INET: 5393ea5eba11SMichael Tuexen { 53946a27c376SRandall Stewart struct sockaddr_in *sin; 53956a27c376SRandall Stewart 53966a27c376SRandall Stewart sin = (struct sockaddr_in *)addr; 53976a27c376SRandall Stewart return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); 5398ea5eba11SMichael Tuexen } 5399ea5eba11SMichael Tuexen #endif 5400ea5eba11SMichael Tuexen #ifdef INET6 54012c2e3218SMichael Tuexen case AF_INET6: 5402ea5eba11SMichael Tuexen { 54036a27c376SRandall Stewart struct sockaddr_in6 *sin6; 54046a27c376SRandall Stewart uint32_t hash_of_addr; 54056a27c376SRandall Stewart 54066a27c376SRandall Stewart sin6 = (struct sockaddr_in6 *)addr; 54076a27c376SRandall Stewart hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + 54086a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[1] + 54096a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[2] + 54106a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[3]); 54116a27c376SRandall Stewart hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); 54126a27c376SRandall Stewart return (hash_of_addr); 54136a27c376SRandall Stewart } 5414ea5eba11SMichael Tuexen #endif 5415ea5eba11SMichael Tuexen default: 5416ea5eba11SMichael Tuexen break; 5417ea5eba11SMichael Tuexen } 54186a27c376SRandall Stewart return (0); 54196a27c376SRandall Stewart } 54206a27c376SRandall Stewart 542142551e99SRandall Stewart struct sctp_ifa * 542242551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) 542342551e99SRandall Stewart { 542442551e99SRandall Stewart struct sctp_ifa *sctp_ifap; 542542551e99SRandall Stewart struct sctp_vrf *vrf; 54266a27c376SRandall Stewart struct sctp_ifalist *hash_head; 54276a27c376SRandall Stewart uint32_t hash_of_addr; 542842551e99SRandall Stewart 542942551e99SRandall Stewart if (holds_lock == 0) 5430c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 543142551e99SRandall Stewart 5432bff64a4dSRandall Stewart vrf = sctp_find_vrf(vrf_id); 5433bff64a4dSRandall Stewart if (vrf == NULL) { 5434bff64a4dSRandall Stewart if (holds_lock == 0) 5435c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5436bff64a4dSRandall Stewart return (NULL); 5437bff64a4dSRandall Stewart } 54380053ed28SMichael Tuexen 5439bff64a4dSRandall Stewart hash_of_addr = sctp_get_ifa_hash_val(addr); 5440bff64a4dSRandall Stewart 544117205eccSRandall Stewart hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; 5442bff64a4dSRandall Stewart if (hash_head == NULL) { 5443ad81507eSRandall Stewart SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ", 5444c99efcf6SRandall Stewart hash_of_addr, (uint32_t)vrf->vrf_addr_hashmark, 5445c99efcf6SRandall Stewart (uint32_t)(hash_of_addr & vrf->vrf_addr_hashmark)); 5446bff64a4dSRandall Stewart sctp_print_address(addr); 5447ad81507eSRandall Stewart SCTP_PRINTF("No such bucket for address\n"); 5448bff64a4dSRandall Stewart if (holds_lock == 0) 5449c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5450bff64a4dSRandall Stewart 5451bff64a4dSRandall Stewart return (NULL); 5452bff64a4dSRandall Stewart } 54536a27c376SRandall Stewart LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { 54546a27c376SRandall Stewart if (addr->sa_family != sctp_ifap->address.sa.sa_family) 54556a27c376SRandall Stewart continue; 5456e6194c2eSMichael Tuexen #ifdef INET 54576a27c376SRandall Stewart if (addr->sa_family == AF_INET) { 54586a27c376SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 54596a27c376SRandall Stewart sctp_ifap->address.sin.sin_addr.s_addr) { 54606a27c376SRandall Stewart /* found him. */ 546142551e99SRandall Stewart if (holds_lock == 0) 5462c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 546342551e99SRandall Stewart return (sctp_ifap); 54646a27c376SRandall Stewart break; 54656a27c376SRandall Stewart } 54665e2c2d87SRandall Stewart } 5467e6194c2eSMichael Tuexen #endif 54685e2c2d87SRandall Stewart #ifdef INET6 54695e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 5470c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 5471c54a18d2SRandall Stewart &sctp_ifap->address.sin6)) { 54726a27c376SRandall Stewart /* found him. */ 54736a27c376SRandall Stewart if (holds_lock == 0) 5474c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 54756a27c376SRandall Stewart return (sctp_ifap); 54766a27c376SRandall Stewart break; 54776a27c376SRandall Stewart } 547842551e99SRandall Stewart } 54795e2c2d87SRandall Stewart #endif 548042551e99SRandall Stewart } 548142551e99SRandall Stewart if (holds_lock == 0) 5482c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5483f8829a4aSRandall Stewart return (NULL); 5484f8829a4aSRandall Stewart } 5485f8829a4aSRandall Stewart 5486f8829a4aSRandall Stewart static void 54874c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t *freed_so_far, int hold_rlock, 5488f8829a4aSRandall Stewart uint32_t rwnd_req) 5489f8829a4aSRandall Stewart { 5490f8829a4aSRandall Stewart /* User pulled some data, do we need a rwnd update? */ 5491868b51f2SMichael Tuexen struct epoch_tracker et; 5492f8829a4aSRandall Stewart int r_unlocked = 0; 5493f8829a4aSRandall Stewart uint32_t dif, rwnd; 5494f8829a4aSRandall Stewart struct socket *so = NULL; 5495f8829a4aSRandall Stewart 5496f8829a4aSRandall Stewart if (stcb == NULL) 5497f8829a4aSRandall Stewart return; 5498f8829a4aSRandall Stewart 549950cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5500f8829a4aSRandall Stewart 5501839d21d6SMichael Tuexen if ((SCTP_GET_STATE(stcb) == SCTP_STATE_SHUTDOWN_ACK_SENT) || 550261a21880SMichael Tuexen (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | SCTP_STATE_SHUTDOWN_RECEIVED))) { 5503f8829a4aSRandall Stewart /* Pre-check If we are freeing no update */ 5504f8829a4aSRandall Stewart goto no_lock; 5505f8829a4aSRandall Stewart } 5506f8829a4aSRandall Stewart SCTP_INP_INCR_REF(stcb->sctp_ep); 5507f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5508f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5509f8829a4aSRandall Stewart goto out; 5510f8829a4aSRandall Stewart } 5511f8829a4aSRandall Stewart so = stcb->sctp_socket; 5512f8829a4aSRandall Stewart if (so == NULL) { 5513f8829a4aSRandall Stewart goto out; 5514f8829a4aSRandall Stewart } 5515f8829a4aSRandall Stewart atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); 5516f8829a4aSRandall Stewart /* Have you have freed enough to look */ 5517f8829a4aSRandall Stewart *freed_so_far = 0; 5518f8829a4aSRandall Stewart /* Yep, its worth a look and the lock overhead */ 5519f8829a4aSRandall Stewart 5520f8829a4aSRandall Stewart /* Figure out what the rwnd would be */ 5521f8829a4aSRandall Stewart rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); 5522f8829a4aSRandall Stewart if (rwnd >= stcb->asoc.my_last_reported_rwnd) { 5523f8829a4aSRandall Stewart dif = rwnd - stcb->asoc.my_last_reported_rwnd; 5524f8829a4aSRandall Stewart } else { 5525f8829a4aSRandall Stewart dif = 0; 5526f8829a4aSRandall Stewart } 5527f8829a4aSRandall Stewart if (dif >= rwnd_req) { 5528f8829a4aSRandall Stewart if (hold_rlock) { 5529f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 5530f8829a4aSRandall Stewart r_unlocked = 1; 5531f8829a4aSRandall Stewart } 5532f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5533f8829a4aSRandall Stewart /* 5534f8829a4aSRandall Stewart * One last check before we allow the guy possibly 5535f8829a4aSRandall Stewart * to get in. There is a race, where the guy has not 5536f8829a4aSRandall Stewart * reached the gate. In that case 5537f8829a4aSRandall Stewart */ 5538f8829a4aSRandall Stewart goto out; 5539f8829a4aSRandall Stewart } 5540f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 5541f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5542f8829a4aSRandall Stewart /* No reports here */ 5543f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5544f8829a4aSRandall Stewart goto out; 5545f8829a4aSRandall Stewart } 5546f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_wu_sacks_sent); 5547868b51f2SMichael Tuexen NET_EPOCH_ENTER(et); 5548689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_LOCKED); 5549830d754dSRandall Stewart 5550f8829a4aSRandall Stewart sctp_chunk_output(stcb->sctp_ep, stcb, 5551ceaad40aSRandall Stewart SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); 5552f8829a4aSRandall Stewart /* make sure no timer is running */ 5553868b51f2SMichael Tuexen NET_EPOCH_EXIT(et); 5554ba785902SMichael Tuexen sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, 5555ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_6); 5556f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5557f8829a4aSRandall Stewart } else { 5558f8829a4aSRandall Stewart /* Update how much we have pending */ 5559f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = dif; 5560f8829a4aSRandall Stewart } 5561f8829a4aSRandall Stewart out: 5562f8829a4aSRandall Stewart if (so && r_unlocked && hold_rlock) { 5563f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 5564f8829a4aSRandall Stewart } 55650053ed28SMichael Tuexen 5566f8829a4aSRandall Stewart SCTP_INP_DECR_REF(stcb->sctp_ep); 5567f8829a4aSRandall Stewart no_lock: 556850cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 5569f8829a4aSRandall Stewart return; 5570f8829a4aSRandall Stewart } 5571f8829a4aSRandall Stewart 5572f8829a4aSRandall Stewart int 5573f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so, 5574f8829a4aSRandall Stewart struct uio *uio, 5575f8829a4aSRandall Stewart struct mbuf **mp, 5576f8829a4aSRandall Stewart struct sockaddr *from, 5577f8829a4aSRandall Stewart int fromlen, 5578f8829a4aSRandall Stewart int *msg_flags, 5579f8829a4aSRandall Stewart struct sctp_sndrcvinfo *sinfo, 5580f8829a4aSRandall Stewart int filling_sinfo) 5581f8829a4aSRandall Stewart { 5582f8829a4aSRandall Stewart /* 5583f8829a4aSRandall Stewart * MSG flags we will look at MSG_DONTWAIT - non-blocking IO. 5584f8829a4aSRandall Stewart * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy 5585f8829a4aSRandall Stewart * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ?? 5586f8829a4aSRandall Stewart * On the way out we may send out any combination of: 5587f8829a4aSRandall Stewart * MSG_NOTIFICATION MSG_EOR 5588f8829a4aSRandall Stewart * 5589f8829a4aSRandall Stewart */ 5590f8829a4aSRandall Stewart struct sctp_inpcb *inp = NULL; 559158e6eeefSMichael Tuexen ssize_t my_len = 0; 559258e6eeefSMichael Tuexen ssize_t cp_len = 0; 55930d3cf13dSMichael Tuexen int error = 0; 5594f8829a4aSRandall Stewart struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; 559594b0d969SMichael Tuexen struct mbuf *m = NULL; 5596f8829a4aSRandall Stewart struct sctp_tcb *stcb = NULL; 5597f8829a4aSRandall Stewart int wakeup_read_socket = 0; 5598f8829a4aSRandall Stewart int freecnt_applied = 0; 5599f8829a4aSRandall Stewart int out_flags = 0, in_flags = 0; 5600f8829a4aSRandall Stewart int block_allowed = 1; 56014c9179adSRandall Stewart uint32_t freed_so_far = 0; 560258e6eeefSMichael Tuexen ssize_t copied_so_far = 0; 560393164cf9SRandall Stewart int in_eeor_mode = 0; 5604f8829a4aSRandall Stewart int no_rcv_needed = 0; 5605f8829a4aSRandall Stewart uint32_t rwnd_req = 0; 5606f8829a4aSRandall Stewart int hold_sblock = 0; 5607f8829a4aSRandall Stewart int hold_rlock = 0; 56089a8e3088SMichael Tuexen ssize_t slen = 0; 56094c9179adSRandall Stewart uint32_t held_length = 0; 56107abab911SRobert Watson int sockbuf_lock = 0; 5611f8829a4aSRandall Stewart 561217205eccSRandall Stewart if (uio == NULL) { 5613c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 561417205eccSRandall Stewart return (EINVAL); 561517205eccSRandall Stewart } 56160053ed28SMichael Tuexen 5617f8829a4aSRandall Stewart if (msg_flags) { 5618f8829a4aSRandall Stewart in_flags = *msg_flags; 5619c105859eSRandall Stewart if (in_flags & MSG_PEEK) 5620c105859eSRandall Stewart SCTP_STAT_INCR(sctps_read_peeks); 5621f8829a4aSRandall Stewart } else { 5622f8829a4aSRandall Stewart in_flags = 0; 5623f8829a4aSRandall Stewart } 5624f8829a4aSRandall Stewart slen = uio->uio_resid; 562517205eccSRandall Stewart 5626f8829a4aSRandall Stewart /* Pull in and set up our int flags */ 5627f8829a4aSRandall Stewart if (in_flags & MSG_OOB) { 5628f8829a4aSRandall Stewart /* Out of band's NOT supported */ 5629f8829a4aSRandall Stewart return (EOPNOTSUPP); 5630f8829a4aSRandall Stewart } 5631f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) && (mp != NULL)) { 5632c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 5633f8829a4aSRandall Stewart return (EINVAL); 5634f8829a4aSRandall Stewart } 5635f8829a4aSRandall Stewart if ((in_flags & (MSG_DONTWAIT 5636f8829a4aSRandall Stewart | MSG_NBIO 5637f8829a4aSRandall Stewart )) || 563842551e99SRandall Stewart SCTP_SO_IS_NBIO(so)) { 5639f8829a4aSRandall Stewart block_allowed = 0; 5640f8829a4aSRandall Stewart } 5641f8829a4aSRandall Stewart /* setup the endpoint */ 5642f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 5643f8829a4aSRandall Stewart if (inp == NULL) { 5644c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 5645f8829a4aSRandall Stewart return (EFAULT); 5646f8829a4aSRandall Stewart } 564762c1ff9cSRandall Stewart rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); 5648f8829a4aSRandall Stewart /* Must be at least a MTU's worth */ 5649f8829a4aSRandall Stewart if (rwnd_req < SCTP_MIN_RWND) 5650f8829a4aSRandall Stewart rwnd_req = SCTP_MIN_RWND; 5651f8829a4aSRandall Stewart in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 5652b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5653f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTER, 56549a8e3088SMichael Tuexen rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); 565580fefe0aSRandall Stewart } 5656b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5657f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTERPL, 56589a8e3088SMichael Tuexen rwnd_req, block_allowed, so->so_rcv.sb_cc, (uint32_t)uio->uio_resid); 565980fefe0aSRandall Stewart } 56600053ed28SMichael Tuexen 56610053ed28SMichael Tuexen 5662265de5bbSRobert Watson error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); 5663f8829a4aSRandall Stewart if (error) { 5664f8829a4aSRandall Stewart goto release_unlocked; 5665f8829a4aSRandall Stewart } 56668e1e6e5fSMateusz Guzik sockbuf_lock = 1; 5667f8829a4aSRandall Stewart restart: 56687abab911SRobert Watson 5669f8829a4aSRandall Stewart 5670f8829a4aSRandall Stewart restart_nosblocks: 5671f8829a4aSRandall Stewart if (hold_sblock == 0) { 5672f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5673f8829a4aSRandall Stewart hold_sblock = 1; 5674f8829a4aSRandall Stewart } 5675f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5676f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5677f8829a4aSRandall Stewart goto out; 5678f8829a4aSRandall Stewart } 56794e88d37aSMichael Tuexen if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) { 5680f8829a4aSRandall Stewart if (so->so_error) { 5681f8829a4aSRandall Stewart error = so->so_error; 568244b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 568344b7479bSRandall Stewart so->so_error = 0; 56849f22f500SRandall Stewart goto out; 5685f8829a4aSRandall Stewart } else { 56864e88d37aSMichael Tuexen if (so->so_rcv.sb_cc == 0) { 56877924093fSRandall Stewart /* indicate EOF */ 56887924093fSRandall Stewart error = 0; 5689f8829a4aSRandall Stewart goto out; 5690f8829a4aSRandall Stewart } 56919f22f500SRandall Stewart } 56929f22f500SRandall Stewart } 56939de217ceSMichael Tuexen if (so->so_rcv.sb_cc <= held_length) { 56949de217ceSMichael Tuexen if (so->so_error) { 56959de217ceSMichael Tuexen error = so->so_error; 56969de217ceSMichael Tuexen if ((in_flags & MSG_PEEK) == 0) { 56979de217ceSMichael Tuexen so->so_error = 0; 56989de217ceSMichael Tuexen } 56999de217ceSMichael Tuexen goto out; 57009de217ceSMichael Tuexen } 57014e88d37aSMichael Tuexen if ((so->so_rcv.sb_cc == 0) && 5702f8829a4aSRandall Stewart ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5703f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 5704f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 5705f8829a4aSRandall Stewart /* 5706f8829a4aSRandall Stewart * For active open side clear flags for 5707f8829a4aSRandall Stewart * re-use passive open is blocked by 5708f8829a4aSRandall Stewart * connect. 5709f8829a4aSRandall Stewart */ 5710f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 5711b7b84c0eSMichael Tuexen /* 5712b7b84c0eSMichael Tuexen * You were aborted, passive side 5713b7b84c0eSMichael Tuexen * always hits here 5714b7b84c0eSMichael Tuexen */ 5715c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 5716f8829a4aSRandall Stewart error = ECONNRESET; 5717f8829a4aSRandall Stewart } 5718f8829a4aSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 5719f8829a4aSRandall Stewart SS_ISDISCONNECTING | 5720f8829a4aSRandall Stewart SS_ISCONFIRMING | 5721f8829a4aSRandall Stewart SS_ISCONNECTED); 5722f8829a4aSRandall Stewart if (error == 0) { 5723f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5724c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 5725f8829a4aSRandall Stewart error = ENOTCONN; 5726f8829a4aSRandall Stewart } 5727f8829a4aSRandall Stewart } 5728f8829a4aSRandall Stewart goto out; 5729f8829a4aSRandall Stewart } 5730f8829a4aSRandall Stewart } 57319de217ceSMichael Tuexen if (block_allowed) { 5732f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5733f8829a4aSRandall Stewart if (error) { 5734f8829a4aSRandall Stewart goto out; 5735f8829a4aSRandall Stewart } 5736f8829a4aSRandall Stewart held_length = 0; 5737f8829a4aSRandall Stewart goto restart_nosblocks; 573844b7479bSRandall Stewart } else { 5739c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); 5740f8829a4aSRandall Stewart error = EWOULDBLOCK; 5741f8829a4aSRandall Stewart goto out; 5742f8829a4aSRandall Stewart } 57439de217ceSMichael Tuexen } 5744d06c82f1SRandall Stewart if (hold_sblock == 1) { 5745d06c82f1SRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5746d06c82f1SRandall Stewart hold_sblock = 0; 5747d06c82f1SRandall Stewart } 5748f8829a4aSRandall Stewart /* we possibly have data we can read */ 57493c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 5750f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5751f8829a4aSRandall Stewart if (control == NULL) { 5752f8829a4aSRandall Stewart /* 5753f8829a4aSRandall Stewart * This could be happening since the appender did the 5754f8829a4aSRandall Stewart * increment but as not yet did the tailq insert onto the 5755f8829a4aSRandall Stewart * read_queue 5756f8829a4aSRandall Stewart */ 5757f8829a4aSRandall Stewart if (hold_rlock == 0) { 5758f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5759f8829a4aSRandall Stewart } 5760f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 57614e88d37aSMichael Tuexen if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { 5762a5d547adSRandall Stewart #ifdef INVARIANTS 5763f8829a4aSRandall Stewart panic("Huh, its non zero and nothing on control?"); 5764f8829a4aSRandall Stewart #endif 57654e88d37aSMichael Tuexen so->so_rcv.sb_cc = 0; 5766f8829a4aSRandall Stewart } 5767f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5768f8829a4aSRandall Stewart hold_rlock = 0; 5769f8829a4aSRandall Stewart goto restart; 5770f8829a4aSRandall Stewart } 57710053ed28SMichael Tuexen 5772f8829a4aSRandall Stewart if ((control->length == 0) && 5773f8829a4aSRandall Stewart (control->do_not_ref_stcb)) { 5774f8829a4aSRandall Stewart /* 5775f8829a4aSRandall Stewart * Clean up code for freeing assoc that left behind a 5776f8829a4aSRandall Stewart * pdapi.. maybe a peer in EEOR that just closed after 5777f8829a4aSRandall Stewart * sending and never indicated a EOR. 5778f8829a4aSRandall Stewart */ 5779f8829a4aSRandall Stewart if (hold_rlock == 0) { 5780f8829a4aSRandall Stewart hold_rlock = 1; 5781f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5782f8829a4aSRandall Stewart } 5783f8829a4aSRandall Stewart control->held_length = 0; 5784f8829a4aSRandall Stewart if (control->data) { 5785f8829a4aSRandall Stewart /* Hmm there is data here .. fix */ 57864c9179adSRandall Stewart struct mbuf *m_tmp; 5787f8829a4aSRandall Stewart int cnt = 0; 5788f8829a4aSRandall Stewart 57894c9179adSRandall Stewart m_tmp = control->data; 57904c9179adSRandall Stewart while (m_tmp) { 57914c9179adSRandall Stewart cnt += SCTP_BUF_LEN(m_tmp); 57924c9179adSRandall Stewart if (SCTP_BUF_NEXT(m_tmp) == NULL) { 57934c9179adSRandall Stewart control->tail_mbuf = m_tmp; 5794f8829a4aSRandall Stewart control->end_added = 1; 5795f8829a4aSRandall Stewart } 57964c9179adSRandall Stewart m_tmp = SCTP_BUF_NEXT(m_tmp); 5797f8829a4aSRandall Stewart } 5798f8829a4aSRandall Stewart control->length = cnt; 5799f8829a4aSRandall Stewart } else { 5800f8829a4aSRandall Stewart /* remove it */ 5801f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5802f8829a4aSRandall Stewart /* Add back any hiddend data */ 5803f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5804f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5805f8829a4aSRandall Stewart } 5806f8829a4aSRandall Stewart if (hold_rlock) { 5807f8829a4aSRandall Stewart hold_rlock = 0; 5808f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5809f8829a4aSRandall Stewart } 5810f8829a4aSRandall Stewart goto restart; 5811f8829a4aSRandall Stewart } 5812810ec536SMichael Tuexen if ((control->length == 0) && 5813810ec536SMichael Tuexen (control->end_added == 1)) { 5814b7b84c0eSMichael Tuexen /* 5815b7b84c0eSMichael Tuexen * Do we also need to check for (control->pdapi_aborted == 5816b7b84c0eSMichael Tuexen * 1)? 5817b7b84c0eSMichael Tuexen */ 5818810ec536SMichael Tuexen if (hold_rlock == 0) { 5819810ec536SMichael Tuexen hold_rlock = 1; 5820810ec536SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5821810ec536SMichael Tuexen } 5822810ec536SMichael Tuexen TAILQ_REMOVE(&inp->read_queue, control, next); 5823810ec536SMichael Tuexen if (control->data) { 5824810ec536SMichael Tuexen #ifdef INVARIANTS 5825810ec536SMichael Tuexen panic("control->data not null but control->length == 0"); 5826810ec536SMichael Tuexen #else 5827810ec536SMichael Tuexen SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n"); 5828810ec536SMichael Tuexen sctp_m_freem(control->data); 5829810ec536SMichael Tuexen control->data = NULL; 5830810ec536SMichael Tuexen #endif 5831810ec536SMichael Tuexen } 5832810ec536SMichael Tuexen if (control->aux_data) { 5833810ec536SMichael Tuexen sctp_m_free(control->aux_data); 5834810ec536SMichael Tuexen control->aux_data = NULL; 5835810ec536SMichael Tuexen } 583698d5fd97SMichael Tuexen #ifdef INVARIANTS 583744249214SRandall Stewart if (control->on_strm_q) { 583844249214SRandall Stewart panic("About to free ctl:%p so:%p and its in %d", 583944249214SRandall Stewart control, so, control->on_strm_q); 584044249214SRandall Stewart } 584198d5fd97SMichael Tuexen #endif 5842810ec536SMichael Tuexen sctp_free_remote_addr(control->whoFrom); 5843810ec536SMichael Tuexen sctp_free_a_readq(stcb, control); 5844810ec536SMichael Tuexen if (hold_rlock) { 5845810ec536SMichael Tuexen hold_rlock = 0; 5846810ec536SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 5847810ec536SMichael Tuexen } 5848810ec536SMichael Tuexen goto restart; 5849810ec536SMichael Tuexen } 5850f8829a4aSRandall Stewart if (control->length == 0) { 5851f8829a4aSRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && 5852f8829a4aSRandall Stewart (filling_sinfo)) { 5853f8829a4aSRandall Stewart /* find a more suitable one then this */ 5854f8829a4aSRandall Stewart ctl = TAILQ_NEXT(control, next); 5855f8829a4aSRandall Stewart while (ctl) { 58569a6142d8SRandall Stewart if ((ctl->stcb != control->stcb) && (ctl->length) && 58579a6142d8SRandall Stewart (ctl->some_taken || 58586114cd96SRandall Stewart (ctl->spec_flags & M_NOTIFICATION) || 58599a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 58609a6142d8SRandall Stewart (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) 58619a6142d8SRandall Stewart ) { 58629a6142d8SRandall Stewart /*- 58639a6142d8SRandall Stewart * If we have a different TCB next, and there is data 58649a6142d8SRandall Stewart * present. If we have already taken some (pdapi), OR we can 58659a6142d8SRandall Stewart * ref the tcb and no delivery as started on this stream, we 586617205eccSRandall Stewart * take it. Note we allow a notification on a different 586717205eccSRandall Stewart * assoc to be delivered.. 58689a6142d8SRandall Stewart */ 58699a6142d8SRandall Stewart control = ctl; 58709a6142d8SRandall Stewart goto found_one; 58719a6142d8SRandall Stewart } else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) && 58729a6142d8SRandall Stewart (ctl->length) && 58739a6142d8SRandall Stewart ((ctl->some_taken) || 58749a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 587517205eccSRandall Stewart ((ctl->spec_flags & M_NOTIFICATION) == 0) && 5876b5c16493SMichael Tuexen (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) { 58779a6142d8SRandall Stewart /*- 58789a6142d8SRandall Stewart * If we have the same tcb, and there is data present, and we 58799a6142d8SRandall Stewart * have the strm interleave feature present. Then if we have 58809a6142d8SRandall Stewart * taken some (pdapi) or we can refer to tht tcb AND we have 58819a6142d8SRandall Stewart * not started a delivery for this stream, we can take it. 588217205eccSRandall Stewart * Note we do NOT allow a notificaiton on the same assoc to 588317205eccSRandall Stewart * be delivered. 58849a6142d8SRandall Stewart */ 5885f8829a4aSRandall Stewart control = ctl; 5886f8829a4aSRandall Stewart goto found_one; 5887f8829a4aSRandall Stewart } 5888f8829a4aSRandall Stewart ctl = TAILQ_NEXT(ctl, next); 5889f8829a4aSRandall Stewart } 5890f8829a4aSRandall Stewart } 5891f8829a4aSRandall Stewart /* 5892f8829a4aSRandall Stewart * if we reach here, not suitable replacement is available 58934e88d37aSMichael Tuexen * <or> fragment interleave is NOT on. So stuff the sb_cc 5894f8829a4aSRandall Stewart * into the our held count, and its time to sleep again. 5895f8829a4aSRandall Stewart */ 58964e88d37aSMichael Tuexen held_length = so->so_rcv.sb_cc; 58974e88d37aSMichael Tuexen control->held_length = so->so_rcv.sb_cc; 5898f8829a4aSRandall Stewart goto restart; 5899f8829a4aSRandall Stewart } 5900f8829a4aSRandall Stewart /* Clear the held length since there is something to read */ 5901f8829a4aSRandall Stewart control->held_length = 0; 5902f8829a4aSRandall Stewart found_one: 5903f8829a4aSRandall Stewart /* 5904f8829a4aSRandall Stewart * If we reach here, control has a some data for us to read off. 5905f8829a4aSRandall Stewart * Note that stcb COULD be NULL. 5906f8829a4aSRandall Stewart */ 59079c5ca6f2SMichael Tuexen if (hold_rlock == 0) { 59089c5ca6f2SMichael Tuexen hold_rlock = 1; 59099c5ca6f2SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5910f8829a4aSRandall Stewart } 59119c5ca6f2SMichael Tuexen control->some_taken++; 5912f8829a4aSRandall Stewart stcb = control->stcb; 5913f8829a4aSRandall Stewart if (stcb) { 59140696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 59150696e120SRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { 591650cec919SRandall Stewart if (freecnt_applied == 0) 5917f8829a4aSRandall Stewart stcb = NULL; 5918f8829a4aSRandall Stewart } else if (control->do_not_ref_stcb == 0) { 5919f8829a4aSRandall Stewart /* you can't free it on me please */ 5920f8829a4aSRandall Stewart /* 5921f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the 5922f8829a4aSRandall Stewart * free code will stop. But since we used the 5923f8829a4aSRandall Stewart * socketbuf lock and the sender uses the tcb_lock 5924f8829a4aSRandall Stewart * to increment, we need to use the atomic add to 5925f8829a4aSRandall Stewart * the refcnt 5926f8829a4aSRandall Stewart */ 5927d55b0b1bSRandall Stewart if (freecnt_applied) { 5928d55b0b1bSRandall Stewart #ifdef INVARIANTS 5929207304d4SRandall Stewart panic("refcnt already incremented"); 5930d55b0b1bSRandall Stewart #else 5931cd3fd531SMichael Tuexen SCTP_PRINTF("refcnt already incremented?\n"); 5932d55b0b1bSRandall Stewart #endif 5933d55b0b1bSRandall Stewart } else { 593450cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5935f8829a4aSRandall Stewart freecnt_applied = 1; 5936d55b0b1bSRandall Stewart } 5937f8829a4aSRandall Stewart /* 5938f8829a4aSRandall Stewart * Setup to remember how much we have not yet told 5939f8829a4aSRandall Stewart * the peer our rwnd has opened up. Note we grab the 5940f8829a4aSRandall Stewart * value from the tcb from last time. Note too that 59410696e120SRandall Stewart * sack sending clears this when a sack is sent, 5942f8829a4aSRandall Stewart * which is fine. Once we hit the rwnd_req, we then 5943f8829a4aSRandall Stewart * will go to the sctp_user_rcvd() that will not 5944f8829a4aSRandall Stewart * lock until it KNOWs it MUST send a WUP-SACK. 5945f8829a4aSRandall Stewart */ 594658e6eeefSMichael Tuexen freed_so_far = (uint32_t)stcb->freed_by_sorcv_sincelast; 5947f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = 0; 5948f8829a4aSRandall Stewart } 5949f8829a4aSRandall Stewart } 59506114cd96SRandall Stewart if (stcb && 59516114cd96SRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0) && 59526114cd96SRandall Stewart control->do_not_ref_stcb == 0) { 5953d06c82f1SRandall Stewart stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; 5954d06c82f1SRandall Stewart } 59550053ed28SMichael Tuexen 5956f8829a4aSRandall Stewart /* First lets get off the sinfo and sockaddr info */ 59575f05199cSMichael Tuexen if ((sinfo != NULL) && (filling_sinfo != 0)) { 59585f05199cSMichael Tuexen sinfo->sinfo_stream = control->sinfo_stream; 595949656eefSMichael Tuexen sinfo->sinfo_ssn = (uint16_t)control->mid; 59605f05199cSMichael Tuexen sinfo->sinfo_flags = control->sinfo_flags; 59615f05199cSMichael Tuexen sinfo->sinfo_ppid = control->sinfo_ppid; 59625f05199cSMichael Tuexen sinfo->sinfo_context = control->sinfo_context; 59635f05199cSMichael Tuexen sinfo->sinfo_timetolive = control->sinfo_timetolive; 59645f05199cSMichael Tuexen sinfo->sinfo_tsn = control->sinfo_tsn; 59655f05199cSMichael Tuexen sinfo->sinfo_cumtsn = control->sinfo_cumtsn; 59665f05199cSMichael Tuexen sinfo->sinfo_assoc_id = control->sinfo_assoc_id; 5967f8829a4aSRandall Stewart nxt = TAILQ_NEXT(control, next); 5968e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 5969e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { 5970f8829a4aSRandall Stewart struct sctp_extrcvinfo *s_extra; 5971f8829a4aSRandall Stewart 5972f8829a4aSRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 59739a6142d8SRandall Stewart if ((nxt) && 59749a6142d8SRandall Stewart (nxt->length)) { 5975b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NEXT_MSG_AVAIL; 5976f8829a4aSRandall Stewart if (nxt->sinfo_flags & SCTP_UNORDERED) { 5977b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED; 5978f8829a4aSRandall Stewart } 5979f42a358aSRandall Stewart if (nxt->spec_flags & M_NOTIFICATION) { 5980b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION; 5981f42a358aSRandall Stewart } 5982b70b526dSMichael Tuexen s_extra->serinfo_next_aid = nxt->sinfo_assoc_id; 5983b70b526dSMichael Tuexen s_extra->serinfo_next_length = nxt->length; 5984b70b526dSMichael Tuexen s_extra->serinfo_next_ppid = nxt->sinfo_ppid; 5985b70b526dSMichael Tuexen s_extra->serinfo_next_stream = nxt->sinfo_stream; 5986f8829a4aSRandall Stewart if (nxt->tail_mbuf != NULL) { 5987139bc87fSRandall Stewart if (nxt->end_added) { 5988b70b526dSMichael Tuexen s_extra->serinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE; 5989f8829a4aSRandall Stewart } 5990f8829a4aSRandall Stewart } 5991f8829a4aSRandall Stewart } else { 5992f8829a4aSRandall Stewart /* 5993f8829a4aSRandall Stewart * we explicitly 0 this, since the memcpy 5994f8829a4aSRandall Stewart * got some other things beyond the older 5995f8829a4aSRandall Stewart * sinfo_ that is on the control's structure 5996f8829a4aSRandall Stewart * :-D 5997f8829a4aSRandall Stewart */ 59989a6142d8SRandall Stewart nxt = NULL; 5999b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; 6000b70b526dSMichael Tuexen s_extra->serinfo_next_aid = 0; 6001b70b526dSMichael Tuexen s_extra->serinfo_next_length = 0; 6002b70b526dSMichael Tuexen s_extra->serinfo_next_ppid = 0; 6003b70b526dSMichael Tuexen s_extra->serinfo_next_stream = 0; 6004f8829a4aSRandall Stewart } 6005f8829a4aSRandall Stewart } 6006f8829a4aSRandall Stewart /* 6007f8829a4aSRandall Stewart * update off the real current cum-ack, if we have an stcb. 6008f8829a4aSRandall Stewart */ 60090696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb) 6010f8829a4aSRandall Stewart sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 6011f8829a4aSRandall Stewart /* 6012f8829a4aSRandall Stewart * mask off the high bits, we keep the actual chunk bits in 6013f8829a4aSRandall Stewart * there. 6014f8829a4aSRandall Stewart */ 6015f8829a4aSRandall Stewart sinfo->sinfo_flags &= 0x00ff; 60165f26a41dSRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { 60175f26a41dSRandall Stewart sinfo->sinfo_flags |= SCTP_UNORDERED; 60185f26a41dSRandall Stewart } 6019f8829a4aSRandall Stewart } 602018e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 602118e198d3SRandall Stewart { 602218e198d3SRandall Stewart int index, newindex; 602318e198d3SRandall Stewart struct sctp_pcbtsn_rlog *entry; 602418e198d3SRandall Stewart 602518e198d3SRandall Stewart do { 602618e198d3SRandall Stewart index = inp->readlog_index; 602718e198d3SRandall Stewart newindex = index + 1; 602818e198d3SRandall Stewart if (newindex >= SCTP_READ_LOG_SIZE) { 602918e198d3SRandall Stewart newindex = 0; 603018e198d3SRandall Stewart } 603118e198d3SRandall Stewart } while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0); 603218e198d3SRandall Stewart entry = &inp->readlog[index]; 603318e198d3SRandall Stewart entry->vtag = control->sinfo_assoc_id; 603418e198d3SRandall Stewart entry->strm = control->sinfo_stream; 603549656eefSMichael Tuexen entry->seq = (uint16_t)control->mid; 603618e198d3SRandall Stewart entry->sz = control->length; 603718e198d3SRandall Stewart entry->flgs = control->sinfo_flags; 603818e198d3SRandall Stewart } 603918e198d3SRandall Stewart #endif 6040d59107f7SMichael Tuexen if ((fromlen > 0) && (from != NULL)) { 6041d59107f7SMichael Tuexen union sctp_sockstore store; 6042d59107f7SMichael Tuexen size_t len; 6043d59107f7SMichael Tuexen 6044b5b6e5c2SMichael Tuexen switch (control->whoFrom->ro._l_addr.sa.sa_family) { 6045b5b6e5c2SMichael Tuexen #ifdef INET6 6046b5b6e5c2SMichael Tuexen case AF_INET6: 6047d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in6); 6048d59107f7SMichael Tuexen store.sin6 = control->whoFrom->ro._l_addr.sin6; 6049d59107f7SMichael Tuexen store.sin6.sin6_port = control->port_from; 6050b5b6e5c2SMichael Tuexen break; 6051f8829a4aSRandall Stewart #endif 6052b5b6e5c2SMichael Tuexen #ifdef INET 6053b5b6e5c2SMichael Tuexen case AF_INET: 6054d59107f7SMichael Tuexen #ifdef INET6 6055d59107f7SMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { 6056d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in6); 6057d59107f7SMichael Tuexen in6_sin_2_v4mapsin6(&control->whoFrom->ro._l_addr.sin, 6058d59107f7SMichael Tuexen &store.sin6); 6059d59107f7SMichael Tuexen store.sin6.sin6_port = control->port_from; 6060d59107f7SMichael Tuexen } else { 6061d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in); 6062d59107f7SMichael Tuexen store.sin = control->whoFrom->ro._l_addr.sin; 6063d59107f7SMichael Tuexen store.sin.sin_port = control->port_from; 6064d59107f7SMichael Tuexen } 6065d59107f7SMichael Tuexen #else 6066d59107f7SMichael Tuexen len = sizeof(struct sockaddr_in); 6067d59107f7SMichael Tuexen store.sin = control->whoFrom->ro._l_addr.sin; 6068d59107f7SMichael Tuexen store.sin.sin_port = control->port_from; 6069d59107f7SMichael Tuexen #endif 6070b5b6e5c2SMichael Tuexen break; 6071b5b6e5c2SMichael Tuexen #endif 6072b5b6e5c2SMichael Tuexen default: 6073d59107f7SMichael Tuexen len = 0; 6074b5b6e5c2SMichael Tuexen break; 6075b5b6e5c2SMichael Tuexen } 6076d59107f7SMichael Tuexen memcpy(from, &store, min((size_t)fromlen, len)); 6077e0e00a4dSMichael Tuexen #ifdef INET6 6078f8829a4aSRandall Stewart { 6079b5b6e5c2SMichael Tuexen struct sockaddr_in6 lsa6, *from6; 6080f8829a4aSRandall Stewart 6081b5b6e5c2SMichael Tuexen from6 = (struct sockaddr_in6 *)from; 6082b5b6e5c2SMichael Tuexen sctp_recover_scope_mac(from6, (&lsa6)); 6083f8829a4aSRandall Stewart } 6084f8829a4aSRandall Stewart #endif 6085f8829a4aSRandall Stewart } 60869c5ca6f2SMichael Tuexen if (hold_rlock) { 60879c5ca6f2SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 60889c5ca6f2SMichael Tuexen hold_rlock = 0; 60899c5ca6f2SMichael Tuexen } 60909c5ca6f2SMichael Tuexen if (hold_sblock) { 60919c5ca6f2SMichael Tuexen SOCKBUF_UNLOCK(&so->so_rcv); 60929c5ca6f2SMichael Tuexen hold_sblock = 0; 60939c5ca6f2SMichael Tuexen } 6094f8829a4aSRandall Stewart /* now copy out what data we can */ 6095f8829a4aSRandall Stewart if (mp == NULL) { 6096f8829a4aSRandall Stewart /* copy out each mbuf in the chain up to length */ 6097f8829a4aSRandall Stewart get_more_data: 6098f8829a4aSRandall Stewart m = control->data; 6099f8829a4aSRandall Stewart while (m) { 6100f8829a4aSRandall Stewart /* Move out all we can */ 61010d3cf13dSMichael Tuexen cp_len = uio->uio_resid; 61020d3cf13dSMichael Tuexen my_len = SCTP_BUF_LEN(m); 6103f8829a4aSRandall Stewart if (cp_len > my_len) { 6104f8829a4aSRandall Stewart /* not enough in this buf */ 6105f8829a4aSRandall Stewart cp_len = my_len; 6106f8829a4aSRandall Stewart } 6107f8829a4aSRandall Stewart if (hold_rlock) { 6108f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6109f8829a4aSRandall Stewart hold_rlock = 0; 6110f8829a4aSRandall Stewart } 6111f8829a4aSRandall Stewart if (cp_len > 0) 611258e6eeefSMichael Tuexen error = uiomove(mtod(m, char *), (int)cp_len, uio); 6113f8829a4aSRandall Stewart /* re-read */ 6114f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 6115f8829a4aSRandall Stewart goto release; 6116f8829a4aSRandall Stewart } 61170053ed28SMichael Tuexen 61180696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb && 6119f8829a4aSRandall Stewart stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 6120f8829a4aSRandall Stewart no_rcv_needed = 1; 6121f8829a4aSRandall Stewart } 6122f8829a4aSRandall Stewart if (error) { 6123f8829a4aSRandall Stewart /* error we are out of here */ 6124f8829a4aSRandall Stewart goto release; 6125f8829a4aSRandall Stewart } 6126f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6127f8829a4aSRandall Stewart hold_rlock = 1; 6128139bc87fSRandall Stewart if (cp_len == SCTP_BUF_LEN(m)) { 6129139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 6130139bc87fSRandall Stewart (control->end_added)) { 6131f8829a4aSRandall Stewart out_flags |= MSG_EOR; 613252129fcdSRandall Stewart if ((control->do_not_ref_stcb == 0) && 613352129fcdSRandall Stewart (control->stcb != NULL) && 613452129fcdSRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0)) 6135ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 6136f8829a4aSRandall Stewart } 6137139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6138f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6139f8829a4aSRandall Stewart } 6140f8829a4aSRandall Stewart /* we ate up the mbuf */ 6141f8829a4aSRandall Stewart if (in_flags & MSG_PEEK) { 6142f8829a4aSRandall Stewart /* just looking */ 6143139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 6144f8829a4aSRandall Stewart copied_so_far += cp_len; 6145f8829a4aSRandall Stewart } else { 6146f8829a4aSRandall Stewart /* dispose of the mbuf */ 6147b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6148f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6149139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 615080fefe0aSRandall Stewart } 6151f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 6152b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6153f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6154f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 615580fefe0aSRandall Stewart } 6156f8829a4aSRandall Stewart copied_so_far += cp_len; 615758e6eeefSMichael Tuexen freed_so_far += (uint32_t)cp_len; 6158c4739e2fSRandall Stewart freed_so_far += MSIZE; 615918e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 6160f8829a4aSRandall Stewart control->data = sctp_m_free(m); 6161f8829a4aSRandall Stewart m = control->data; 6162b7b84c0eSMichael Tuexen /* 6163b7b84c0eSMichael Tuexen * been through it all, must hold sb 6164b7b84c0eSMichael Tuexen * lock ok to null tail 6165b7b84c0eSMichael Tuexen */ 6166f8829a4aSRandall Stewart if (control->data == NULL) { 6167a5d547adSRandall Stewart #ifdef INVARIANTS 6168f8829a4aSRandall Stewart if ((control->end_added == 0) || 6169f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 6170f8829a4aSRandall Stewart /* 6171f8829a4aSRandall Stewart * If the end is not 6172f8829a4aSRandall Stewart * added, OR the 6173f8829a4aSRandall Stewart * next is NOT null 6174f8829a4aSRandall Stewart * we MUST have the 6175f8829a4aSRandall Stewart * lock. 6176f8829a4aSRandall Stewart */ 6177f8829a4aSRandall Stewart if (mtx_owned(&inp->inp_rdata_mtx) == 0) { 6178f8829a4aSRandall Stewart panic("Hmm we don't own the lock?"); 6179f8829a4aSRandall Stewart } 6180f8829a4aSRandall Stewart } 6181f8829a4aSRandall Stewart #endif 6182f8829a4aSRandall Stewart control->tail_mbuf = NULL; 6183a5d547adSRandall Stewart #ifdef INVARIANTS 6184f8829a4aSRandall Stewart if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { 6185f8829a4aSRandall Stewart panic("end_added, nothing left and no MSG_EOR"); 6186f8829a4aSRandall Stewart } 6187f8829a4aSRandall Stewart #endif 6188f8829a4aSRandall Stewart } 6189f8829a4aSRandall Stewart } 6190f8829a4aSRandall Stewart } else { 6191f8829a4aSRandall Stewart /* Do we need to trim the mbuf? */ 6192139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6193f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6194f8829a4aSRandall Stewart } 6195f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) == 0) { 6196139bc87fSRandall Stewart SCTP_BUF_RESV_UF(m, cp_len); 619758e6eeefSMichael Tuexen SCTP_BUF_LEN(m) -= (int)cp_len; 6198b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 619958e6eeefSMichael Tuexen sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, (int)cp_len); 620080fefe0aSRandall Stewart } 62014e88d37aSMichael Tuexen atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); 62020696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 62030696e120SRandall Stewart stcb) { 62044e88d37aSMichael Tuexen atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); 6205f8829a4aSRandall Stewart } 6206f8829a4aSRandall Stewart copied_so_far += cp_len; 620758e6eeefSMichael Tuexen freed_so_far += (uint32_t)cp_len; 6208c4739e2fSRandall Stewart freed_so_far += MSIZE; 6209b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6210f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, 6211f8829a4aSRandall Stewart SCTP_LOG_SBRESULT, 0); 621280fefe0aSRandall Stewart } 621318e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 6214f8829a4aSRandall Stewart } else { 6215f8829a4aSRandall Stewart copied_so_far += cp_len; 6216f8829a4aSRandall Stewart } 6217f8829a4aSRandall Stewart } 6218d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { 6219f8829a4aSRandall Stewart break; 6220f8829a4aSRandall Stewart } 6221f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 6222f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 6223f8829a4aSRandall Stewart (freed_so_far >= rwnd_req)) { 6224f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6225f8829a4aSRandall Stewart } 6226f8829a4aSRandall Stewart } /* end while(m) */ 6227f8829a4aSRandall Stewart /* 6228f8829a4aSRandall Stewart * At this point we have looked at it all and we either have 6229f8829a4aSRandall Stewart * a MSG_EOR/or read all the user wants... <OR> 6230f8829a4aSRandall Stewart * control->length == 0. 6231f8829a4aSRandall Stewart */ 6232d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) { 6233f8829a4aSRandall Stewart /* we are done with this control */ 6234f8829a4aSRandall Stewart if (control->length == 0) { 6235f8829a4aSRandall Stewart if (control->data) { 6236a5d547adSRandall Stewart #ifdef INVARIANTS 6237f8829a4aSRandall Stewart panic("control->data not null at read eor?"); 6238f8829a4aSRandall Stewart #else 6239ad81507eSRandall Stewart SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n"); 6240f8829a4aSRandall Stewart sctp_m_freem(control->data); 6241f8829a4aSRandall Stewart control->data = NULL; 6242f8829a4aSRandall Stewart #endif 6243f8829a4aSRandall Stewart } 6244f8829a4aSRandall Stewart done_with_control: 6245f8829a4aSRandall Stewart if (hold_rlock == 0) { 6246f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6247f8829a4aSRandall Stewart hold_rlock = 1; 6248f8829a4aSRandall Stewart } 6249f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 6250f8829a4aSRandall Stewart /* Add back any hiddend data */ 6251f8829a4aSRandall Stewart if (control->held_length) { 6252f8829a4aSRandall Stewart held_length = 0; 6253f8829a4aSRandall Stewart control->held_length = 0; 6254f8829a4aSRandall Stewart wakeup_read_socket = 1; 6255f8829a4aSRandall Stewart } 625617205eccSRandall Stewart if (control->aux_data) { 625717205eccSRandall Stewart sctp_m_free(control->aux_data); 625817205eccSRandall Stewart control->aux_data = NULL; 625917205eccSRandall Stewart } 6260f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 6261f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 6262f8829a4aSRandall Stewart control->data = NULL; 626398d5fd97SMichael Tuexen #ifdef INVARIANTS 626444249214SRandall Stewart if (control->on_strm_q) { 626544249214SRandall Stewart panic("About to free ctl:%p so:%p and its in %d", 626644249214SRandall Stewart control, so, control->on_strm_q); 626744249214SRandall Stewart } 626898d5fd97SMichael Tuexen #endif 6269f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 6270f8829a4aSRandall Stewart control = NULL; 62710696e120SRandall Stewart if ((freed_so_far >= rwnd_req) && 62720696e120SRandall Stewart (no_rcv_needed == 0)) 6273f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6274f8829a4aSRandall Stewart 6275f8829a4aSRandall Stewart } else { 6276f8829a4aSRandall Stewart /* 6277f8829a4aSRandall Stewart * The user did not read all of this 6278f8829a4aSRandall Stewart * message, turn off the returned MSG_EOR 6279f8829a4aSRandall Stewart * since we are leaving more behind on the 6280f8829a4aSRandall Stewart * control to read. 6281f8829a4aSRandall Stewart */ 6282a5d547adSRandall Stewart #ifdef INVARIANTS 62830696e120SRandall Stewart if (control->end_added && 62840696e120SRandall Stewart (control->data == NULL) && 6285f8829a4aSRandall Stewart (control->tail_mbuf == NULL)) { 6286f8829a4aSRandall Stewart panic("Gak, control->length is corrupt?"); 6287f8829a4aSRandall Stewart } 6288f8829a4aSRandall Stewart #endif 6289f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 6290f8829a4aSRandall Stewart out_flags &= ~MSG_EOR; 6291f8829a4aSRandall Stewart } 6292f8829a4aSRandall Stewart } 6293f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 6294f8829a4aSRandall Stewart goto release; 6295f8829a4aSRandall Stewart } 6296f8829a4aSRandall Stewart if ((uio->uio_resid == 0) || 629704aab884SMichael Tuexen ((in_eeor_mode) && 629843ecbff2SMichael Tuexen (copied_so_far >= max(so->so_rcv.sb_lowat, 1)))) { 6299f8829a4aSRandall Stewart goto release; 6300f8829a4aSRandall Stewart } 6301f8829a4aSRandall Stewart /* 6302f8829a4aSRandall Stewart * If I hit here the receiver wants more and this message is 6303f8829a4aSRandall Stewart * NOT done (pd-api). So two questions. Can we block? if not 6304f8829a4aSRandall Stewart * we are done. Did the user NOT set MSG_WAITALL? 6305f8829a4aSRandall Stewart */ 6306f8829a4aSRandall Stewart if (block_allowed == 0) { 6307f8829a4aSRandall Stewart goto release; 6308f8829a4aSRandall Stewart } 6309f8829a4aSRandall Stewart /* 6310f8829a4aSRandall Stewart * We need to wait for more data a few things: - We don't 6311f8829a4aSRandall Stewart * sbunlock() so we don't get someone else reading. - We 6312f8829a4aSRandall Stewart * must be sure to account for the case where what is added 6313f8829a4aSRandall Stewart * is NOT to our control when we wakeup. 6314f8829a4aSRandall Stewart */ 6315f8829a4aSRandall Stewart 6316f8829a4aSRandall Stewart /* 6317f8829a4aSRandall Stewart * Do we need to tell the transport a rwnd update might be 6318f8829a4aSRandall Stewart * needed before we go to sleep? 6319f8829a4aSRandall Stewart */ 6320f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 6321f8829a4aSRandall Stewart ((freed_so_far >= rwnd_req) && 6322f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 6323f8829a4aSRandall Stewart (no_rcv_needed == 0))) { 6324f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6325f8829a4aSRandall Stewart } 6326f8829a4aSRandall Stewart wait_some_more: 632744b7479bSRandall Stewart if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { 6328f8829a4aSRandall Stewart goto release; 6329f8829a4aSRandall Stewart } 63300053ed28SMichael Tuexen 6331f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) 6332f8829a4aSRandall Stewart goto release; 6333f8829a4aSRandall Stewart 6334f8829a4aSRandall Stewart if (hold_rlock == 1) { 6335f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6336f8829a4aSRandall Stewart hold_rlock = 0; 6337f8829a4aSRandall Stewart } 6338f8829a4aSRandall Stewart if (hold_sblock == 0) { 6339f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 6340f8829a4aSRandall Stewart hold_sblock = 1; 6341f8829a4aSRandall Stewart } 6342851b7298SRandall Stewart if ((copied_so_far) && (control->length == 0) && 6343b5c16493SMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) { 6344851b7298SRandall Stewart goto release; 6345851b7298SRandall Stewart } 63464e88d37aSMichael Tuexen if (so->so_rcv.sb_cc <= control->held_length) { 6347f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 6348f8829a4aSRandall Stewart if (error) { 6349f8829a4aSRandall Stewart goto release; 6350f8829a4aSRandall Stewart } 6351f8829a4aSRandall Stewart control->held_length = 0; 6352f8829a4aSRandall Stewart } 6353f8829a4aSRandall Stewart if (hold_sblock) { 6354f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6355f8829a4aSRandall Stewart hold_sblock = 0; 6356f8829a4aSRandall Stewart } 6357f8829a4aSRandall Stewart if (control->length == 0) { 6358f8829a4aSRandall Stewart /* still nothing here */ 6359f8829a4aSRandall Stewart if (control->end_added == 1) { 6360f8829a4aSRandall Stewart /* he aborted, or is done i.e.did a shutdown */ 6361f8829a4aSRandall Stewart out_flags |= MSG_EOR; 63629a6142d8SRandall Stewart if (control->pdapi_aborted) { 63636114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 6364ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 63659a6142d8SRandall Stewart 636603b0b021SRandall Stewart out_flags |= MSG_TRUNC; 63679a6142d8SRandall Stewart } else { 63686114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 6369ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 63709a6142d8SRandall Stewart } 6371f8829a4aSRandall Stewart goto done_with_control; 6372f8829a4aSRandall Stewart } 63734e88d37aSMichael Tuexen if (so->so_rcv.sb_cc > held_length) { 63744e88d37aSMichael Tuexen control->held_length = so->so_rcv.sb_cc; 6375f8829a4aSRandall Stewart held_length = 0; 6376f8829a4aSRandall Stewart } 6377f8829a4aSRandall Stewart goto wait_some_more; 6378f8829a4aSRandall Stewart } else if (control->data == NULL) { 637950cec919SRandall Stewart /* 638050cec919SRandall Stewart * we must re-sync since data is probably being 638150cec919SRandall Stewart * added 638250cec919SRandall Stewart */ 638350cec919SRandall Stewart SCTP_INP_READ_LOCK(inp); 638450cec919SRandall Stewart if ((control->length > 0) && (control->data == NULL)) { 6385b7b84c0eSMichael Tuexen /* 6386b7b84c0eSMichael Tuexen * big trouble.. we have the lock and its 6387b7b84c0eSMichael Tuexen * corrupt? 6388b7b84c0eSMichael Tuexen */ 63899c04b296SRandall Stewart #ifdef INVARIANTS 63909d18771fSRandall Stewart panic("Impossible data==NULL length !=0"); 63919c04b296SRandall Stewart #endif 63929c04b296SRandall Stewart out_flags |= MSG_EOR; 63939c04b296SRandall Stewart out_flags |= MSG_TRUNC; 63949c04b296SRandall Stewart control->length = 0; 63959c04b296SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 63969c04b296SRandall Stewart goto done_with_control; 6397f8829a4aSRandall Stewart } 639850cec919SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 639950cec919SRandall Stewart /* We will fall around to get more data */ 640050cec919SRandall Stewart } 6401f8829a4aSRandall Stewart goto get_more_data; 6402f8829a4aSRandall Stewart } else { 640317205eccSRandall Stewart /*- 640417205eccSRandall Stewart * Give caller back the mbuf chain, 640517205eccSRandall Stewart * store in uio_resid the length 6406f8829a4aSRandall Stewart */ 640717205eccSRandall Stewart wakeup_read_socket = 0; 6408f8829a4aSRandall Stewart if ((control->end_added == 0) || 6409f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 6410f8829a4aSRandall Stewart /* Need to get rlock */ 6411f8829a4aSRandall Stewart if (hold_rlock == 0) { 6412f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 6413f8829a4aSRandall Stewart hold_rlock = 1; 6414f8829a4aSRandall Stewart } 6415f8829a4aSRandall Stewart } 6416139bc87fSRandall Stewart if (control->end_added) { 6417f8829a4aSRandall Stewart out_flags |= MSG_EOR; 641860990c0cSMichael Tuexen if ((control->do_not_ref_stcb == 0) && 641960990c0cSMichael Tuexen (control->stcb != NULL) && 642060990c0cSMichael Tuexen ((control->spec_flags & M_NOTIFICATION) == 0)) 6421ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 6422f8829a4aSRandall Stewart } 6423139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 6424f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 6425f8829a4aSRandall Stewart } 642617205eccSRandall Stewart uio->uio_resid = control->length; 6427f8829a4aSRandall Stewart *mp = control->data; 6428f8829a4aSRandall Stewart m = control->data; 6429f8829a4aSRandall Stewart while (m) { 6430b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6431f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6432139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 643380fefe0aSRandall Stewart } 6434f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 643558e6eeefSMichael Tuexen freed_so_far += (uint32_t)SCTP_BUF_LEN(m); 6436c4739e2fSRandall Stewart freed_so_far += MSIZE; 6437b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6438f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6439f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 644080fefe0aSRandall Stewart } 6441139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 6442f8829a4aSRandall Stewart } 6443f8829a4aSRandall Stewart control->data = control->tail_mbuf = NULL; 6444f8829a4aSRandall Stewart control->length = 0; 6445f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 6446f8829a4aSRandall Stewart /* Done with this control */ 6447f8829a4aSRandall Stewart goto done_with_control; 6448f8829a4aSRandall Stewart } 6449f8829a4aSRandall Stewart } 6450f8829a4aSRandall Stewart release: 6451f8829a4aSRandall Stewart if (hold_rlock == 1) { 6452f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6453f8829a4aSRandall Stewart hold_rlock = 0; 6454f8829a4aSRandall Stewart } 64557abab911SRobert Watson if (hold_sblock == 1) { 64567abab911SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 64577abab911SRobert Watson hold_sblock = 0; 6458f8829a4aSRandall Stewart } 64590053ed28SMichael Tuexen 6460f8829a4aSRandall Stewart sbunlock(&so->so_rcv); 64617abab911SRobert Watson sockbuf_lock = 0; 6462f8829a4aSRandall Stewart 6463f8829a4aSRandall Stewart release_unlocked: 6464f8829a4aSRandall Stewart if (hold_sblock) { 6465f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6466f8829a4aSRandall Stewart hold_sblock = 0; 6467f8829a4aSRandall Stewart } 6468f8829a4aSRandall Stewart if ((stcb) && (in_flags & MSG_PEEK) == 0) { 6469f8829a4aSRandall Stewart if ((freed_so_far >= rwnd_req) && 6470f8829a4aSRandall Stewart (control && (control->do_not_ref_stcb == 0)) && 6471f8829a4aSRandall Stewart (no_rcv_needed == 0)) 6472f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6473f8829a4aSRandall Stewart } 6474f8829a4aSRandall Stewart out: 64751b9f62a0SRandall Stewart if (msg_flags) { 64761b9f62a0SRandall Stewart *msg_flags = out_flags; 64771b9f62a0SRandall Stewart } 64789a6142d8SRandall Stewart if (((out_flags & MSG_EOR) == 0) && 64799a6142d8SRandall Stewart ((in_flags & MSG_PEEK) == 0) && 64809a6142d8SRandall Stewart (sinfo) && 6481e2e7c62eSMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 6482e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) { 64839a6142d8SRandall Stewart struct sctp_extrcvinfo *s_extra; 64849a6142d8SRandall Stewart 64859a6142d8SRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 6486b70b526dSMichael Tuexen s_extra->serinfo_next_flags = SCTP_NO_NEXT_MSG; 64879a6142d8SRandall Stewart } 6488f8829a4aSRandall Stewart if (hold_rlock == 1) { 6489f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6490f8829a4aSRandall Stewart } 6491f8829a4aSRandall Stewart if (hold_sblock) { 6492f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6493f8829a4aSRandall Stewart } 64947abab911SRobert Watson if (sockbuf_lock) { 64957abab911SRobert Watson sbunlock(&so->so_rcv); 64967abab911SRobert Watson } 64970053ed28SMichael Tuexen 649850cec919SRandall Stewart if (freecnt_applied) { 6499f8829a4aSRandall Stewart /* 6500f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the free 6501f8829a4aSRandall Stewart * code will stop. But since we used the socketbuf lock and 6502f8829a4aSRandall Stewart * the sender uses the tcb_lock to increment, we need to use 6503f8829a4aSRandall Stewart * the atomic add to the refcnt. 6504f8829a4aSRandall Stewart */ 650550cec919SRandall Stewart if (stcb == NULL) { 6506df6e0cc3SRandall Stewart #ifdef INVARIANTS 650750cec919SRandall Stewart panic("stcb for refcnt has gone NULL?"); 6508df6e0cc3SRandall Stewart goto stage_left; 6509df6e0cc3SRandall Stewart #else 6510df6e0cc3SRandall Stewart goto stage_left; 6511df6e0cc3SRandall Stewart #endif 651250cec919SRandall Stewart } 6513f8829a4aSRandall Stewart /* Save the value back for next time */ 6514f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = freed_so_far; 6515cf46caceSMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, -1); 6516f8829a4aSRandall Stewart } 6517b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 6518f8829a4aSRandall Stewart if (stcb) { 6519f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6520f8829a4aSRandall Stewart freed_so_far, 65219a8e3088SMichael Tuexen (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), 6522f8829a4aSRandall Stewart stcb->asoc.my_rwnd, 65234e88d37aSMichael Tuexen so->so_rcv.sb_cc); 6524f8829a4aSRandall Stewart } else { 6525f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6526f8829a4aSRandall Stewart freed_so_far, 65279a8e3088SMichael Tuexen (uint32_t)((uio) ? (slen - uio->uio_resid) : slen), 6528f8829a4aSRandall Stewart 0, 65294e88d37aSMichael Tuexen so->so_rcv.sb_cc); 6530f8829a4aSRandall Stewart } 653180fefe0aSRandall Stewart } 6532df6e0cc3SRandall Stewart stage_left: 6533f8829a4aSRandall Stewart if (wakeup_read_socket) { 6534f8829a4aSRandall Stewart sctp_sorwakeup(inp, so); 6535f8829a4aSRandall Stewart } 6536f8829a4aSRandall Stewart return (error); 6537f8829a4aSRandall Stewart } 6538f8829a4aSRandall Stewart 6539f8829a4aSRandall Stewart 6540f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING 6541f8829a4aSRandall Stewart struct mbuf * 6542f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m) 6543f8829a4aSRandall Stewart { 6544b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 6545f8829a4aSRandall Stewart sctp_log_mb(m, SCTP_MBUF_IFREE); 6546f8829a4aSRandall Stewart } 6547f8829a4aSRandall Stewart return (m_free(m)); 6548f8829a4aSRandall Stewart } 6549f8829a4aSRandall Stewart 6550f8829a4aSRandall Stewart void 6551f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb) 6552f8829a4aSRandall Stewart { 6553f8829a4aSRandall Stewart while (mb != NULL) 6554f8829a4aSRandall Stewart mb = sctp_m_free(mb); 6555f8829a4aSRandall Stewart } 6556f8829a4aSRandall Stewart 6557f8829a4aSRandall Stewart #endif 6558f8829a4aSRandall Stewart 655942551e99SRandall Stewart int 656042551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) 656142551e99SRandall Stewart { 656242551e99SRandall Stewart /* 656342551e99SRandall Stewart * Given a local address. For all associations that holds the 656442551e99SRandall Stewart * address, request a peer-set-primary. 656542551e99SRandall Stewart */ 656642551e99SRandall Stewart struct sctp_ifa *ifa; 656742551e99SRandall Stewart struct sctp_laddr *wi; 656842551e99SRandall Stewart 656942551e99SRandall Stewart ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); 657042551e99SRandall Stewart if (ifa == NULL) { 6571c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); 657242551e99SRandall Stewart return (EADDRNOTAVAIL); 657342551e99SRandall Stewart } 657442551e99SRandall Stewart /* 657542551e99SRandall Stewart * Now that we have the ifa we must awaken the iterator with this 657642551e99SRandall Stewart * message. 657742551e99SRandall Stewart */ 6578b3f1ea41SRandall Stewart wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); 657942551e99SRandall Stewart if (wi == NULL) { 6580c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 658142551e99SRandall Stewart return (ENOMEM); 658242551e99SRandall Stewart } 658342551e99SRandall Stewart /* Now incr the count and int wi structure */ 658442551e99SRandall Stewart SCTP_INCR_LADDR_COUNT(); 65855ba7f91fSMichael Tuexen memset(wi, 0, sizeof(*wi)); 6586d61a0ae0SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); 658742551e99SRandall Stewart wi->ifa = ifa; 658842551e99SRandall Stewart wi->action = SCTP_SET_PRIM_ADDR; 658942551e99SRandall Stewart atomic_add_int(&ifa->refcount, 1); 659042551e99SRandall Stewart 659142551e99SRandall Stewart /* Now add it to the work queue */ 6592f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 659342551e99SRandall Stewart /* 659442551e99SRandall Stewart * Should this really be a tailq? As it is we will process the 659542551e99SRandall Stewart * newest first :-0 659642551e99SRandall Stewart */ 6597b3f1ea41SRandall Stewart LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 659842551e99SRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 659942551e99SRandall Stewart (struct sctp_inpcb *)NULL, 660042551e99SRandall Stewart (struct sctp_tcb *)NULL, 660142551e99SRandall Stewart (struct sctp_nets *)NULL); 66022c62ba73SMichael Tuexen SCTP_WQ_ADDR_UNLOCK(); 660342551e99SRandall Stewart return (0); 660442551e99SRandall Stewart } 660542551e99SRandall Stewart 660642551e99SRandall Stewart 6607f8829a4aSRandall Stewart int 660817205eccSRandall Stewart sctp_soreceive(struct socket *so, 660917205eccSRandall Stewart struct sockaddr **psa, 661017205eccSRandall Stewart struct uio *uio, 661117205eccSRandall Stewart struct mbuf **mp0, 661217205eccSRandall Stewart struct mbuf **controlp, 661317205eccSRandall Stewart int *flagsp) 6614f8829a4aSRandall Stewart { 6615f8829a4aSRandall Stewart int error, fromlen; 6616f8829a4aSRandall Stewart uint8_t sockbuf[256]; 6617f8829a4aSRandall Stewart struct sockaddr *from; 6618f8829a4aSRandall Stewart struct sctp_extrcvinfo sinfo; 6619f8829a4aSRandall Stewart int filling_sinfo = 1; 662046bf534cSMichael Tuexen int flags; 6621f8829a4aSRandall Stewart struct sctp_inpcb *inp; 6622f8829a4aSRandall Stewart 6623f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 6624f8829a4aSRandall Stewart /* pickup the assoc we are reading from */ 6625f8829a4aSRandall Stewart if (inp == NULL) { 6626c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6627f8829a4aSRandall Stewart return (EINVAL); 6628f8829a4aSRandall Stewart } 6629e2e7c62eSMichael Tuexen if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && 6630e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && 6631e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) || 6632f8829a4aSRandall Stewart (controlp == NULL)) { 6633f8829a4aSRandall Stewart /* user does not want the sndrcv ctl */ 6634f8829a4aSRandall Stewart filling_sinfo = 0; 6635f8829a4aSRandall Stewart } 6636f8829a4aSRandall Stewart if (psa) { 6637f8829a4aSRandall Stewart from = (struct sockaddr *)sockbuf; 6638f8829a4aSRandall Stewart fromlen = sizeof(sockbuf); 6639f8829a4aSRandall Stewart from->sa_len = 0; 6640f8829a4aSRandall Stewart } else { 6641f8829a4aSRandall Stewart from = NULL; 6642f8829a4aSRandall Stewart fromlen = 0; 6643f8829a4aSRandall Stewart } 6644f8829a4aSRandall Stewart 6645e432298aSXin LI if (filling_sinfo) { 6646e432298aSXin LI memset(&sinfo, 0, sizeof(struct sctp_extrcvinfo)); 6647e432298aSXin LI } 664846bf534cSMichael Tuexen if (flagsp != NULL) { 664946bf534cSMichael Tuexen flags = *flagsp; 665046bf534cSMichael Tuexen } else { 665146bf534cSMichael Tuexen flags = 0; 665246bf534cSMichael Tuexen } 665346bf534cSMichael Tuexen error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, &flags, 6654f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo); 665546bf534cSMichael Tuexen if (flagsp != NULL) { 665646bf534cSMichael Tuexen *flagsp = flags; 665746bf534cSMichael Tuexen } 6658e432298aSXin LI if (controlp != NULL) { 6659f8829a4aSRandall Stewart /* copy back the sinfo in a CMSG format */ 666046bf534cSMichael Tuexen if (filling_sinfo && ((flags & MSG_NOTIFICATION) == 0)) { 6661f8829a4aSRandall Stewart *controlp = sctp_build_ctl_nchunk(inp, 6662f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo); 666346bf534cSMichael Tuexen } else { 6664f8829a4aSRandall Stewart *controlp = NULL; 6665f8829a4aSRandall Stewart } 666646bf534cSMichael Tuexen } 6667f8829a4aSRandall Stewart if (psa) { 6668f8829a4aSRandall Stewart /* copy back the address info */ 6669f8829a4aSRandall Stewart if (from && from->sa_len) { 6670f8829a4aSRandall Stewart *psa = sodupsockaddr(from, M_NOWAIT); 6671f8829a4aSRandall Stewart } else { 6672f8829a4aSRandall Stewart *psa = NULL; 6673f8829a4aSRandall Stewart } 6674f8829a4aSRandall Stewart } 6675f8829a4aSRandall Stewart return (error); 6676f8829a4aSRandall Stewart } 667717205eccSRandall Stewart 667817205eccSRandall Stewart 667917205eccSRandall Stewart 668017205eccSRandall Stewart 668117205eccSRandall Stewart 668217205eccSRandall Stewart int 6683d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, 6684d61a0ae0SRandall Stewart int totaddr, int *error) 668517205eccSRandall Stewart { 668617205eccSRandall Stewart int added = 0; 668717205eccSRandall Stewart int i; 668817205eccSRandall Stewart struct sctp_inpcb *inp; 668917205eccSRandall Stewart struct sockaddr *sa; 669017205eccSRandall Stewart size_t incr = 0; 669192776dfdSMichael Tuexen #ifdef INET 669292776dfdSMichael Tuexen struct sockaddr_in *sin; 669392776dfdSMichael Tuexen #endif 669492776dfdSMichael Tuexen #ifdef INET6 669592776dfdSMichael Tuexen struct sockaddr_in6 *sin6; 669692776dfdSMichael Tuexen #endif 669792776dfdSMichael Tuexen 669817205eccSRandall Stewart sa = addr; 669917205eccSRandall Stewart inp = stcb->sctp_ep; 670017205eccSRandall Stewart *error = 0; 670117205eccSRandall Stewart for (i = 0; i < totaddr; i++) { 6702ea5eba11SMichael Tuexen switch (sa->sa_family) { 6703ea5eba11SMichael Tuexen #ifdef INET 6704ea5eba11SMichael Tuexen case AF_INET: 670517205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 670692776dfdSMichael Tuexen sin = (struct sockaddr_in *)sa; 670792776dfdSMichael Tuexen if ((sin->sin_addr.s_addr == INADDR_ANY) || 670892776dfdSMichael Tuexen (sin->sin_addr.s_addr == INADDR_BROADCAST) || 670992776dfdSMichael Tuexen IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 671092776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6711ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6712ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_7); 671392776dfdSMichael Tuexen *error = EINVAL; 671492776dfdSMichael Tuexen goto out_now; 671592776dfdSMichael Tuexen } 67167154bf4aSMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, 67177154bf4aSMichael Tuexen SCTP_DONOT_SETSCOPE, 67187154bf4aSMichael Tuexen SCTP_ADDR_IS_CONFIRMED)) { 671917205eccSRandall Stewart /* assoc gone no un-lock */ 6720c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6721ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6722ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_8); 672317205eccSRandall Stewart *error = ENOBUFS; 672417205eccSRandall Stewart goto out_now; 672517205eccSRandall Stewart } 672617205eccSRandall Stewart added++; 6727ea5eba11SMichael Tuexen break; 6728ea5eba11SMichael Tuexen #endif 6729ea5eba11SMichael Tuexen #ifdef INET6 6730ea5eba11SMichael Tuexen case AF_INET6: 673117205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 673292776dfdSMichael Tuexen sin6 = (struct sockaddr_in6 *)sa; 673392776dfdSMichael Tuexen if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 673492776dfdSMichael Tuexen IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 673592776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6736ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6737ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_9); 673892776dfdSMichael Tuexen *error = EINVAL; 673992776dfdSMichael Tuexen goto out_now; 674092776dfdSMichael Tuexen } 67417154bf4aSMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, stcb->asoc.port, 67427154bf4aSMichael Tuexen SCTP_DONOT_SETSCOPE, 67437154bf4aSMichael Tuexen SCTP_ADDR_IS_CONFIRMED)) { 674417205eccSRandall Stewart /* assoc gone no un-lock */ 6745c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6746ba785902SMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, 6747ba785902SMichael Tuexen SCTP_FROM_SCTPUTIL + SCTP_LOC_10); 674817205eccSRandall Stewart *error = ENOBUFS; 674917205eccSRandall Stewart goto out_now; 675017205eccSRandall Stewart } 675117205eccSRandall Stewart added++; 6752ea5eba11SMichael Tuexen break; 6753ea5eba11SMichael Tuexen #endif 6754ea5eba11SMichael Tuexen default: 6755ea5eba11SMichael Tuexen break; 675617205eccSRandall Stewart } 675717205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 675817205eccSRandall Stewart } 675917205eccSRandall Stewart out_now: 676017205eccSRandall Stewart return (added); 676117205eccSRandall Stewart } 676217205eccSRandall Stewart 6763fc26bf71SMichael Tuexen int 6764d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, 6765fc26bf71SMichael Tuexen unsigned int totaddr, 6766fc26bf71SMichael Tuexen unsigned int *num_v4, unsigned int *num_v6, 6767fc26bf71SMichael Tuexen unsigned int limit) 676817205eccSRandall Stewart { 676917205eccSRandall Stewart struct sockaddr *sa; 6770fc26bf71SMichael Tuexen struct sctp_tcb *stcb; 67719a8e3088SMichael Tuexen unsigned int incr, at, i; 677217205eccSRandall Stewart 6773e1949767SMichael Tuexen at = 0; 677417205eccSRandall Stewart sa = addr; 6775fc26bf71SMichael Tuexen *num_v6 = *num_v4 = 0; 677617205eccSRandall Stewart /* account and validate addresses */ 6777fc26bf71SMichael Tuexen if (totaddr == 0) { 6778fc26bf71SMichael Tuexen return (EINVAL); 6779fc26bf71SMichael Tuexen } 6780fc26bf71SMichael Tuexen for (i = 0; i < totaddr; i++) { 6781fc26bf71SMichael Tuexen if (at + sizeof(struct sockaddr) > limit) { 6782fc26bf71SMichael Tuexen return (EINVAL); 6783fc26bf71SMichael Tuexen } 6784ea5eba11SMichael Tuexen switch (sa->sa_family) { 6785ea5eba11SMichael Tuexen #ifdef INET 6786ea5eba11SMichael Tuexen case AF_INET: 6787e1949767SMichael Tuexen incr = (unsigned int)sizeof(struct sockaddr_in); 6788d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6789fc26bf71SMichael Tuexen return (EINVAL); 6790d61a0ae0SRandall Stewart } 67919a8e3088SMichael Tuexen (*num_v4) += 1; 6792ea5eba11SMichael Tuexen break; 6793ea5eba11SMichael Tuexen #endif 6794ea5eba11SMichael Tuexen #ifdef INET6 6795ea5eba11SMichael Tuexen case AF_INET6: 6796ea5eba11SMichael Tuexen { 679717205eccSRandall Stewart struct sockaddr_in6 *sin6; 679817205eccSRandall Stewart 679917205eccSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 680017205eccSRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 680117205eccSRandall Stewart /* Must be non-mapped for connectx */ 6802fc26bf71SMichael Tuexen return (EINVAL); 680317205eccSRandall Stewart } 6804e1949767SMichael Tuexen incr = (unsigned int)sizeof(struct sockaddr_in6); 6805d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6806fc26bf71SMichael Tuexen return (EINVAL); 6807d61a0ae0SRandall Stewart } 68089a8e3088SMichael Tuexen (*num_v6) += 1; 6809ea5eba11SMichael Tuexen break; 6810ea5eba11SMichael Tuexen } 6811ea5eba11SMichael Tuexen #endif 6812ea5eba11SMichael Tuexen default: 6813fc26bf71SMichael Tuexen return (EINVAL); 681417205eccSRandall Stewart } 6815fc26bf71SMichael Tuexen if ((at + incr) > limit) { 6816fc26bf71SMichael Tuexen return (EINVAL); 6817ea5eba11SMichael Tuexen } 6818d61a0ae0SRandall Stewart SCTP_INP_INCR_REF(inp); 681917205eccSRandall Stewart stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 682017205eccSRandall Stewart if (stcb != NULL) { 6821fc26bf71SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 6822fc26bf71SMichael Tuexen return (EALREADY); 6823d61a0ae0SRandall Stewart } else { 6824d61a0ae0SRandall Stewart SCTP_INP_DECR_REF(inp); 682517205eccSRandall Stewart } 6826fc26bf71SMichael Tuexen at += incr; 682717205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 682817205eccSRandall Stewart } 6829fc26bf71SMichael Tuexen return (0); 683017205eccSRandall Stewart } 683135918f85SRandall Stewart 683235918f85SRandall Stewart /* 683335918f85SRandall Stewart * sctp_bindx(ADD) for one address. 683435918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 683535918f85SRandall Stewart */ 683635918f85SRandall Stewart void 683735918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, 683835918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 683935918f85SRandall Stewart uint32_t vrf_id, int *error, void *p) 684035918f85SRandall Stewart { 684135918f85SRandall Stewart struct sockaddr *addr_touse; 6842d59107f7SMichael Tuexen #if defined(INET) && defined(INET6) 684335918f85SRandall Stewart struct sockaddr_in sin; 68445e2c2d87SRandall Stewart #endif 68455e2c2d87SRandall Stewart 684635918f85SRandall Stewart /* see if we're bound all already! */ 684735918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6848c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 684935918f85SRandall Stewart *error = EINVAL; 685035918f85SRandall Stewart return; 685135918f85SRandall Stewart } 685235918f85SRandall Stewart addr_touse = sa; 6853ea5eba11SMichael Tuexen #ifdef INET6 685435918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 6855d59107f7SMichael Tuexen #ifdef INET 685635918f85SRandall Stewart struct sockaddr_in6 *sin6; 685735918f85SRandall Stewart 6858d59107f7SMichael Tuexen #endif 685935918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6860c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 686135918f85SRandall Stewart *error = EINVAL; 686235918f85SRandall Stewart return; 686335918f85SRandall Stewart } 6864db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6865db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6866c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6867db4fd95bSRandall Stewart *error = EINVAL; 6868db4fd95bSRandall Stewart return; 6869db4fd95bSRandall Stewart } 6870d59107f7SMichael Tuexen #ifdef INET 687135918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 687235918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6873db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6874db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6875db4fd95bSRandall Stewart /* can't bind v4-mapped on PF_INET sockets */ 6876c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6877db4fd95bSRandall Stewart *error = EINVAL; 6878db4fd95bSRandall Stewart return; 6879db4fd95bSRandall Stewart } 688035918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 688135918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 688235918f85SRandall Stewart } 6883d59107f7SMichael Tuexen #endif 688435918f85SRandall Stewart } 688535918f85SRandall Stewart #endif 6886ea5eba11SMichael Tuexen #ifdef INET 688735918f85SRandall Stewart if (sa->sa_family == AF_INET) { 688835918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6889c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 689035918f85SRandall Stewart *error = EINVAL; 689135918f85SRandall Stewart return; 689235918f85SRandall Stewart } 6893db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6894db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6895db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6896c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6897db4fd95bSRandall Stewart *error = EINVAL; 6898db4fd95bSRandall Stewart return; 6899db4fd95bSRandall Stewart } 690035918f85SRandall Stewart } 6901ea5eba11SMichael Tuexen #endif 690235918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 690335918f85SRandall Stewart if (p == NULL) { 690435918f85SRandall Stewart /* Can't get proc for Net/Open BSD */ 6905c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 690635918f85SRandall Stewart *error = EINVAL; 690735918f85SRandall Stewart return; 690835918f85SRandall Stewart } 69091b649582SRandall Stewart *error = sctp_inpcb_bind(so, addr_touse, NULL, p); 691035918f85SRandall Stewart return; 691135918f85SRandall Stewart } 691235918f85SRandall Stewart /* 691335918f85SRandall Stewart * No locks required here since bind and mgmt_ep_sa all do their own 691435918f85SRandall Stewart * locking. If we do something for the FIX: below we may need to 691535918f85SRandall Stewart * lock in that case. 691635918f85SRandall Stewart */ 691735918f85SRandall Stewart if (assoc_id == 0) { 691835918f85SRandall Stewart /* add the address */ 691935918f85SRandall Stewart struct sctp_inpcb *lep; 692097c76f10SRandall Stewart struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse; 692135918f85SRandall Stewart 692297c76f10SRandall Stewart /* validate the incoming port */ 692397c76f10SRandall Stewart if ((lsin->sin_port != 0) && 692497c76f10SRandall Stewart (lsin->sin_port != inp->sctp_lport)) { 6925c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 692697c76f10SRandall Stewart *error = EINVAL; 692797c76f10SRandall Stewart return; 692897c76f10SRandall Stewart } else { 692997c76f10SRandall Stewart /* user specified 0 port, set it to existing port */ 693097c76f10SRandall Stewart lsin->sin_port = inp->sctp_lport; 693197c76f10SRandall Stewart } 693297c76f10SRandall Stewart 693335918f85SRandall Stewart lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id); 693435918f85SRandall Stewart if (lep != NULL) { 693535918f85SRandall Stewart /* 693635918f85SRandall Stewart * We must decrement the refcount since we have the 693735918f85SRandall Stewart * ep already and are binding. No remove going on 693835918f85SRandall Stewart * here. 693935918f85SRandall Stewart */ 69406d9e8f2bSRandall Stewart SCTP_INP_DECR_REF(lep); 694135918f85SRandall Stewart } 694235918f85SRandall Stewart if (lep == inp) { 694335918f85SRandall Stewart /* already bound to it.. ok */ 694435918f85SRandall Stewart return; 694535918f85SRandall Stewart } else if (lep == NULL) { 694635918f85SRandall Stewart ((struct sockaddr_in *)addr_touse)->sin_port = 0; 694735918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 694835918f85SRandall Stewart SCTP_ADD_IP_ADDRESS, 694980fefe0aSRandall Stewart vrf_id, NULL); 695035918f85SRandall Stewart } else { 695135918f85SRandall Stewart *error = EADDRINUSE; 695235918f85SRandall Stewart } 695335918f85SRandall Stewart if (*error) 695435918f85SRandall Stewart return; 695535918f85SRandall Stewart } else { 695635918f85SRandall Stewart /* 695735918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 695835918f85SRandall Stewart */ 695935918f85SRandall Stewart } 696035918f85SRandall Stewart } 696135918f85SRandall Stewart 696235918f85SRandall Stewart /* 696335918f85SRandall Stewart * sctp_bindx(DELETE) for one address. 696435918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 696535918f85SRandall Stewart */ 696635918f85SRandall Stewart void 69677215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp, 696835918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 696935918f85SRandall Stewart uint32_t vrf_id, int *error) 697035918f85SRandall Stewart { 697135918f85SRandall Stewart struct sockaddr *addr_touse; 6972d59107f7SMichael Tuexen #if defined(INET) && defined(INET6) 697335918f85SRandall Stewart struct sockaddr_in sin; 69745e2c2d87SRandall Stewart #endif 69755e2c2d87SRandall Stewart 697635918f85SRandall Stewart /* see if we're bound all already! */ 697735918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6978c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 697935918f85SRandall Stewart *error = EINVAL; 698035918f85SRandall Stewart return; 698135918f85SRandall Stewart } 698235918f85SRandall Stewart addr_touse = sa; 6983e0e00a4dSMichael Tuexen #ifdef INET6 698435918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 6985d59107f7SMichael Tuexen #ifdef INET 698635918f85SRandall Stewart struct sockaddr_in6 *sin6; 6987d59107f7SMichael Tuexen #endif 6988d59107f7SMichael Tuexen 698935918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6990c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 699135918f85SRandall Stewart *error = EINVAL; 699235918f85SRandall Stewart return; 699335918f85SRandall Stewart } 6994db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6995db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6996c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6997db4fd95bSRandall Stewart *error = EINVAL; 6998db4fd95bSRandall Stewart return; 6999db4fd95bSRandall Stewart } 7000d59107f7SMichael Tuexen #ifdef INET 700135918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 700235918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 7003db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 7004db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 7005db4fd95bSRandall Stewart /* can't bind mapped-v4 on PF_INET sockets */ 7006c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 7007db4fd95bSRandall Stewart *error = EINVAL; 7008db4fd95bSRandall Stewart return; 7009db4fd95bSRandall Stewart } 701035918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 701135918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 701235918f85SRandall Stewart } 7013d59107f7SMichael Tuexen #endif 701435918f85SRandall Stewart } 701535918f85SRandall Stewart #endif 7016ea5eba11SMichael Tuexen #ifdef INET 701735918f85SRandall Stewart if (sa->sa_family == AF_INET) { 701835918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 7019c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 702035918f85SRandall Stewart *error = EINVAL; 702135918f85SRandall Stewart return; 702235918f85SRandall Stewart } 7023db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 7024db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 7025db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 7026c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 7027db4fd95bSRandall Stewart *error = EINVAL; 7028db4fd95bSRandall Stewart return; 7029db4fd95bSRandall Stewart } 703035918f85SRandall Stewart } 7031ea5eba11SMichael Tuexen #endif 703235918f85SRandall Stewart /* 703335918f85SRandall Stewart * No lock required mgmt_ep_sa does its own locking. If the FIX: 703435918f85SRandall Stewart * below is ever changed we may need to lock before calling 703535918f85SRandall Stewart * association level binding. 703635918f85SRandall Stewart */ 703735918f85SRandall Stewart if (assoc_id == 0) { 703835918f85SRandall Stewart /* delete the address */ 703935918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 704035918f85SRandall Stewart SCTP_DEL_IP_ADDRESS, 704180fefe0aSRandall Stewart vrf_id, NULL); 704235918f85SRandall Stewart } else { 704335918f85SRandall Stewart /* 704435918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 704535918f85SRandall Stewart */ 704635918f85SRandall Stewart } 704735918f85SRandall Stewart } 70481b649582SRandall Stewart 70491b649582SRandall Stewart /* 70501b649582SRandall Stewart * returns the valid local address count for an assoc, taking into account 70511b649582SRandall Stewart * all scoping rules 70521b649582SRandall Stewart */ 70531b649582SRandall Stewart int 70541b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb) 70551b649582SRandall Stewart { 7056b54ddf22SMichael Tuexen int loopback_scope; 7057b54ddf22SMichael Tuexen #if defined(INET) 7058b54ddf22SMichael Tuexen int ipv4_local_scope, ipv4_addr_legal; 7059b54ddf22SMichael Tuexen #endif 7060b54ddf22SMichael Tuexen #if defined (INET6) 7061b54ddf22SMichael Tuexen int local_scope, site_scope, ipv6_addr_legal; 7062b54ddf22SMichael Tuexen #endif 70631b649582SRandall Stewart struct sctp_vrf *vrf; 70641b649582SRandall Stewart struct sctp_ifn *sctp_ifn; 70651b649582SRandall Stewart struct sctp_ifa *sctp_ifa; 70661b649582SRandall Stewart int count = 0; 70671b649582SRandall Stewart 70681b649582SRandall Stewart /* Turn on all the appropriate scopes */ 7069a1cb341bSMichael Tuexen loopback_scope = stcb->asoc.scope.loopback_scope; 7070b54ddf22SMichael Tuexen #if defined(INET) 7071a1cb341bSMichael Tuexen ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; 7072b54ddf22SMichael Tuexen ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; 7073b54ddf22SMichael Tuexen #endif 7074b54ddf22SMichael Tuexen #if defined(INET6) 7075a1cb341bSMichael Tuexen local_scope = stcb->asoc.scope.local_scope; 7076a1cb341bSMichael Tuexen site_scope = stcb->asoc.scope.site_scope; 7077a1cb341bSMichael Tuexen ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; 7078b54ddf22SMichael Tuexen #endif 7079c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 70801b649582SRandall Stewart vrf = sctp_find_vrf(stcb->asoc.vrf_id); 70811b649582SRandall Stewart if (vrf == NULL) { 70821b649582SRandall Stewart /* no vrf, no addresses */ 7083c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 70841b649582SRandall Stewart return (0); 70851b649582SRandall Stewart } 70860053ed28SMichael Tuexen 70871b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 70881b649582SRandall Stewart /* 70891b649582SRandall Stewart * bound all case: go through all ifns on the vrf 70901b649582SRandall Stewart */ 70911b649582SRandall Stewart LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 70921b649582SRandall Stewart if ((loopback_scope == 0) && 70931b649582SRandall Stewart SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 70941b649582SRandall Stewart continue; 70951b649582SRandall Stewart } 70961b649582SRandall Stewart LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 70971b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, sctp_ifa)) 70981b649582SRandall Stewart continue; 70995e2c2d87SRandall Stewart switch (sctp_ifa->address.sa.sa_family) { 7100ea5eba11SMichael Tuexen #ifdef INET 71015e2c2d87SRandall Stewart case AF_INET: 71025e2c2d87SRandall Stewart if (ipv4_addr_legal) { 71031b649582SRandall Stewart struct sockaddr_in *sin; 71041b649582SRandall Stewart 710524aaac8dSMichael Tuexen sin = &sctp_ifa->address.sin; 71061b649582SRandall Stewart if (sin->sin_addr.s_addr == 0) { 7107b7b84c0eSMichael Tuexen /* 7108b7b84c0eSMichael Tuexen * skip unspecified 7109b7b84c0eSMichael Tuexen * addrs 7110b7b84c0eSMichael Tuexen */ 71111b649582SRandall Stewart continue; 71121b649582SRandall Stewart } 71136ba22f19SMichael Tuexen if (prison_check_ip4(stcb->sctp_ep->ip_inp.inp.inp_cred, 71146ba22f19SMichael Tuexen &sin->sin_addr) != 0) { 71156ba22f19SMichael Tuexen continue; 71166ba22f19SMichael Tuexen } 71171b649582SRandall Stewart if ((ipv4_local_scope == 0) && 71181b649582SRandall Stewart (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 71191b649582SRandall Stewart continue; 71201b649582SRandall Stewart } 71211b649582SRandall Stewart /* count this one */ 71221b649582SRandall Stewart count++; 71235e2c2d87SRandall Stewart } else { 71245e2c2d87SRandall Stewart continue; 71255e2c2d87SRandall Stewart } 71265e2c2d87SRandall Stewart break; 7127ea5eba11SMichael Tuexen #endif 71285e2c2d87SRandall Stewart #ifdef INET6 71295e2c2d87SRandall Stewart case AF_INET6: 71305e2c2d87SRandall Stewart if (ipv6_addr_legal) { 71311b649582SRandall Stewart struct sockaddr_in6 *sin6; 71321b649582SRandall Stewart 713324aaac8dSMichael Tuexen sin6 = &sctp_ifa->address.sin6; 71341b649582SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 71351b649582SRandall Stewart continue; 71361b649582SRandall Stewart } 71376ba22f19SMichael Tuexen if (prison_check_ip6(stcb->sctp_ep->ip_inp.inp.inp_cred, 71386ba22f19SMichael Tuexen &sin6->sin6_addr) != 0) { 71396ba22f19SMichael Tuexen continue; 71406ba22f19SMichael Tuexen } 71411b649582SRandall Stewart if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 71421b649582SRandall Stewart if (local_scope == 0) 71431b649582SRandall Stewart continue; 71441b649582SRandall Stewart if (sin6->sin6_scope_id == 0) { 71451b649582SRandall Stewart if (sa6_recoverscope(sin6) != 0) 71461b649582SRandall Stewart /* 71475e2c2d87SRandall Stewart * 71485e2c2d87SRandall Stewart * bad 71495b495f17SMichael Tuexen * link 71505e2c2d87SRandall Stewart * 71515b495f17SMichael Tuexen * local 71525e2c2d87SRandall Stewart * 71535b495f17SMichael Tuexen * address 71545b495f17SMichael Tuexen */ 71551b649582SRandall Stewart continue; 71561b649582SRandall Stewart } 71571b649582SRandall Stewart } 71581b649582SRandall Stewart if ((site_scope == 0) && 71591b649582SRandall Stewart (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 71601b649582SRandall Stewart continue; 71611b649582SRandall Stewart } 71621b649582SRandall Stewart /* count this one */ 71631b649582SRandall Stewart count++; 71641b649582SRandall Stewart } 71655e2c2d87SRandall Stewart break; 71665e2c2d87SRandall Stewart #endif 71675e2c2d87SRandall Stewart default: 71685e2c2d87SRandall Stewart /* TSNH */ 71695e2c2d87SRandall Stewart break; 71705e2c2d87SRandall Stewart } 71711b649582SRandall Stewart } 71721b649582SRandall Stewart } 71731b649582SRandall Stewart } else { 71741b649582SRandall Stewart /* 71751b649582SRandall Stewart * subset bound case 71761b649582SRandall Stewart */ 71771b649582SRandall Stewart struct sctp_laddr *laddr; 71781b649582SRandall Stewart 71791b649582SRandall Stewart LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, 71801b649582SRandall Stewart sctp_nxt_addr) { 71811b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 71821b649582SRandall Stewart continue; 71831b649582SRandall Stewart } 71841b649582SRandall Stewart /* count this one */ 71851b649582SRandall Stewart count++; 71861b649582SRandall Stewart } 71871b649582SRandall Stewart } 7188c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 71891b649582SRandall Stewart return (count); 71901b649582SRandall Stewart } 7191c4739e2fSRandall Stewart 7192c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF) 7193c4739e2fSRandall Stewart 7194c4739e2fSRandall Stewart void 7195b27a6b7dSRandall 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) 7196c4739e2fSRandall Stewart { 7197b27a6b7dSRandall Stewart uint32_t saveindex, newindex; 7198c4739e2fSRandall Stewart 7199c4739e2fSRandall Stewart do { 7200b3f1ea41SRandall Stewart saveindex = SCTP_BASE_SYSCTL(sctp_log).index; 7201c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 7202c4739e2fSRandall Stewart newindex = 1; 7203c4739e2fSRandall Stewart } else { 7204c4739e2fSRandall Stewart newindex = saveindex + 1; 7205c4739e2fSRandall Stewart } 7206b3f1ea41SRandall Stewart } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0); 7207c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 7208c4739e2fSRandall Stewart saveindex = 0; 7209c4739e2fSRandall Stewart } 7210b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; 7211b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys; 7212b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a; 7213b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b; 7214b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c; 7215b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d; 7216b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e; 7217b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f; 7218c4739e2fSRandall Stewart } 7219c4739e2fSRandall Stewart 7220c4739e2fSRandall Stewart #endif 7221a99b6783SRandall Stewart static void 72227cca1775SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *inp, 722381d3ec17SBryan Venteicher const struct sockaddr *sa SCTP_UNUSED, void *ctx SCTP_UNUSED) 7224a99b6783SRandall Stewart { 7225a99b6783SRandall Stewart struct ip *iph; 72263a51a264SMichael Tuexen #ifdef INET6 72273a51a264SMichael Tuexen struct ip6_hdr *ip6; 72283a51a264SMichael Tuexen #endif 7229a99b6783SRandall Stewart struct mbuf *sp, *last; 7230a99b6783SRandall Stewart struct udphdr *uhdr; 7231285052f0SMichael Tuexen uint16_t port; 7232a99b6783SRandall Stewart 7233a99b6783SRandall Stewart if ((m->m_flags & M_PKTHDR) == 0) { 7234a99b6783SRandall Stewart /* Can't handle one that is not a pkt hdr */ 7235a99b6783SRandall Stewart goto out; 7236a99b6783SRandall Stewart } 7237285052f0SMichael Tuexen /* Pull the src port */ 7238a99b6783SRandall Stewart iph = mtod(m, struct ip *); 7239a99b6783SRandall Stewart uhdr = (struct udphdr *)((caddr_t)iph + off); 7240a99b6783SRandall Stewart port = uhdr->uh_sport; 7241285052f0SMichael Tuexen /* 7242285052f0SMichael Tuexen * Split out the mbuf chain. Leave the IP header in m, place the 7243285052f0SMichael Tuexen * rest in the sp. 7244285052f0SMichael Tuexen */ 7245eb1b1807SGleb Smirnoff sp = m_split(m, off, M_NOWAIT); 7246a99b6783SRandall Stewart if (sp == NULL) { 7247a99b6783SRandall Stewart /* Gak, drop packet, we can't do a split */ 7248a99b6783SRandall Stewart goto out; 7249a99b6783SRandall Stewart } 7250285052f0SMichael Tuexen if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) { 7251285052f0SMichael Tuexen /* Gak, packet can't have an SCTP header in it - too small */ 7252a99b6783SRandall Stewart m_freem(sp); 7253a99b6783SRandall Stewart goto out; 7254a99b6783SRandall Stewart } 7255285052f0SMichael Tuexen /* Now pull up the UDP header and SCTP header together */ 7256285052f0SMichael Tuexen sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr)); 7257a99b6783SRandall Stewart if (sp == NULL) { 7258a99b6783SRandall Stewart /* Gak pullup failed */ 7259a99b6783SRandall Stewart goto out; 7260a99b6783SRandall Stewart } 7261285052f0SMichael Tuexen /* Trim out the UDP header */ 7262a99b6783SRandall Stewart m_adj(sp, sizeof(struct udphdr)); 7263a99b6783SRandall Stewart 7264a99b6783SRandall Stewart /* Now reconstruct the mbuf chain */ 7265285052f0SMichael Tuexen for (last = m; last->m_next; last = last->m_next); 7266a99b6783SRandall Stewart last->m_next = sp; 7267a99b6783SRandall Stewart m->m_pkthdr.len += sp->m_pkthdr.len; 726852f175beSMichael Tuexen /* 726952f175beSMichael Tuexen * The CSUM_DATA_VALID flags indicates that the HW checked the UDP 727052f175beSMichael Tuexen * checksum and it was valid. Since CSUM_DATA_VALID == 727152f175beSMichael Tuexen * CSUM_SCTP_VALID this would imply that the HW also verified the 727252f175beSMichael Tuexen * SCTP checksum. Therefore, clear the bit. 727352f175beSMichael Tuexen */ 727452f175beSMichael Tuexen SCTPDBG(SCTP_DEBUG_CRCOFFLOAD, 727552f175beSMichael Tuexen "sctp_recv_udp_tunneled_packet(): Packet of length %d received on %s with csum_flags 0x%b.\n", 727652f175beSMichael Tuexen m->m_pkthdr.len, 727752f175beSMichael Tuexen if_name(m->m_pkthdr.rcvif), 727852f175beSMichael Tuexen (int)m->m_pkthdr.csum_flags, CSUM_BITS); 727952f175beSMichael Tuexen m->m_pkthdr.csum_flags &= ~CSUM_DATA_VALID; 7280a99b6783SRandall Stewart iph = mtod(m, struct ip *); 7281a99b6783SRandall Stewart switch (iph->ip_v) { 7282e6194c2eSMichael Tuexen #ifdef INET 7283a99b6783SRandall Stewart case IPVERSION: 728409c1c856SMichael Tuexen iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); 7285a99b6783SRandall Stewart sctp_input_with_port(m, off, port); 7286a99b6783SRandall Stewart break; 7287e6194c2eSMichael Tuexen #endif 7288a99b6783SRandall Stewart #ifdef INET6 7289a99b6783SRandall Stewart case IPV6_VERSION >> 4: 72903a51a264SMichael Tuexen ip6 = mtod(m, struct ip6_hdr *); 72913a51a264SMichael Tuexen ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct udphdr)); 72923a51a264SMichael Tuexen sctp6_input_with_port(&m, &off, port); 7293a99b6783SRandall Stewart break; 7294a99b6783SRandall Stewart #endif 7295a99b6783SRandall Stewart default: 7296285052f0SMichael Tuexen goto out; 7297a99b6783SRandall Stewart break; 7298a99b6783SRandall Stewart } 7299a99b6783SRandall Stewart return; 7300a99b6783SRandall Stewart out: 7301a99b6783SRandall Stewart m_freem(m); 7302a99b6783SRandall Stewart } 7303c54a18d2SRandall Stewart 7304fd7af143SMichael Tuexen #ifdef INET 7305fd7af143SMichael Tuexen static void 7306fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet(int cmd, struct sockaddr *sa, void *vip, void *ctx SCTP_UNUSED) 7307fd7af143SMichael Tuexen { 7308fd7af143SMichael Tuexen struct ip *outer_ip, *inner_ip; 7309fd7af143SMichael Tuexen struct sctphdr *sh; 7310fd7af143SMichael Tuexen struct icmp *icmp; 7311fd7af143SMichael Tuexen struct udphdr *udp; 7312fd7af143SMichael Tuexen struct sctp_inpcb *inp; 7313fd7af143SMichael Tuexen struct sctp_tcb *stcb; 7314fd7af143SMichael Tuexen struct sctp_nets *net; 7315fd7af143SMichael Tuexen struct sctp_init_chunk *ch; 7316fd7af143SMichael Tuexen struct sockaddr_in src, dst; 7317fd7af143SMichael Tuexen uint8_t type, code; 7318fd7af143SMichael Tuexen 7319fd7af143SMichael Tuexen inner_ip = (struct ip *)vip; 7320fd7af143SMichael Tuexen icmp = (struct icmp *)((caddr_t)inner_ip - 7321fd7af143SMichael Tuexen (sizeof(struct icmp) - sizeof(struct ip))); 7322fd7af143SMichael Tuexen outer_ip = (struct ip *)((caddr_t)icmp - sizeof(struct ip)); 7323fd7af143SMichael Tuexen if (ntohs(outer_ip->ip_len) < 7324fd7af143SMichael Tuexen sizeof(struct ip) + 8 + (inner_ip->ip_hl << 2) + sizeof(struct udphdr) + 8) { 7325fd7af143SMichael Tuexen return; 7326fd7af143SMichael Tuexen } 7327fd7af143SMichael Tuexen udp = (struct udphdr *)((caddr_t)inner_ip + (inner_ip->ip_hl << 2)); 7328fd7af143SMichael Tuexen sh = (struct sctphdr *)(udp + 1); 7329fd7af143SMichael Tuexen memset(&src, 0, sizeof(struct sockaddr_in)); 7330fd7af143SMichael Tuexen src.sin_family = AF_INET; 7331fd7af143SMichael Tuexen src.sin_len = sizeof(struct sockaddr_in); 7332fd7af143SMichael Tuexen src.sin_port = sh->src_port; 7333fd7af143SMichael Tuexen src.sin_addr = inner_ip->ip_src; 7334fd7af143SMichael Tuexen memset(&dst, 0, sizeof(struct sockaddr_in)); 7335fd7af143SMichael Tuexen dst.sin_family = AF_INET; 7336fd7af143SMichael Tuexen dst.sin_len = sizeof(struct sockaddr_in); 7337fd7af143SMichael Tuexen dst.sin_port = sh->dest_port; 7338fd7af143SMichael Tuexen dst.sin_addr = inner_ip->ip_dst; 7339fd7af143SMichael Tuexen /* 7340fd7af143SMichael Tuexen * 'dst' holds the dest of the packet that failed to be sent. 'src' 7341fd7af143SMichael Tuexen * holds our local endpoint address. Thus we reverse the dst and the 7342fd7af143SMichael Tuexen * src in the lookup. 7343fd7af143SMichael Tuexen */ 7344fd7af143SMichael Tuexen inp = NULL; 7345fd7af143SMichael Tuexen net = NULL; 7346fd7af143SMichael Tuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, 7347fd7af143SMichael Tuexen (struct sockaddr *)&src, 7348fd7af143SMichael Tuexen &inp, &net, 1, 7349fd7af143SMichael Tuexen SCTP_DEFAULT_VRFID); 7350fd7af143SMichael Tuexen if ((stcb != NULL) && 7351fd7af143SMichael Tuexen (net != NULL) && 735255b8cd93SMichael Tuexen (inp != NULL)) { 7353fd7af143SMichael Tuexen /* Check the UDP port numbers */ 7354fd7af143SMichael Tuexen if ((udp->uh_dport != net->port) || 7355fd7af143SMichael Tuexen (udp->uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { 7356fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7357fd7af143SMichael Tuexen return; 7358fd7af143SMichael Tuexen } 7359fd7af143SMichael Tuexen /* Check the verification tag */ 7360fd7af143SMichael Tuexen if (ntohl(sh->v_tag) != 0) { 7361fd7af143SMichael Tuexen /* 7362fd7af143SMichael Tuexen * This must be the verification tag used for 7363fd7af143SMichael Tuexen * sending out packets. We don't consider packets 7364fd7af143SMichael Tuexen * reflecting the verification tag. 7365fd7af143SMichael Tuexen */ 7366fd7af143SMichael Tuexen if (ntohl(sh->v_tag) != stcb->asoc.peer_vtag) { 7367fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7368fd7af143SMichael Tuexen return; 7369fd7af143SMichael Tuexen } 7370fd7af143SMichael Tuexen } else { 7371fd7af143SMichael Tuexen if (ntohs(outer_ip->ip_len) >= 7372fd7af143SMichael Tuexen sizeof(struct ip) + 7373fd7af143SMichael Tuexen 8 + (inner_ip->ip_hl << 2) + 8 + 20) { 7374fd7af143SMichael Tuexen /* 7375fd7af143SMichael Tuexen * In this case we can check if we got an 7376fd7af143SMichael Tuexen * INIT chunk and if the initiate tag 7377fd7af143SMichael Tuexen * matches. 7378fd7af143SMichael Tuexen */ 7379fd7af143SMichael Tuexen ch = (struct sctp_init_chunk *)(sh + 1); 7380fd7af143SMichael Tuexen if ((ch->ch.chunk_type != SCTP_INITIATION) || 7381fd7af143SMichael Tuexen (ntohl(ch->init.initiate_tag) != stcb->asoc.my_vtag)) { 7382fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7383fd7af143SMichael Tuexen return; 7384fd7af143SMichael Tuexen } 7385fd7af143SMichael Tuexen } else { 7386fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7387fd7af143SMichael Tuexen return; 7388fd7af143SMichael Tuexen } 7389fd7af143SMichael Tuexen } 7390fd7af143SMichael Tuexen type = icmp->icmp_type; 7391fd7af143SMichael Tuexen code = icmp->icmp_code; 73923c3f9e2aSMichael Tuexen if ((type == ICMP_UNREACH) && 73933c3f9e2aSMichael Tuexen (code == ICMP_UNREACH_PORT)) { 7394fd7af143SMichael Tuexen code = ICMP_UNREACH_PROTOCOL; 7395fd7af143SMichael Tuexen } 7396fd7af143SMichael Tuexen sctp_notify(inp, stcb, net, type, code, 7397fd7af143SMichael Tuexen ntohs(inner_ip->ip_len), 73986ebfa5eeSMichael Tuexen (uint32_t)ntohs(icmp->icmp_nextmtu)); 7399fd7af143SMichael Tuexen } else { 7400fd7af143SMichael Tuexen if ((stcb == NULL) && (inp != NULL)) { 7401fd7af143SMichael Tuexen /* reduce ref-count */ 7402fd7af143SMichael Tuexen SCTP_INP_WLOCK(inp); 7403fd7af143SMichael Tuexen SCTP_INP_DECR_REF(inp); 7404fd7af143SMichael Tuexen SCTP_INP_WUNLOCK(inp); 7405fd7af143SMichael Tuexen } 7406fd7af143SMichael Tuexen if (stcb) { 7407fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7408fd7af143SMichael Tuexen } 7409fd7af143SMichael Tuexen } 7410fd7af143SMichael Tuexen return; 7411fd7af143SMichael Tuexen } 7412fd7af143SMichael Tuexen #endif 7413fd7af143SMichael Tuexen 7414fd7af143SMichael Tuexen #ifdef INET6 7415fd7af143SMichael Tuexen static void 7416fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet(int cmd, struct sockaddr *sa, void *d, void *ctx SCTP_UNUSED) 7417fd7af143SMichael Tuexen { 7418fd7af143SMichael Tuexen struct ip6ctlparam *ip6cp; 7419fd7af143SMichael Tuexen struct sctp_inpcb *inp; 7420fd7af143SMichael Tuexen struct sctp_tcb *stcb; 7421fd7af143SMichael Tuexen struct sctp_nets *net; 7422fd7af143SMichael Tuexen struct sctphdr sh; 7423fd7af143SMichael Tuexen struct udphdr udp; 7424fd7af143SMichael Tuexen struct sockaddr_in6 src, dst; 7425fd7af143SMichael Tuexen uint8_t type, code; 7426fd7af143SMichael Tuexen 7427fd7af143SMichael Tuexen ip6cp = (struct ip6ctlparam *)d; 7428fd7af143SMichael Tuexen /* 7429fd7af143SMichael Tuexen * XXX: We assume that when IPV6 is non NULL, M and OFF are valid. 7430fd7af143SMichael Tuexen */ 7431fd7af143SMichael Tuexen if (ip6cp->ip6c_m == NULL) { 7432fd7af143SMichael Tuexen return; 7433fd7af143SMichael Tuexen } 7434fd7af143SMichael Tuexen /* 7435fd7af143SMichael Tuexen * Check if we can safely examine the ports and the verification tag 7436fd7af143SMichael Tuexen * of the SCTP common header. 7437fd7af143SMichael Tuexen */ 7438fd7af143SMichael Tuexen if (ip6cp->ip6c_m->m_pkthdr.len < 7439fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr) + offsetof(struct sctphdr, checksum)) { 7440fd7af143SMichael Tuexen return; 7441fd7af143SMichael Tuexen } 7442fd7af143SMichael Tuexen /* Copy out the UDP header. */ 7443fd7af143SMichael Tuexen memset(&udp, 0, sizeof(struct udphdr)); 7444fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7445fd7af143SMichael Tuexen ip6cp->ip6c_off, 7446fd7af143SMichael Tuexen sizeof(struct udphdr), 7447fd7af143SMichael Tuexen (caddr_t)&udp); 7448fd7af143SMichael Tuexen /* Copy out the port numbers and the verification tag. */ 7449fd7af143SMichael Tuexen memset(&sh, 0, sizeof(struct sctphdr)); 7450fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7451fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr), 7452fd7af143SMichael Tuexen sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), 7453fd7af143SMichael Tuexen (caddr_t)&sh); 7454fd7af143SMichael Tuexen memset(&src, 0, sizeof(struct sockaddr_in6)); 7455fd7af143SMichael Tuexen src.sin6_family = AF_INET6; 7456fd7af143SMichael Tuexen src.sin6_len = sizeof(struct sockaddr_in6); 7457fd7af143SMichael Tuexen src.sin6_port = sh.src_port; 7458fd7af143SMichael Tuexen src.sin6_addr = ip6cp->ip6c_ip6->ip6_src; 7459fd7af143SMichael Tuexen if (in6_setscope(&src.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { 7460fd7af143SMichael Tuexen return; 7461fd7af143SMichael Tuexen } 7462fd7af143SMichael Tuexen memset(&dst, 0, sizeof(struct sockaddr_in6)); 7463fd7af143SMichael Tuexen dst.sin6_family = AF_INET6; 7464fd7af143SMichael Tuexen dst.sin6_len = sizeof(struct sockaddr_in6); 7465fd7af143SMichael Tuexen dst.sin6_port = sh.dest_port; 7466fd7af143SMichael Tuexen dst.sin6_addr = ip6cp->ip6c_ip6->ip6_dst; 7467fd7af143SMichael Tuexen if (in6_setscope(&dst.sin6_addr, ip6cp->ip6c_m->m_pkthdr.rcvif, NULL) != 0) { 7468fd7af143SMichael Tuexen return; 7469fd7af143SMichael Tuexen } 7470fd7af143SMichael Tuexen inp = NULL; 7471fd7af143SMichael Tuexen net = NULL; 7472fd7af143SMichael Tuexen stcb = sctp_findassociation_addr_sa((struct sockaddr *)&dst, 7473fd7af143SMichael Tuexen (struct sockaddr *)&src, 7474fd7af143SMichael Tuexen &inp, &net, 1, SCTP_DEFAULT_VRFID); 7475fd7af143SMichael Tuexen if ((stcb != NULL) && 7476fd7af143SMichael Tuexen (net != NULL) && 747755b8cd93SMichael Tuexen (inp != NULL)) { 7478fd7af143SMichael Tuexen /* Check the UDP port numbers */ 7479fd7af143SMichael Tuexen if ((udp.uh_dport != net->port) || 7480fd7af143SMichael Tuexen (udp.uh_sport != htons(SCTP_BASE_SYSCTL(sctp_udp_tunneling_port)))) { 7481fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7482fd7af143SMichael Tuexen return; 7483fd7af143SMichael Tuexen } 7484fd7af143SMichael Tuexen /* Check the verification tag */ 7485fd7af143SMichael Tuexen if (ntohl(sh.v_tag) != 0) { 7486fd7af143SMichael Tuexen /* 7487fd7af143SMichael Tuexen * This must be the verification tag used for 7488fd7af143SMichael Tuexen * sending out packets. We don't consider packets 7489fd7af143SMichael Tuexen * reflecting the verification tag. 7490fd7af143SMichael Tuexen */ 7491fd7af143SMichael Tuexen if (ntohl(sh.v_tag) != stcb->asoc.peer_vtag) { 7492fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7493fd7af143SMichael Tuexen return; 7494fd7af143SMichael Tuexen } 7495fd7af143SMichael Tuexen } else { 7496fd7af143SMichael Tuexen if (ip6cp->ip6c_m->m_pkthdr.len >= 7497fd7af143SMichael Tuexen ip6cp->ip6c_off + sizeof(struct udphdr) + 7498fd7af143SMichael Tuexen sizeof(struct sctphdr) + 7499fd7af143SMichael Tuexen sizeof(struct sctp_chunkhdr) + 7500fd7af143SMichael Tuexen offsetof(struct sctp_init, a_rwnd)) { 7501fd7af143SMichael Tuexen /* 7502fd7af143SMichael Tuexen * In this case we can check if we got an 7503fd7af143SMichael Tuexen * INIT chunk and if the initiate tag 7504fd7af143SMichael Tuexen * matches. 7505fd7af143SMichael Tuexen */ 7506fd7af143SMichael Tuexen uint32_t initiate_tag; 7507fd7af143SMichael Tuexen uint8_t chunk_type; 7508fd7af143SMichael Tuexen 7509fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7510fd7af143SMichael Tuexen ip6cp->ip6c_off + 7511fd7af143SMichael Tuexen sizeof(struct udphdr) + 7512fd7af143SMichael Tuexen sizeof(struct sctphdr), 7513fd7af143SMichael Tuexen sizeof(uint8_t), 7514fd7af143SMichael Tuexen (caddr_t)&chunk_type); 7515fd7af143SMichael Tuexen m_copydata(ip6cp->ip6c_m, 7516fd7af143SMichael Tuexen ip6cp->ip6c_off + 7517fd7af143SMichael Tuexen sizeof(struct udphdr) + 7518fd7af143SMichael Tuexen sizeof(struct sctphdr) + 7519fd7af143SMichael Tuexen sizeof(struct sctp_chunkhdr), 7520fd7af143SMichael Tuexen sizeof(uint32_t), 7521fd7af143SMichael Tuexen (caddr_t)&initiate_tag); 7522fd7af143SMichael Tuexen if ((chunk_type != SCTP_INITIATION) || 7523fd7af143SMichael Tuexen (ntohl(initiate_tag) != stcb->asoc.my_vtag)) { 7524fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7525fd7af143SMichael Tuexen return; 7526fd7af143SMichael Tuexen } 7527fd7af143SMichael Tuexen } else { 7528fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7529fd7af143SMichael Tuexen return; 7530fd7af143SMichael Tuexen } 7531fd7af143SMichael Tuexen } 7532fd7af143SMichael Tuexen type = ip6cp->ip6c_icmp6->icmp6_type; 7533fd7af143SMichael Tuexen code = ip6cp->ip6c_icmp6->icmp6_code; 7534fd7af143SMichael Tuexen if ((type == ICMP6_DST_UNREACH) && 7535fd7af143SMichael Tuexen (code == ICMP6_DST_UNREACH_NOPORT)) { 7536fd7af143SMichael Tuexen type = ICMP6_PARAM_PROB; 7537fd7af143SMichael Tuexen code = ICMP6_PARAMPROB_NEXTHEADER; 7538fd7af143SMichael Tuexen } 7539fd7af143SMichael Tuexen sctp6_notify(inp, stcb, net, type, code, 75406ebfa5eeSMichael Tuexen ntohl(ip6cp->ip6c_icmp6->icmp6_mtu)); 7541fd7af143SMichael Tuexen } else { 7542fd7af143SMichael Tuexen if ((stcb == NULL) && (inp != NULL)) { 7543fd7af143SMichael Tuexen /* reduce inp's ref-count */ 7544fd7af143SMichael Tuexen SCTP_INP_WLOCK(inp); 7545fd7af143SMichael Tuexen SCTP_INP_DECR_REF(inp); 7546fd7af143SMichael Tuexen SCTP_INP_WUNLOCK(inp); 7547fd7af143SMichael Tuexen } 7548fd7af143SMichael Tuexen if (stcb) { 7549fd7af143SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 7550fd7af143SMichael Tuexen } 7551fd7af143SMichael Tuexen } 7552fd7af143SMichael Tuexen } 7553fd7af143SMichael Tuexen #endif 7554fd7af143SMichael Tuexen 7555c54a18d2SRandall Stewart void 7556c54a18d2SRandall Stewart sctp_over_udp_stop(void) 7557c54a18d2SRandall Stewart { 7558a99b6783SRandall Stewart /* 7559a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 7560a99b6783SRandall Stewart * for writting! 7561a99b6783SRandall Stewart */ 75623a51a264SMichael Tuexen #ifdef INET 75633a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { 75643a51a264SMichael Tuexen soclose(SCTP_BASE_INFO(udp4_tun_socket)); 75653a51a264SMichael Tuexen SCTP_BASE_INFO(udp4_tun_socket) = NULL; 7566c54a18d2SRandall Stewart } 75673a51a264SMichael Tuexen #endif 75683a51a264SMichael Tuexen #ifdef INET6 75693a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { 75703a51a264SMichael Tuexen soclose(SCTP_BASE_INFO(udp6_tun_socket)); 75713a51a264SMichael Tuexen SCTP_BASE_INFO(udp6_tun_socket) = NULL; 75723a51a264SMichael Tuexen } 75733a51a264SMichael Tuexen #endif 7574a99b6783SRandall Stewart } 7575ea5eba11SMichael Tuexen 7576c54a18d2SRandall Stewart int 7577c54a18d2SRandall Stewart sctp_over_udp_start(void) 7578c54a18d2SRandall Stewart { 7579a99b6783SRandall Stewart uint16_t port; 7580a99b6783SRandall Stewart int ret; 75813a51a264SMichael Tuexen #ifdef INET 75823a51a264SMichael Tuexen struct sockaddr_in sin; 75833a51a264SMichael Tuexen #endif 75843a51a264SMichael Tuexen #ifdef INET6 75853a51a264SMichael Tuexen struct sockaddr_in6 sin6; 75863a51a264SMichael Tuexen #endif 7587a99b6783SRandall Stewart /* 7588a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 7589a99b6783SRandall Stewart * for writting! 7590a99b6783SRandall Stewart */ 7591a99b6783SRandall Stewart port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); 75923a51a264SMichael Tuexen if (ntohs(port) == 0) { 7593a99b6783SRandall Stewart /* Must have a port set */ 7594a99b6783SRandall Stewart return (EINVAL); 7595a99b6783SRandall Stewart } 75963a51a264SMichael Tuexen #ifdef INET 75973a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp4_tun_socket) != NULL) { 7598a99b6783SRandall Stewart /* Already running -- must stop first */ 7599a99b6783SRandall Stewart return (EALREADY); 7600a99b6783SRandall Stewart } 76013a51a264SMichael Tuexen #endif 76023a51a264SMichael Tuexen #ifdef INET6 76033a51a264SMichael Tuexen if (SCTP_BASE_INFO(udp6_tun_socket) != NULL) { 76043a51a264SMichael Tuexen /* Already running -- must stop first */ 76053a51a264SMichael Tuexen return (EALREADY); 7606a99b6783SRandall Stewart } 76073a51a264SMichael Tuexen #endif 76083a51a264SMichael Tuexen #ifdef INET 76093a51a264SMichael Tuexen if ((ret = socreate(PF_INET, &SCTP_BASE_INFO(udp4_tun_socket), 76103a51a264SMichael Tuexen SOCK_DGRAM, IPPROTO_UDP, 76113a51a264SMichael Tuexen curthread->td_ucred, curthread))) { 7612a99b6783SRandall Stewart sctp_over_udp_stop(); 7613a99b6783SRandall Stewart return (ret); 7614a99b6783SRandall Stewart } 76153a51a264SMichael Tuexen /* Call the special UDP hook. */ 76163a51a264SMichael Tuexen if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp4_tun_socket), 7617fd7af143SMichael Tuexen sctp_recv_udp_tunneled_packet, 7618fd7af143SMichael Tuexen sctp_recv_icmp_tunneled_packet, 7619fd7af143SMichael Tuexen NULL))) { 76203a51a264SMichael Tuexen sctp_over_udp_stop(); 76213a51a264SMichael Tuexen return (ret); 76223a51a264SMichael Tuexen } 76233a51a264SMichael Tuexen /* Ok, we have a socket, bind it to the port. */ 76243a51a264SMichael Tuexen memset(&sin, 0, sizeof(struct sockaddr_in)); 76253a51a264SMichael Tuexen sin.sin_len = sizeof(struct sockaddr_in); 76263a51a264SMichael Tuexen sin.sin_family = AF_INET; 76273a51a264SMichael Tuexen sin.sin_port = htons(port); 76283a51a264SMichael Tuexen if ((ret = sobind(SCTP_BASE_INFO(udp4_tun_socket), 76293a51a264SMichael Tuexen (struct sockaddr *)&sin, curthread))) { 76303a51a264SMichael Tuexen sctp_over_udp_stop(); 76313a51a264SMichael Tuexen return (ret); 76323a51a264SMichael Tuexen } 76333a51a264SMichael Tuexen #endif 76343a51a264SMichael Tuexen #ifdef INET6 76353a51a264SMichael Tuexen if ((ret = socreate(PF_INET6, &SCTP_BASE_INFO(udp6_tun_socket), 76363a51a264SMichael Tuexen SOCK_DGRAM, IPPROTO_UDP, 76373a51a264SMichael Tuexen curthread->td_ucred, curthread))) { 76383a51a264SMichael Tuexen sctp_over_udp_stop(); 76393a51a264SMichael Tuexen return (ret); 76403a51a264SMichael Tuexen } 76413a51a264SMichael Tuexen /* Call the special UDP hook. */ 76423a51a264SMichael Tuexen if ((ret = udp_set_kernel_tunneling(SCTP_BASE_INFO(udp6_tun_socket), 7643fd7af143SMichael Tuexen sctp_recv_udp_tunneled_packet, 7644fd7af143SMichael Tuexen sctp_recv_icmp6_tunneled_packet, 7645fd7af143SMichael Tuexen NULL))) { 76463a51a264SMichael Tuexen sctp_over_udp_stop(); 76473a51a264SMichael Tuexen return (ret); 76483a51a264SMichael Tuexen } 76493a51a264SMichael Tuexen /* Ok, we have a socket, bind it to the port. */ 76503a51a264SMichael Tuexen memset(&sin6, 0, sizeof(struct sockaddr_in6)); 76513a51a264SMichael Tuexen sin6.sin6_len = sizeof(struct sockaddr_in6); 76523a51a264SMichael Tuexen sin6.sin6_family = AF_INET6; 76533a51a264SMichael Tuexen sin6.sin6_port = htons(port); 76543a51a264SMichael Tuexen if ((ret = sobind(SCTP_BASE_INFO(udp6_tun_socket), 76553a51a264SMichael Tuexen (struct sockaddr *)&sin6, curthread))) { 76563a51a264SMichael Tuexen sctp_over_udp_stop(); 76573a51a264SMichael Tuexen return (ret); 76583a51a264SMichael Tuexen } 76593a51a264SMichael Tuexen #endif 7660a99b6783SRandall Stewart return (0); 7661c54a18d2SRandall Stewart } 766210e0318aSMichael Tuexen 766310e0318aSMichael Tuexen /* 766410e0318aSMichael Tuexen * sctp_min_mtu ()returns the minimum of all non-zero arguments. 766510e0318aSMichael Tuexen * If all arguments are zero, zero is returned. 766610e0318aSMichael Tuexen */ 766710e0318aSMichael Tuexen uint32_t 7668b0471b4bSMichael Tuexen sctp_min_mtu(uint32_t mtu1, uint32_t mtu2, uint32_t mtu3) 7669b0471b4bSMichael Tuexen { 767010e0318aSMichael Tuexen if (mtu1 > 0) { 767110e0318aSMichael Tuexen if (mtu2 > 0) { 767210e0318aSMichael Tuexen if (mtu3 > 0) { 767310e0318aSMichael Tuexen return (min(mtu1, min(mtu2, mtu3))); 767410e0318aSMichael Tuexen } else { 767510e0318aSMichael Tuexen return (min(mtu1, mtu2)); 767610e0318aSMichael Tuexen } 767710e0318aSMichael Tuexen } else { 767810e0318aSMichael Tuexen if (mtu3 > 0) { 767910e0318aSMichael Tuexen return (min(mtu1, mtu3)); 768010e0318aSMichael Tuexen } else { 768110e0318aSMichael Tuexen return (mtu1); 768210e0318aSMichael Tuexen } 768310e0318aSMichael Tuexen } 768410e0318aSMichael Tuexen } else { 768510e0318aSMichael Tuexen if (mtu2 > 0) { 768610e0318aSMichael Tuexen if (mtu3 > 0) { 768710e0318aSMichael Tuexen return (min(mtu2, mtu3)); 768810e0318aSMichael Tuexen } else { 768910e0318aSMichael Tuexen return (mtu2); 769010e0318aSMichael Tuexen } 769110e0318aSMichael Tuexen } else { 769210e0318aSMichael Tuexen return (mtu3); 769310e0318aSMichael Tuexen } 769410e0318aSMichael Tuexen } 769510e0318aSMichael Tuexen } 769610e0318aSMichael Tuexen 769710e0318aSMichael Tuexen void 769810e0318aSMichael Tuexen sctp_hc_set_mtu(union sctp_sockstore *addr, uint16_t fibnum, uint32_t mtu) 769910e0318aSMichael Tuexen { 770010e0318aSMichael Tuexen struct in_conninfo inc; 770110e0318aSMichael Tuexen 770210e0318aSMichael Tuexen memset(&inc, 0, sizeof(struct in_conninfo)); 770310e0318aSMichael Tuexen inc.inc_fibnum = fibnum; 770410e0318aSMichael Tuexen switch (addr->sa.sa_family) { 770510e0318aSMichael Tuexen #ifdef INET 770610e0318aSMichael Tuexen case AF_INET: 770710e0318aSMichael Tuexen inc.inc_faddr = addr->sin.sin_addr; 770810e0318aSMichael Tuexen break; 770910e0318aSMichael Tuexen #endif 771010e0318aSMichael Tuexen #ifdef INET6 771110e0318aSMichael Tuexen case AF_INET6: 771210e0318aSMichael Tuexen inc.inc_flags |= INC_ISIPV6; 771310e0318aSMichael Tuexen inc.inc6_faddr = addr->sin6.sin6_addr; 771410e0318aSMichael Tuexen break; 771510e0318aSMichael Tuexen #endif 771610e0318aSMichael Tuexen default: 771710e0318aSMichael Tuexen return; 771810e0318aSMichael Tuexen } 771910e0318aSMichael Tuexen tcp_hc_updatemtu(&inc, (u_long)mtu); 772010e0318aSMichael Tuexen } 772110e0318aSMichael Tuexen 772210e0318aSMichael Tuexen uint32_t 7723b0471b4bSMichael Tuexen sctp_hc_get_mtu(union sctp_sockstore *addr, uint16_t fibnum) 7724b0471b4bSMichael Tuexen { 772510e0318aSMichael Tuexen struct in_conninfo inc; 772610e0318aSMichael Tuexen 772710e0318aSMichael Tuexen memset(&inc, 0, sizeof(struct in_conninfo)); 772810e0318aSMichael Tuexen inc.inc_fibnum = fibnum; 772910e0318aSMichael Tuexen switch (addr->sa.sa_family) { 773010e0318aSMichael Tuexen #ifdef INET 773110e0318aSMichael Tuexen case AF_INET: 773210e0318aSMichael Tuexen inc.inc_faddr = addr->sin.sin_addr; 773310e0318aSMichael Tuexen break; 773410e0318aSMichael Tuexen #endif 773510e0318aSMichael Tuexen #ifdef INET6 773610e0318aSMichael Tuexen case AF_INET6: 773710e0318aSMichael Tuexen inc.inc_flags |= INC_ISIPV6; 773810e0318aSMichael Tuexen inc.inc6_faddr = addr->sin6.sin6_addr; 773910e0318aSMichael Tuexen break; 774010e0318aSMichael Tuexen #endif 774110e0318aSMichael Tuexen default: 774210e0318aSMichael Tuexen return (0); 774310e0318aSMichael Tuexen } 774410e0318aSMichael Tuexen return ((uint32_t)tcp_hc_getmtu(&inc)); 774510e0318aSMichael Tuexen } 77466ef849e6SMichael Tuexen 77471a0b0216SMichael Tuexen void 77481a0b0216SMichael Tuexen sctp_set_state(struct sctp_tcb *stcb, int new_state) 77491a0b0216SMichael Tuexen { 77501e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77511e88cc8bSMichael Tuexen int old_state = stcb->asoc.state; 77521e88cc8bSMichael Tuexen #endif 77531e88cc8bSMichael Tuexen 77541a0b0216SMichael Tuexen KASSERT((new_state & ~SCTP_STATE_MASK) == 0, 77551a0b0216SMichael Tuexen ("sctp_set_state: Can't set substate (new_state = %x)", 77561a0b0216SMichael Tuexen new_state)); 77571a0b0216SMichael Tuexen stcb->asoc.state = (stcb->asoc.state & ~SCTP_STATE_MASK) | new_state; 77581a0b0216SMichael Tuexen if ((new_state == SCTP_STATE_SHUTDOWN_RECEIVED) || 77591a0b0216SMichael Tuexen (new_state == SCTP_STATE_SHUTDOWN_SENT) || 77601a0b0216SMichael Tuexen (new_state == SCTP_STATE_SHUTDOWN_ACK_SENT)) { 77611a0b0216SMichael Tuexen SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_SHUTDOWN_PENDING); 77621a0b0216SMichael Tuexen } 77631e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77641e88cc8bSMichael Tuexen if (((old_state & SCTP_STATE_MASK) != new_state) && 77651e88cc8bSMichael Tuexen !(((old_state & SCTP_STATE_MASK) == SCTP_STATE_EMPTY) && 77661e88cc8bSMichael Tuexen (new_state == SCTP_STATE_INUSE))) { 77671e88cc8bSMichael Tuexen SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state); 77681e88cc8bSMichael Tuexen } 77691e88cc8bSMichael Tuexen #endif 77701a0b0216SMichael Tuexen } 77711a0b0216SMichael Tuexen 77721a0b0216SMichael Tuexen void 77731a0b0216SMichael Tuexen sctp_add_substate(struct sctp_tcb *stcb, int substate) 77741a0b0216SMichael Tuexen { 77751e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77761e88cc8bSMichael Tuexen int old_state = stcb->asoc.state; 77771e88cc8bSMichael Tuexen #endif 77781e88cc8bSMichael Tuexen 77791a0b0216SMichael Tuexen KASSERT((substate & SCTP_STATE_MASK) == 0, 77801a0b0216SMichael Tuexen ("sctp_add_substate: Can't set state (substate = %x)", 77811a0b0216SMichael Tuexen substate)); 77821a0b0216SMichael Tuexen stcb->asoc.state |= substate; 77831e88cc8bSMichael Tuexen #if defined(KDTRACE_HOOKS) 77841e88cc8bSMichael Tuexen if (((substate & SCTP_STATE_ABOUT_TO_BE_FREED) && 77851e88cc8bSMichael Tuexen ((old_state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0)) || 77861e88cc8bSMichael Tuexen ((substate & SCTP_STATE_SHUTDOWN_PENDING) && 77871e88cc8bSMichael Tuexen ((old_state & SCTP_STATE_SHUTDOWN_PENDING) == 0))) { 77881e88cc8bSMichael Tuexen SCTP_PROBE6(state__change, NULL, stcb, NULL, stcb, NULL, old_state); 77891e88cc8bSMichael Tuexen } 77901e88cc8bSMichael Tuexen #endif 77911a0b0216SMichael Tuexen } 7792