1f8829a4aSRandall Stewart /*- 2830d754dSRandall Stewart * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 3807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. 4807aad63SMichael Tuexen * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. 5f8829a4aSRandall Stewart * 6f8829a4aSRandall Stewart * Redistribution and use in source and binary forms, with or without 7f8829a4aSRandall Stewart * modification, are permitted provided that the following conditions are met: 8f8829a4aSRandall Stewart * 9f8829a4aSRandall Stewart * a) Redistributions of source code must retain the above copyright notice, 10f8829a4aSRandall Stewart * this list of conditions and the following disclaimer. 11f8829a4aSRandall Stewart * 12f8829a4aSRandall Stewart * b) Redistributions in binary form must reproduce the above copyright 13f8829a4aSRandall Stewart * notice, this list of conditions and the following disclaimer in 14f8829a4aSRandall Stewart * the documentation and/or other materials provided with the distribution. 15f8829a4aSRandall Stewart * 16f8829a4aSRandall Stewart * c) Neither the name of Cisco Systems, Inc. nor the names of its 17f8829a4aSRandall Stewart * contributors may be used to endorse or promote products derived 18f8829a4aSRandall Stewart * from this software without specific prior written permission. 19f8829a4aSRandall Stewart * 20f8829a4aSRandall Stewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21f8829a4aSRandall Stewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22f8829a4aSRandall Stewart * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23f8829a4aSRandall Stewart * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24f8829a4aSRandall Stewart * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25f8829a4aSRandall Stewart * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26f8829a4aSRandall Stewart * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27f8829a4aSRandall Stewart * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28f8829a4aSRandall Stewart * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29f8829a4aSRandall Stewart * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30f8829a4aSRandall Stewart * THE POSSIBILITY OF SUCH DAMAGE. 31f8829a4aSRandall Stewart */ 32f8829a4aSRandall Stewart 33f8829a4aSRandall Stewart #include <sys/cdefs.h> 34f8829a4aSRandall Stewart __FBSDID("$FreeBSD$"); 35f8829a4aSRandall Stewart 36f8829a4aSRandall Stewart #include <netinet/sctp_os.h> 37f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h> 38f8829a4aSRandall Stewart #include <netinet/sctputil.h> 39f8829a4aSRandall Stewart #include <netinet/sctp_var.h> 4042551e99SRandall Stewart #include <netinet/sctp_sysctl.h> 41f8829a4aSRandall Stewart #ifdef INET6 42f8829a4aSRandall Stewart #endif 43f8829a4aSRandall Stewart #include <netinet/sctp_header.h> 44f8829a4aSRandall Stewart #include <netinet/sctp_output.h> 45f8829a4aSRandall Stewart #include <netinet/sctp_uio.h> 46f8829a4aSRandall Stewart #include <netinet/sctp_timer.h> 47f8829a4aSRandall Stewart #include <netinet/sctp_indata.h>/* for sctp_deliver_data() */ 48f8829a4aSRandall Stewart #include <netinet/sctp_auth.h> 49f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h> 50f7517433SRandall Stewart #include <netinet/sctp_bsd_addr.h> 51f8829a4aSRandall Stewart 52f8829a4aSRandall Stewart 53b9e7085aSRandall Stewart #ifndef KTR_SCTP 54b9e7085aSRandall Stewart #define KTR_SCTP KTR_SUBSYS 5580fefe0aSRandall Stewart #endif 56f8829a4aSRandall Stewart 570e9a9c10SMichael Tuexen extern struct sctp_cc_functions sctp_cc_functions[]; 58f7a77f6fSMichael Tuexen extern struct sctp_ss_functions sctp_ss_functions[]; 590e9a9c10SMichael Tuexen 60f8829a4aSRandall Stewart void 61dcb68fbaSMichael Tuexen sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr) 62f8829a4aSRandall Stewart { 6380fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 64f8829a4aSRandall Stewart 6580fefe0aSRandall Stewart sctp_clog.x.sb.stcb = stcb; 6680fefe0aSRandall Stewart sctp_clog.x.sb.so_sbcc = sb->sb_cc; 67f8829a4aSRandall Stewart if (stcb) 6880fefe0aSRandall Stewart sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc; 69f8829a4aSRandall Stewart else 7080fefe0aSRandall Stewart sctp_clog.x.sb.stcb_sbcc = 0; 7180fefe0aSRandall Stewart sctp_clog.x.sb.incr = incr; 72c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 7380fefe0aSRandall Stewart SCTP_LOG_EVENT_SB, 7480fefe0aSRandall Stewart from, 7580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 7680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 7780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 7880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 79f8829a4aSRandall Stewart } 80f8829a4aSRandall Stewart 81f8829a4aSRandall Stewart void 82f8829a4aSRandall Stewart sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) 83f8829a4aSRandall Stewart { 8480fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 85f8829a4aSRandall Stewart 8680fefe0aSRandall Stewart sctp_clog.x.close.inp = (void *)inp; 8780fefe0aSRandall Stewart sctp_clog.x.close.sctp_flags = inp->sctp_flags; 88f8829a4aSRandall Stewart if (stcb) { 8980fefe0aSRandall Stewart sctp_clog.x.close.stcb = (void *)stcb; 9080fefe0aSRandall Stewart sctp_clog.x.close.state = (uint16_t) stcb->asoc.state; 91f8829a4aSRandall Stewart } else { 9280fefe0aSRandall Stewart sctp_clog.x.close.stcb = 0; 9380fefe0aSRandall Stewart sctp_clog.x.close.state = 0; 94f8829a4aSRandall Stewart } 9580fefe0aSRandall Stewart sctp_clog.x.close.loc = loc; 96c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 9780fefe0aSRandall Stewart SCTP_LOG_EVENT_CLOSE, 9880fefe0aSRandall Stewart 0, 9980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 10080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 10180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 10280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 103f8829a4aSRandall Stewart } 104f8829a4aSRandall Stewart 105f8829a4aSRandall Stewart void 106f8829a4aSRandall Stewart rto_logging(struct sctp_nets *net, int from) 107f8829a4aSRandall Stewart { 10880fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 109f8829a4aSRandall Stewart 110bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 11180fefe0aSRandall Stewart sctp_clog.x.rto.net = (void *)net; 112be1d9176SMichael Tuexen sctp_clog.x.rto.rtt = net->rtt / 1000; 113c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 11480fefe0aSRandall Stewart SCTP_LOG_EVENT_RTT, 11580fefe0aSRandall Stewart from, 11680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 11780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 11880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 11980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 120f8829a4aSRandall Stewart } 121f8829a4aSRandall Stewart 122f8829a4aSRandall Stewart void 1236a91f103SRandall Stewart sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from) 124f8829a4aSRandall Stewart { 12580fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 126f8829a4aSRandall Stewart 12780fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = stcb; 12880fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = tsn; 12980fefe0aSRandall Stewart sctp_clog.x.strlog.n_sseq = sseq; 13080fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 13180fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 13280fefe0aSRandall Stewart sctp_clog.x.strlog.strm = stream; 133c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 13480fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 13580fefe0aSRandall Stewart from, 13680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 13780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 13880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 13980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 140f8829a4aSRandall Stewart } 141f8829a4aSRandall Stewart 142f8829a4aSRandall Stewart void 143f8829a4aSRandall Stewart sctp_log_nagle_event(struct sctp_tcb *stcb, int action) 144f8829a4aSRandall Stewart { 14580fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 146f8829a4aSRandall Stewart 14780fefe0aSRandall Stewart sctp_clog.x.nagle.stcb = (void *)stcb; 14880fefe0aSRandall Stewart sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight; 14980fefe0aSRandall Stewart sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size; 15080fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue; 15180fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count; 152c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 15380fefe0aSRandall Stewart SCTP_LOG_EVENT_NAGLE, 15480fefe0aSRandall Stewart action, 15580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 15680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 15780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 15880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 159f8829a4aSRandall Stewart } 160f8829a4aSRandall Stewart 161f8829a4aSRandall Stewart void 162f8829a4aSRandall Stewart sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from) 163f8829a4aSRandall Stewart { 16480fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 165f8829a4aSRandall Stewart 16680fefe0aSRandall Stewart sctp_clog.x.sack.cumack = cumack; 16780fefe0aSRandall Stewart sctp_clog.x.sack.oldcumack = old_cumack; 16880fefe0aSRandall Stewart sctp_clog.x.sack.tsn = tsn; 16980fefe0aSRandall Stewart sctp_clog.x.sack.numGaps = gaps; 17080fefe0aSRandall Stewart sctp_clog.x.sack.numDups = dups; 171c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 17280fefe0aSRandall Stewart SCTP_LOG_EVENT_SACK, 17380fefe0aSRandall Stewart from, 17480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 17580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 17680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 17780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 178f8829a4aSRandall Stewart } 179f8829a4aSRandall Stewart 180f8829a4aSRandall Stewart void 181f8829a4aSRandall Stewart sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) 182f8829a4aSRandall Stewart { 18380fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 184f8829a4aSRandall Stewart 185bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 18680fefe0aSRandall Stewart sctp_clog.x.map.base = map; 18780fefe0aSRandall Stewart sctp_clog.x.map.cum = cum; 18880fefe0aSRandall Stewart sctp_clog.x.map.high = high; 189c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 19080fefe0aSRandall Stewart SCTP_LOG_EVENT_MAP, 19180fefe0aSRandall Stewart from, 19280fefe0aSRandall Stewart sctp_clog.x.misc.log1, 19380fefe0aSRandall Stewart sctp_clog.x.misc.log2, 19480fefe0aSRandall Stewart sctp_clog.x.misc.log3, 19580fefe0aSRandall Stewart sctp_clog.x.misc.log4); 196f8829a4aSRandall Stewart } 197f8829a4aSRandall Stewart 198f8829a4aSRandall Stewart void 199dcb68fbaSMichael Tuexen sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from) 200f8829a4aSRandall Stewart { 20180fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 202f8829a4aSRandall Stewart 203bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 20480fefe0aSRandall Stewart sctp_clog.x.fr.largest_tsn = biggest_tsn; 20580fefe0aSRandall Stewart sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn; 20680fefe0aSRandall Stewart sctp_clog.x.fr.tsn = tsn; 207c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 20880fefe0aSRandall Stewart SCTP_LOG_EVENT_FR, 20980fefe0aSRandall Stewart from, 21080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 21180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 21280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 21380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 214f8829a4aSRandall Stewart } 215f8829a4aSRandall Stewart 216f8829a4aSRandall Stewart void 217f8829a4aSRandall Stewart sctp_log_mb(struct mbuf *m, int from) 218f8829a4aSRandall Stewart { 21980fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 220f8829a4aSRandall Stewart 22180fefe0aSRandall Stewart sctp_clog.x.mb.mp = m; 22280fefe0aSRandall Stewart sctp_clog.x.mb.mbuf_flags = (uint8_t) (SCTP_BUF_GET_FLAGS(m)); 22380fefe0aSRandall Stewart sctp_clog.x.mb.size = (uint16_t) (SCTP_BUF_LEN(m)); 22480fefe0aSRandall Stewart sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0); 225139bc87fSRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 22680fefe0aSRandall Stewart sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m); 22780fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = (uint8_t) (SCTP_BUF_EXTEND_REFCNT(m)); 228f8829a4aSRandall Stewart } else { 22980fefe0aSRandall Stewart sctp_clog.x.mb.ext = 0; 23080fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = 0; 231f8829a4aSRandall Stewart } 232c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 23380fefe0aSRandall Stewart SCTP_LOG_EVENT_MBUF, 23480fefe0aSRandall Stewart from, 23580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 23680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 23780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 23880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 239f8829a4aSRandall Stewart } 240f8829a4aSRandall Stewart 241f8829a4aSRandall Stewart void 242dcb68fbaSMichael Tuexen sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from) 243f8829a4aSRandall Stewart { 24480fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 245f8829a4aSRandall Stewart 246f8829a4aSRandall Stewart if (control == NULL) { 247ad81507eSRandall Stewart SCTP_PRINTF("Gak log of NULL?\n"); 248f8829a4aSRandall Stewart return; 249f8829a4aSRandall Stewart } 25080fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = control->stcb; 25180fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = control->sinfo_tsn; 25280fefe0aSRandall Stewart sctp_clog.x.strlog.n_sseq = control->sinfo_ssn; 25380fefe0aSRandall Stewart sctp_clog.x.strlog.strm = control->sinfo_stream; 254f8829a4aSRandall Stewart if (poschk != NULL) { 25580fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn; 25680fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = poschk->sinfo_ssn; 257f8829a4aSRandall Stewart } else { 25880fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 25980fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 260f8829a4aSRandall Stewart } 261c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 26280fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 26380fefe0aSRandall Stewart from, 26480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 26580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 26680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 26780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 268f8829a4aSRandall Stewart } 269f8829a4aSRandall Stewart 270f8829a4aSRandall Stewart void 271f8829a4aSRandall Stewart sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from) 272f8829a4aSRandall Stewart { 27380fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 274f8829a4aSRandall Stewart 27580fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 276f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 27780fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 278f8829a4aSRandall Stewart else 27980fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 280f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 28180fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 282f8829a4aSRandall Stewart else 28380fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 284f8829a4aSRandall Stewart 285f8829a4aSRandall Stewart if (net) { 28680fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = net->cwnd; 28780fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 28880fefe0aSRandall Stewart sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack; 28980fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack; 29080fefe0aSRandall Stewart sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack; 291f8829a4aSRandall Stewart } 292f8829a4aSRandall Stewart if (SCTP_CWNDLOG_PRESEND == from) { 29380fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd; 294f8829a4aSRandall Stewart } 29580fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = augment; 296c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 29780fefe0aSRandall Stewart SCTP_LOG_EVENT_CWND, 29880fefe0aSRandall Stewart from, 29980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 30080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 30180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 30280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 303f8829a4aSRandall Stewart } 304f8829a4aSRandall Stewart 305f8829a4aSRandall Stewart void 306f8829a4aSRandall Stewart sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) 307f8829a4aSRandall Stewart { 30880fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 309f8829a4aSRandall Stewart 310bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 31103b0b021SRandall Stewart if (inp) { 31280fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)inp->sctp_socket; 31303b0b021SRandall Stewart 31403b0b021SRandall Stewart } else { 31580fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)NULL; 31603b0b021SRandall Stewart } 31780fefe0aSRandall Stewart sctp_clog.x.lock.inp = (void *)inp; 318f8829a4aSRandall Stewart if (stcb) { 31980fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx); 320f8829a4aSRandall Stewart } else { 32180fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN; 322f8829a4aSRandall Stewart } 323f8829a4aSRandall Stewart if (inp) { 32480fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx); 32580fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx); 326f8829a4aSRandall Stewart } else { 32780fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN; 32880fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN; 329f8829a4aSRandall Stewart } 330b3f1ea41SRandall Stewart sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); 33152129fcdSRandall Stewart if (inp && (inp->sctp_socket)) { 33280fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 33380fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 33480fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx)); 335f8829a4aSRandall Stewart } else { 33680fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN; 33780fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; 33880fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN; 339f8829a4aSRandall Stewart } 340c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 34180fefe0aSRandall Stewart SCTP_LOG_LOCK_EVENT, 34280fefe0aSRandall Stewart from, 34380fefe0aSRandall Stewart sctp_clog.x.misc.log1, 34480fefe0aSRandall Stewart sctp_clog.x.misc.log2, 34580fefe0aSRandall Stewart sctp_clog.x.misc.log3, 34680fefe0aSRandall Stewart sctp_clog.x.misc.log4); 347f8829a4aSRandall Stewart } 348f8829a4aSRandall Stewart 349f8829a4aSRandall Stewart void 350f8829a4aSRandall Stewart sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from) 351f8829a4aSRandall Stewart { 35280fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 353f8829a4aSRandall Stewart 354bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 35580fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 35680fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = error; 35780fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 35880fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = burst; 359f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 36080fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 361f8829a4aSRandall Stewart else 36280fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 363f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 36480fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 365f8829a4aSRandall Stewart else 36680fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 367c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 36880fefe0aSRandall Stewart SCTP_LOG_EVENT_MAXBURST, 36980fefe0aSRandall Stewart from, 37080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 37180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 37280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 37380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 374f8829a4aSRandall Stewart } 375f8829a4aSRandall Stewart 376f8829a4aSRandall Stewart void 377f8829a4aSRandall Stewart sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead) 378f8829a4aSRandall Stewart { 37980fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 380f8829a4aSRandall Stewart 38180fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 38280fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = snd_size; 38380fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 38480fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = 0; 385c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 38680fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 38780fefe0aSRandall Stewart from, 38880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 38980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 39080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 39180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 392f8829a4aSRandall Stewart } 393f8829a4aSRandall Stewart 394f8829a4aSRandall Stewart void 395f8829a4aSRandall Stewart sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval) 396f8829a4aSRandall Stewart { 39780fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 398f8829a4aSRandall Stewart 39980fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 40080fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = flight_size; 40180fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 40280fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = a_rwndval; 403c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 40480fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 40580fefe0aSRandall Stewart from, 40680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 40780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 40880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 40980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 410f8829a4aSRandall Stewart } 411f8829a4aSRandall Stewart 412f8829a4aSRandall Stewart void 413f8829a4aSRandall Stewart sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt) 414f8829a4aSRandall Stewart { 41580fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 416f8829a4aSRandall Stewart 41780fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_size = total_oq; 41880fefe0aSRandall Stewart sctp_clog.x.mbcnt.size_change = book; 41980fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q; 42080fefe0aSRandall Stewart sctp_clog.x.mbcnt.mbcnt_change = mbcnt; 421c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 42280fefe0aSRandall Stewart SCTP_LOG_EVENT_MBCNT, 42380fefe0aSRandall Stewart from, 42480fefe0aSRandall Stewart sctp_clog.x.misc.log1, 42580fefe0aSRandall Stewart sctp_clog.x.misc.log2, 42680fefe0aSRandall Stewart sctp_clog.x.misc.log3, 42780fefe0aSRandall Stewart sctp_clog.x.misc.log4); 428f8829a4aSRandall Stewart } 429f8829a4aSRandall Stewart 430f8829a4aSRandall Stewart void 431f8829a4aSRandall Stewart sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) 432f8829a4aSRandall Stewart { 433c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 43480fefe0aSRandall Stewart SCTP_LOG_MISC_EVENT, 43580fefe0aSRandall Stewart from, 43680fefe0aSRandall Stewart a, b, c, d); 437f8829a4aSRandall Stewart } 438f8829a4aSRandall Stewart 439f8829a4aSRandall Stewart void 4407215cc1bSMichael Tuexen sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) 441f8829a4aSRandall Stewart { 44280fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 443f8829a4aSRandall Stewart 44480fefe0aSRandall Stewart sctp_clog.x.wake.stcb = (void *)stcb; 44580fefe0aSRandall Stewart sctp_clog.x.wake.wake_cnt = wake_cnt; 44680fefe0aSRandall Stewart sctp_clog.x.wake.flight = stcb->asoc.total_flight_count; 44780fefe0aSRandall Stewart sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt; 44880fefe0aSRandall Stewart sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt; 449f8829a4aSRandall Stewart 450f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt < 0xff) 45180fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = (uint8_t) stcb->asoc.stream_queue_cnt; 452f8829a4aSRandall Stewart else 45380fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = 0xff; 454f8829a4aSRandall Stewart 455f8829a4aSRandall Stewart if (stcb->asoc.chunks_on_out_queue < 0xff) 45680fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = (uint8_t) stcb->asoc.chunks_on_out_queue; 457f8829a4aSRandall Stewart else 45880fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = 0xff; 459f8829a4aSRandall Stewart 46080fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags = 0; 461f8829a4aSRandall Stewart /* set in the defered mode stuff */ 462f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) 46380fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 1; 464f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) 46580fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 2; 466f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) 46780fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 4; 468f8829a4aSRandall Stewart /* what about the sb */ 469f8829a4aSRandall Stewart if (stcb->sctp_socket) { 470f8829a4aSRandall Stewart struct socket *so = stcb->sctp_socket; 471f8829a4aSRandall Stewart 47280fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = (uint8_t) ((so->so_snd.sb_flags & 0x00ff)); 473f8829a4aSRandall Stewart } else { 47480fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = 0xff; 475f8829a4aSRandall Stewart } 476c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 47780fefe0aSRandall Stewart SCTP_LOG_EVENT_WAKE, 47880fefe0aSRandall Stewart from, 47980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 48080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 48180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 48280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 483f8829a4aSRandall Stewart } 484f8829a4aSRandall Stewart 485f8829a4aSRandall Stewart void 4867215cc1bSMichael Tuexen sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen) 487f8829a4aSRandall Stewart { 48880fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 489f8829a4aSRandall Stewart 49080fefe0aSRandall Stewart sctp_clog.x.blk.onsb = asoc->total_output_queue_size; 49180fefe0aSRandall Stewart sctp_clog.x.blk.send_sent_qcnt = (uint16_t) (asoc->send_queue_cnt + asoc->sent_queue_cnt); 49280fefe0aSRandall Stewart sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd; 49380fefe0aSRandall Stewart sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt; 49480fefe0aSRandall Stewart sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue; 49580fefe0aSRandall Stewart sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight / 1024); 49680fefe0aSRandall Stewart sctp_clog.x.blk.sndlen = sendlen; 497c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 49880fefe0aSRandall Stewart SCTP_LOG_EVENT_BLOCK, 49980fefe0aSRandall Stewart from, 50080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 50180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 50280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 50380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 504f8829a4aSRandall Stewart } 505f8829a4aSRandall Stewart 506f8829a4aSRandall Stewart int 5077215cc1bSMichael Tuexen sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED) 508f8829a4aSRandall Stewart { 50980fefe0aSRandall Stewart /* May need to fix this if ktrdump does not work */ 510f8829a4aSRandall Stewart return (0); 511f8829a4aSRandall Stewart } 512f8829a4aSRandall Stewart 513f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 514f8829a4aSRandall Stewart uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2]; 515f8829a4aSRandall Stewart static int sctp_audit_indx = 0; 516f8829a4aSRandall Stewart 517f8829a4aSRandall Stewart static 518f8829a4aSRandall Stewart void 519f8829a4aSRandall Stewart sctp_print_audit_report(void) 520f8829a4aSRandall Stewart { 521f8829a4aSRandall Stewart int i; 522f8829a4aSRandall Stewart int cnt; 523f8829a4aSRandall Stewart 524f8829a4aSRandall Stewart cnt = 0; 525f8829a4aSRandall Stewart for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) { 526f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 527f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 528f8829a4aSRandall Stewart cnt = 0; 529ad81507eSRandall Stewart SCTP_PRINTF("\n"); 530f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 531f8829a4aSRandall Stewart cnt = 0; 532ad81507eSRandall Stewart SCTP_PRINTF("\n"); 533f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 534f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 535ad81507eSRandall Stewart SCTP_PRINTF("\n"); 536f8829a4aSRandall Stewart cnt = 0; 537f8829a4aSRandall Stewart } 538ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0], 539f8829a4aSRandall Stewart (uint32_t) sctp_audit_data[i][1]); 540f8829a4aSRandall Stewart cnt++; 541f8829a4aSRandall Stewart if ((cnt % 14) == 0) 542ad81507eSRandall Stewart SCTP_PRINTF("\n"); 543f8829a4aSRandall Stewart } 544f8829a4aSRandall Stewart for (i = 0; i < sctp_audit_indx; i++) { 545f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 546f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 547f8829a4aSRandall Stewart cnt = 0; 548ad81507eSRandall Stewart SCTP_PRINTF("\n"); 549f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 550f8829a4aSRandall Stewart cnt = 0; 551ad81507eSRandall Stewart SCTP_PRINTF("\n"); 552f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 553f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 554ad81507eSRandall Stewart SCTP_PRINTF("\n"); 555f8829a4aSRandall Stewart cnt = 0; 556f8829a4aSRandall Stewart } 557ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0], 558f8829a4aSRandall Stewart (uint32_t) sctp_audit_data[i][1]); 559f8829a4aSRandall Stewart cnt++; 560f8829a4aSRandall Stewart if ((cnt % 14) == 0) 561ad81507eSRandall Stewart SCTP_PRINTF("\n"); 562f8829a4aSRandall Stewart } 563ad81507eSRandall Stewart SCTP_PRINTF("\n"); 564f8829a4aSRandall Stewart } 565f8829a4aSRandall Stewart 566f8829a4aSRandall Stewart void 567f8829a4aSRandall Stewart sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 568f8829a4aSRandall Stewart struct sctp_nets *net) 569f8829a4aSRandall Stewart { 570f8829a4aSRandall Stewart int resend_cnt, tot_out, rep, tot_book_cnt; 571f8829a4aSRandall Stewart struct sctp_nets *lnet; 572f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 573f8829a4aSRandall Stewart 574f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAA; 575f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from; 576f8829a4aSRandall Stewart sctp_audit_indx++; 577f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 578f8829a4aSRandall Stewart sctp_audit_indx = 0; 579f8829a4aSRandall Stewart } 580f8829a4aSRandall Stewart if (inp == NULL) { 581f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 582f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x01; 583f8829a4aSRandall Stewart sctp_audit_indx++; 584f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 585f8829a4aSRandall Stewart sctp_audit_indx = 0; 586f8829a4aSRandall Stewart } 587f8829a4aSRandall Stewart return; 588f8829a4aSRandall Stewart } 589f8829a4aSRandall Stewart if (stcb == NULL) { 590f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 591f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x02; 592f8829a4aSRandall Stewart sctp_audit_indx++; 593f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 594f8829a4aSRandall Stewart sctp_audit_indx = 0; 595f8829a4aSRandall Stewart } 596f8829a4aSRandall Stewart return; 597f8829a4aSRandall Stewart } 598f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA1; 599f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 600f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 601f8829a4aSRandall Stewart sctp_audit_indx++; 602f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 603f8829a4aSRandall Stewart sctp_audit_indx = 0; 604f8829a4aSRandall Stewart } 605f8829a4aSRandall Stewart rep = 0; 606f8829a4aSRandall Stewart tot_book_cnt = 0; 607f8829a4aSRandall Stewart resend_cnt = tot_out = 0; 608f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 609f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 610f8829a4aSRandall Stewart resend_cnt++; 611f8829a4aSRandall Stewart } else if (chk->sent < SCTP_DATAGRAM_RESEND) { 612f8829a4aSRandall Stewart tot_out += chk->book_size; 613f8829a4aSRandall Stewart tot_book_cnt++; 614f8829a4aSRandall Stewart } 615f8829a4aSRandall Stewart } 616f8829a4aSRandall Stewart if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) { 617f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 618f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA1; 619f8829a4aSRandall Stewart sctp_audit_indx++; 620f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 621f8829a4aSRandall Stewart sctp_audit_indx = 0; 622f8829a4aSRandall Stewart } 623ad81507eSRandall Stewart SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n", 624f8829a4aSRandall Stewart resend_cnt, stcb->asoc.sent_queue_retran_cnt); 625f8829a4aSRandall Stewart rep = 1; 626f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = resend_cnt; 627f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA2; 628f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 629f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 630f8829a4aSRandall Stewart sctp_audit_indx++; 631f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 632f8829a4aSRandall Stewart sctp_audit_indx = 0; 633f8829a4aSRandall Stewart } 634f8829a4aSRandall Stewart } 635f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 636f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 637f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA2; 638f8829a4aSRandall Stewart sctp_audit_indx++; 639f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 640f8829a4aSRandall Stewart sctp_audit_indx = 0; 641f8829a4aSRandall Stewart } 642f8829a4aSRandall Stewart rep = 1; 643ad81507eSRandall Stewart SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out, 644f8829a4aSRandall Stewart (int)stcb->asoc.total_flight); 645f8829a4aSRandall Stewart stcb->asoc.total_flight = tot_out; 646f8829a4aSRandall Stewart } 647f8829a4aSRandall Stewart if (tot_book_cnt != stcb->asoc.total_flight_count) { 648f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 649f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA5; 650f8829a4aSRandall Stewart sctp_audit_indx++; 651f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 652f8829a4aSRandall Stewart sctp_audit_indx = 0; 653f8829a4aSRandall Stewart } 654f8829a4aSRandall Stewart rep = 1; 655f31e6c7fSMichael Tuexen SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt); 656f8829a4aSRandall Stewart 657f8829a4aSRandall Stewart stcb->asoc.total_flight_count = tot_book_cnt; 658f8829a4aSRandall Stewart } 659f8829a4aSRandall Stewart tot_out = 0; 660f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 661f8829a4aSRandall Stewart tot_out += lnet->flight_size; 662f8829a4aSRandall Stewart } 663f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 664f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 665f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA3; 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 = 1; 671ad81507eSRandall Stewart SCTP_PRINTF("real flight:%d net total was %d\n", 672f8829a4aSRandall Stewart stcb->asoc.total_flight, tot_out); 673f8829a4aSRandall Stewart /* now corrective action */ 674f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 675f8829a4aSRandall Stewart 676f8829a4aSRandall Stewart tot_out = 0; 677f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 678f8829a4aSRandall Stewart if ((chk->whoTo == lnet) && 679f8829a4aSRandall Stewart (chk->sent < SCTP_DATAGRAM_RESEND)) { 680f8829a4aSRandall Stewart tot_out += chk->book_size; 681f8829a4aSRandall Stewart } 682f8829a4aSRandall Stewart } 683f8829a4aSRandall Stewart if (lnet->flight_size != tot_out) { 684f31e6c7fSMichael Tuexen SCTP_PRINTF("net:%p flight was %d corrected to %d\n", 685dd294dceSMichael Tuexen (void *)lnet, lnet->flight_size, 686ad81507eSRandall Stewart tot_out); 687f8829a4aSRandall Stewart lnet->flight_size = tot_out; 688f8829a4aSRandall Stewart } 689f8829a4aSRandall Stewart } 690f8829a4aSRandall Stewart } 691f8829a4aSRandall Stewart if (rep) { 692f8829a4aSRandall Stewart sctp_print_audit_report(); 693f8829a4aSRandall Stewart } 694f8829a4aSRandall Stewart } 695f8829a4aSRandall Stewart 696f8829a4aSRandall Stewart void 697f8829a4aSRandall Stewart sctp_audit_log(uint8_t ev, uint8_t fd) 698f8829a4aSRandall Stewart { 699f8829a4aSRandall Stewart 700f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = ev; 701f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = fd; 702f8829a4aSRandall Stewart sctp_audit_indx++; 703f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 704f8829a4aSRandall Stewart sctp_audit_indx = 0; 705f8829a4aSRandall Stewart } 706f8829a4aSRandall Stewart } 707f8829a4aSRandall Stewart 708f8829a4aSRandall Stewart #endif 709f8829a4aSRandall Stewart 710f8829a4aSRandall Stewart /* 71112af6654SMichael Tuexen * sctp_stop_timers_for_shutdown() should be called 71212af6654SMichael Tuexen * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT 71312af6654SMichael Tuexen * state to make sure that all timers are stopped. 71412af6654SMichael Tuexen */ 71512af6654SMichael Tuexen void 71612af6654SMichael Tuexen sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) 71712af6654SMichael Tuexen { 71812af6654SMichael Tuexen struct sctp_association *asoc; 71912af6654SMichael Tuexen struct sctp_nets *net; 72012af6654SMichael Tuexen 72112af6654SMichael Tuexen asoc = &stcb->asoc; 72212af6654SMichael Tuexen 72312af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); 72412af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); 72512af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer); 72612af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); 72712af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); 72812af6654SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 72912af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); 730ca85e948SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); 73112af6654SMichael Tuexen } 73212af6654SMichael Tuexen } 73312af6654SMichael Tuexen 73412af6654SMichael Tuexen /* 735f8829a4aSRandall Stewart * a list of sizes based on typical mtu's, used only if next hop size not 736f8829a4aSRandall Stewart * returned. 737f8829a4aSRandall Stewart */ 738437fc91aSMichael Tuexen static uint32_t sctp_mtu_sizes[] = { 739f8829a4aSRandall Stewart 68, 740f8829a4aSRandall Stewart 296, 741f8829a4aSRandall Stewart 508, 742f8829a4aSRandall Stewart 512, 743f8829a4aSRandall Stewart 544, 744f8829a4aSRandall Stewart 576, 745f8829a4aSRandall Stewart 1006, 746f8829a4aSRandall Stewart 1492, 747f8829a4aSRandall Stewart 1500, 748f8829a4aSRandall Stewart 1536, 749f8829a4aSRandall Stewart 2002, 750f8829a4aSRandall Stewart 2048, 751f8829a4aSRandall Stewart 4352, 752f8829a4aSRandall Stewart 4464, 753f8829a4aSRandall Stewart 8166, 754f8829a4aSRandall Stewart 17914, 755f8829a4aSRandall Stewart 32000, 756f8829a4aSRandall Stewart 65535 757f8829a4aSRandall Stewart }; 758f8829a4aSRandall Stewart 759f8829a4aSRandall Stewart /* 760437fc91aSMichael Tuexen * Return the largest MTU smaller than val. If there is no 761437fc91aSMichael Tuexen * entry, just return val. 762f8829a4aSRandall Stewart */ 763437fc91aSMichael Tuexen uint32_t 764437fc91aSMichael Tuexen sctp_get_prev_mtu(uint32_t val) 765437fc91aSMichael Tuexen { 766437fc91aSMichael Tuexen uint32_t i; 767437fc91aSMichael Tuexen 768437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[0]) { 769437fc91aSMichael Tuexen return (val); 770437fc91aSMichael Tuexen } 771437fc91aSMichael Tuexen for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 772437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[i]) { 773f8829a4aSRandall Stewart break; 774f8829a4aSRandall Stewart } 775f8829a4aSRandall Stewart } 776437fc91aSMichael Tuexen return (sctp_mtu_sizes[i - 1]); 777437fc91aSMichael Tuexen } 778437fc91aSMichael Tuexen 779437fc91aSMichael Tuexen /* 780437fc91aSMichael Tuexen * Return the smallest MTU larger than val. If there is no 781437fc91aSMichael Tuexen * entry, just return val. 782437fc91aSMichael Tuexen */ 783437fc91aSMichael Tuexen uint32_t 7847215cc1bSMichael Tuexen sctp_get_next_mtu(uint32_t val) 785437fc91aSMichael Tuexen { 786437fc91aSMichael Tuexen /* select another MTU that is just bigger than this one */ 787437fc91aSMichael Tuexen uint32_t i; 788437fc91aSMichael Tuexen 789437fc91aSMichael Tuexen for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 790437fc91aSMichael Tuexen if (val < sctp_mtu_sizes[i]) { 791437fc91aSMichael Tuexen return (sctp_mtu_sizes[i]); 792437fc91aSMichael Tuexen } 793437fc91aSMichael Tuexen } 794437fc91aSMichael Tuexen return (val); 795f8829a4aSRandall Stewart } 796f8829a4aSRandall Stewart 797f8829a4aSRandall Stewart void 798f8829a4aSRandall Stewart sctp_fill_random_store(struct sctp_pcb *m) 799f8829a4aSRandall Stewart { 800f8829a4aSRandall Stewart /* 801f8829a4aSRandall Stewart * Here we use the MD5/SHA-1 to hash with our good randomNumbers and 802f8829a4aSRandall Stewart * our counter. The result becomes our good random numbers and we 803f8829a4aSRandall Stewart * then setup to give these out. Note that we do no locking to 804f8829a4aSRandall Stewart * protect this. This is ok, since if competing folks call this we 80517205eccSRandall Stewart * will get more gobbled gook in the random store which is what we 806f8829a4aSRandall Stewart * want. There is a danger that two guys will use the same random 807f8829a4aSRandall Stewart * numbers, but thats ok too since that is random as well :-> 808f8829a4aSRandall Stewart */ 809f8829a4aSRandall Stewart m->store_at = 0; 810ad81507eSRandall Stewart (void)sctp_hmac(SCTP_HMAC, (uint8_t *) m->random_numbers, 811f8829a4aSRandall Stewart sizeof(m->random_numbers), (uint8_t *) & m->random_counter, 812f8829a4aSRandall Stewart sizeof(m->random_counter), (uint8_t *) m->random_store); 813f8829a4aSRandall Stewart m->random_counter++; 814f8829a4aSRandall Stewart } 815f8829a4aSRandall Stewart 816f8829a4aSRandall Stewart uint32_t 817851b7298SRandall Stewart sctp_select_initial_TSN(struct sctp_pcb *inp) 818f8829a4aSRandall Stewart { 819f8829a4aSRandall Stewart /* 820f8829a4aSRandall Stewart * A true implementation should use random selection process to get 821f8829a4aSRandall Stewart * the initial stream sequence number, using RFC1750 as a good 822f8829a4aSRandall Stewart * guideline 823f8829a4aSRandall Stewart */ 824139bc87fSRandall Stewart uint32_t x, *xp; 825f8829a4aSRandall Stewart uint8_t *p; 826851b7298SRandall Stewart int store_at, new_store; 827f8829a4aSRandall Stewart 828851b7298SRandall Stewart if (inp->initial_sequence_debug != 0) { 829f8829a4aSRandall Stewart uint32_t ret; 830f8829a4aSRandall Stewart 831851b7298SRandall Stewart ret = inp->initial_sequence_debug; 832851b7298SRandall Stewart inp->initial_sequence_debug++; 833f8829a4aSRandall Stewart return (ret); 834f8829a4aSRandall Stewart } 835851b7298SRandall Stewart retry: 836851b7298SRandall Stewart store_at = inp->store_at; 837851b7298SRandall Stewart new_store = store_at + sizeof(uint32_t); 838851b7298SRandall Stewart if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) { 839851b7298SRandall Stewart new_store = 0; 840f8829a4aSRandall Stewart } 841851b7298SRandall Stewart if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) { 842851b7298SRandall Stewart goto retry; 843851b7298SRandall Stewart } 844851b7298SRandall Stewart if (new_store == 0) { 845851b7298SRandall Stewart /* Refill the random store */ 846851b7298SRandall Stewart sctp_fill_random_store(inp); 847851b7298SRandall Stewart } 848851b7298SRandall Stewart p = &inp->random_store[store_at]; 849139bc87fSRandall Stewart xp = (uint32_t *) p; 850f8829a4aSRandall Stewart x = *xp; 851f8829a4aSRandall Stewart return (x); 852f8829a4aSRandall Stewart } 853f8829a4aSRandall Stewart 854f8829a4aSRandall Stewart uint32_t 8557215cc1bSMichael Tuexen sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check) 856f8829a4aSRandall Stewart { 8577215cc1bSMichael Tuexen uint32_t x; 858f8829a4aSRandall Stewart struct timeval now; 859f8829a4aSRandall Stewart 8607215cc1bSMichael Tuexen if (check) { 8616e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 8627215cc1bSMichael Tuexen } 8637215cc1bSMichael Tuexen for (;;) { 864851b7298SRandall Stewart x = sctp_select_initial_TSN(&inp->sctp_ep); 865f8829a4aSRandall Stewart if (x == 0) { 866f8829a4aSRandall Stewart /* we never use 0 */ 867f8829a4aSRandall Stewart continue; 868f8829a4aSRandall Stewart } 8697215cc1bSMichael Tuexen if (!check || sctp_is_vtag_good(x, lport, rport, &now)) { 8707215cc1bSMichael Tuexen break; 871f8829a4aSRandall Stewart } 872f8829a4aSRandall Stewart } 873f8829a4aSRandall Stewart return (x); 874f8829a4aSRandall Stewart } 875f8829a4aSRandall Stewart 876f8829a4aSRandall Stewart int 8770696e120SRandall Stewart sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, 878b5c16493SMichael Tuexen uint32_t override_tag, uint32_t vrf_id) 879f8829a4aSRandall Stewart { 8800696e120SRandall Stewart struct sctp_association *asoc; 8810696e120SRandall Stewart 882f8829a4aSRandall Stewart /* 883f8829a4aSRandall Stewart * Anything set to zero is taken care of by the allocation routine's 884f8829a4aSRandall Stewart * bzero 885f8829a4aSRandall Stewart */ 886f8829a4aSRandall Stewart 887f8829a4aSRandall Stewart /* 888f8829a4aSRandall Stewart * Up front select what scoping to apply on addresses I tell my peer 889f8829a4aSRandall Stewart * Not sure what to do with these right now, we will need to come up 890f8829a4aSRandall Stewart * with a way to set them. We may need to pass them through from the 891f8829a4aSRandall Stewart * caller in the sctp_aloc_assoc() function. 892f8829a4aSRandall Stewart */ 893f8829a4aSRandall Stewart int i; 894f8829a4aSRandall Stewart 8950696e120SRandall Stewart asoc = &stcb->asoc; 896f8829a4aSRandall Stewart /* init all variables to a known value. */ 897c4739e2fSRandall Stewart SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE); 898f8829a4aSRandall Stewart asoc->max_burst = m->sctp_ep.max_burst; 899899288aeSRandall Stewart asoc->fr_max_burst = m->sctp_ep.fr_max_burst; 900f8829a4aSRandall Stewart asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 901f8829a4aSRandall Stewart asoc->cookie_life = m->sctp_ep.def_cookie_life; 90220083c2eSMichael Tuexen asoc->sctp_cmt_on_off = m->sctp_cmt_on_off; 903c446091bSMichael Tuexen asoc->ecn_allowed = m->sctp_ecn_enable; 904830d754dSRandall Stewart asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off); 905ca85e948SMichael Tuexen asoc->sctp_cmt_pf = (uint8_t) 0; 906d61a0ae0SRandall Stewart asoc->sctp_frag_point = m->sctp_frag_point; 907e2e7c62eSMichael Tuexen asoc->sctp_features = m->sctp_features; 90858bdb691SMichael Tuexen asoc->default_dscp = m->sctp_ep.default_dscp; 90942551e99SRandall Stewart #ifdef INET6 91058bdb691SMichael Tuexen if (m->sctp_ep.default_flowlabel) { 91158bdb691SMichael Tuexen asoc->default_flowlabel = m->sctp_ep.default_flowlabel; 91258bdb691SMichael Tuexen } else { 91358bdb691SMichael Tuexen if (m->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) { 91458bdb691SMichael Tuexen asoc->default_flowlabel = sctp_select_initial_TSN(&m->sctp_ep); 91558bdb691SMichael Tuexen asoc->default_flowlabel &= 0x000fffff; 91658bdb691SMichael Tuexen asoc->default_flowlabel |= 0x80000000; 91758bdb691SMichael Tuexen } else { 918f8829a4aSRandall Stewart asoc->default_flowlabel = 0; 91958bdb691SMichael Tuexen } 92058bdb691SMichael Tuexen } 921f8829a4aSRandall Stewart #endif 9229f22f500SRandall Stewart asoc->sb_send_resv = 0; 923f8829a4aSRandall Stewart if (override_tag) { 924f8829a4aSRandall Stewart asoc->my_vtag = override_tag; 925f8829a4aSRandall Stewart } else { 926830d754dSRandall Stewart asoc->my_vtag = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 1); 927f8829a4aSRandall Stewart } 928de0e935bSRandall Stewart /* Get the nonce tags */ 929830d754dSRandall Stewart asoc->my_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 930830d754dSRandall Stewart asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 93142551e99SRandall Stewart asoc->vrf_id = vrf_id; 932de0e935bSRandall Stewart 93318e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 93418e198d3SRandall Stewart asoc->tsn_in_at = 0; 93518e198d3SRandall Stewart asoc->tsn_out_at = 0; 93618e198d3SRandall Stewart asoc->tsn_in_wrapped = 0; 93718e198d3SRandall Stewart asoc->tsn_out_wrapped = 0; 93818e198d3SRandall Stewart asoc->cumack_log_at = 0; 939b201f536SRandall Stewart asoc->cumack_log_atsnt = 0; 94018e198d3SRandall Stewart #endif 94118e198d3SRandall Stewart #ifdef SCTP_FS_SPEC_LOG 94218e198d3SRandall Stewart asoc->fs_index = 0; 94318e198d3SRandall Stewart #endif 944f8829a4aSRandall Stewart asoc->refcnt = 0; 945f8829a4aSRandall Stewart asoc->assoc_up_sent = 0; 946f8829a4aSRandall Stewart asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq = 947f8829a4aSRandall Stewart sctp_select_initial_TSN(&m->sctp_ep); 948c54a18d2SRandall Stewart asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; 949f8829a4aSRandall Stewart /* we are optimisitic here */ 950f8829a4aSRandall Stewart asoc->peer_supports_pktdrop = 1; 951830d754dSRandall Stewart asoc->peer_supports_nat = 0; 952f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 953f8829a4aSRandall Stewart 954f8829a4aSRandall Stewart /* for CMT */ 9558933fa13SRandall Stewart asoc->last_net_cmt_send_started = NULL; 956f8829a4aSRandall Stewart 957f8829a4aSRandall Stewart /* This will need to be adjusted */ 958f8829a4aSRandall Stewart asoc->last_acked_seq = asoc->init_seq_number - 1; 959f8829a4aSRandall Stewart asoc->advanced_peer_ack_point = asoc->last_acked_seq; 960f8829a4aSRandall Stewart asoc->asconf_seq_in = asoc->last_acked_seq; 961f8829a4aSRandall Stewart 962f8829a4aSRandall Stewart /* here we are different, we hold the next one we expect */ 963f8829a4aSRandall Stewart asoc->str_reset_seq_in = asoc->last_acked_seq + 1; 964f8829a4aSRandall Stewart 965f8829a4aSRandall Stewart asoc->initial_init_rto_max = m->sctp_ep.initial_init_rto_max; 966f8829a4aSRandall Stewart asoc->initial_rto = m->sctp_ep.initial_rto; 967f8829a4aSRandall Stewart 968f8829a4aSRandall Stewart asoc->max_init_times = m->sctp_ep.max_init_times; 969f8829a4aSRandall Stewart asoc->max_send_times = m->sctp_ep.max_send_times; 970f8829a4aSRandall Stewart asoc->def_net_failure = m->sctp_ep.def_net_failure; 971ca85e948SMichael Tuexen asoc->def_net_pf_threshold = m->sctp_ep.def_net_pf_threshold; 972f8829a4aSRandall Stewart asoc->free_chunk_cnt = 0; 973f8829a4aSRandall Stewart 974f8829a4aSRandall Stewart asoc->iam_blocking = 0; 975f8829a4aSRandall Stewart asoc->context = m->sctp_context; 976c4e848b7SRandall Stewart asoc->local_strreset_support = m->local_strreset_support; 977f8829a4aSRandall Stewart asoc->def_send = m->def_send; 978f8829a4aSRandall Stewart asoc->delayed_ack = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 97942551e99SRandall Stewart asoc->sack_freq = m->sctp_ep.sctp_sack_freq; 980f8829a4aSRandall Stewart asoc->pr_sctp_cnt = 0; 981f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 982f8829a4aSRandall Stewart 983f8829a4aSRandall Stewart if (m->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 984f8829a4aSRandall Stewart struct in6pcb *inp6; 985f8829a4aSRandall Stewart 986f8829a4aSRandall Stewart /* Its a V6 socket */ 987f8829a4aSRandall Stewart inp6 = (struct in6pcb *)m; 988f8829a4aSRandall Stewart asoc->ipv6_addr_legal = 1; 989f8829a4aSRandall Stewart /* Now look at the binding flag to see if V4 will be legal */ 99044b7479bSRandall Stewart if (SCTP_IPV6_V6ONLY(inp6) == 0) { 991f8829a4aSRandall Stewart asoc->ipv4_addr_legal = 1; 992f8829a4aSRandall Stewart } else { 993f8829a4aSRandall Stewart /* V4 addresses are NOT legal on the association */ 994f8829a4aSRandall Stewart asoc->ipv4_addr_legal = 0; 995f8829a4aSRandall Stewart } 996f8829a4aSRandall Stewart } else { 997f8829a4aSRandall Stewart /* Its a V4 socket, no - V6 */ 998f8829a4aSRandall Stewart asoc->ipv4_addr_legal = 1; 999f8829a4aSRandall Stewart asoc->ipv6_addr_legal = 0; 1000f8829a4aSRandall Stewart } 1001f8829a4aSRandall Stewart 100262c1ff9cSRandall Stewart asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(m->sctp_socket), SCTP_MINIMAL_RWND); 100362c1ff9cSRandall Stewart asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(m->sctp_socket); 1004f8829a4aSRandall Stewart 1005f8829a4aSRandall Stewart asoc->smallest_mtu = m->sctp_frag_point; 1006f8829a4aSRandall Stewart asoc->minrto = m->sctp_ep.sctp_minrto; 1007f8829a4aSRandall Stewart asoc->maxrto = m->sctp_ep.sctp_maxrto; 1008f8829a4aSRandall Stewart 1009f8829a4aSRandall Stewart asoc->locked_on_sending = NULL; 1010f8829a4aSRandall Stewart asoc->stream_locked_on = 0; 1011f8829a4aSRandall Stewart asoc->ecn_echo_cnt_onq = 0; 1012f8829a4aSRandall Stewart asoc->stream_locked = 0; 1013f8829a4aSRandall Stewart 101442551e99SRandall Stewart asoc->send_sack = 1; 101542551e99SRandall Stewart 101642551e99SRandall Stewart LIST_INIT(&asoc->sctp_restricted_addrs); 101742551e99SRandall Stewart 1018f8829a4aSRandall Stewart TAILQ_INIT(&asoc->nets); 1019f8829a4aSRandall Stewart TAILQ_INIT(&asoc->pending_reply_queue); 10202afb3e84SRandall Stewart TAILQ_INIT(&asoc->asconf_ack_sent); 1021f8829a4aSRandall Stewart /* Setup to fill the hb random cache at first HB */ 1022f8829a4aSRandall Stewart asoc->hb_random_idx = 4; 1023f8829a4aSRandall Stewart 1024f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks = m->sctp_ep.auto_close_time; 1025f8829a4aSRandall Stewart 10260e9a9c10SMichael Tuexen stcb->asoc.congestion_control_module = m->sctp_ep.sctp_default_cc_module; 10270e9a9c10SMichael Tuexen stcb->asoc.cc_functions = sctp_cc_functions[m->sctp_ep.sctp_default_cc_module]; 1028b54d3a6cSRandall Stewart 1029f7a77f6fSMichael Tuexen stcb->asoc.stream_scheduling_module = m->sctp_ep.sctp_default_ss_module; 1030f7a77f6fSMichael Tuexen stcb->asoc.ss_functions = sctp_ss_functions[m->sctp_ep.sctp_default_ss_module]; 1031f7a77f6fSMichael Tuexen 1032b54d3a6cSRandall Stewart /* 1033f8829a4aSRandall Stewart * Now the stream parameters, here we allocate space for all streams 1034f8829a4aSRandall Stewart * that we request by default. 1035f8829a4aSRandall Stewart */ 1036ea44232bSRandall Stewart asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams = 1037f8829a4aSRandall Stewart m->sctp_ep.pre_open_stream_count; 1038f8829a4aSRandall Stewart SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *, 1039f8829a4aSRandall Stewart asoc->streamoutcnt * sizeof(struct sctp_stream_out), 1040207304d4SRandall Stewart SCTP_M_STRMO); 1041f8829a4aSRandall Stewart if (asoc->strmout == NULL) { 1042f8829a4aSRandall Stewart /* big trouble no memory */ 1043c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1044f8829a4aSRandall Stewart return (ENOMEM); 1045f8829a4aSRandall Stewart } 1046f8829a4aSRandall Stewart for (i = 0; i < asoc->streamoutcnt; i++) { 1047f8829a4aSRandall Stewart /* 1048f8829a4aSRandall Stewart * inbound side must be set to 0xffff, also NOTE when we get 1049f8829a4aSRandall Stewart * the INIT-ACK back (for INIT sender) we MUST reduce the 1050f8829a4aSRandall Stewart * count (streamoutcnt) but first check if we sent to any of 1051f8829a4aSRandall Stewart * the upper streams that were dropped (if some were). Those 1052f8829a4aSRandall Stewart * that were dropped must be notified to the upper layer as 1053f8829a4aSRandall Stewart * failed to send. 1054f8829a4aSRandall Stewart */ 1055f3b05218SMichael Tuexen asoc->strmout[i].next_sequence_send = 0x0; 1056f8829a4aSRandall Stewart TAILQ_INIT(&asoc->strmout[i].outqueue); 1057*325c8c46SMichael Tuexen asoc->strmout[i].chunks_on_queues = 0; 1058f8829a4aSRandall Stewart asoc->strmout[i].stream_no = i; 1059f8829a4aSRandall Stewart asoc->strmout[i].last_msg_incomplete = 0; 1060252f7f93SMichael Tuexen asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL); 1061f8829a4aSRandall Stewart } 1062f7a77f6fSMichael Tuexen asoc->ss_functions.sctp_ss_init(stcb, asoc, 0); 1063f7a77f6fSMichael Tuexen 1064f8829a4aSRandall Stewart /* Now the mapping array */ 1065f8829a4aSRandall Stewart asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; 1066f8829a4aSRandall Stewart SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size, 1067207304d4SRandall Stewart SCTP_M_MAP); 1068f8829a4aSRandall Stewart if (asoc->mapping_array == NULL) { 1069207304d4SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1070c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1071f8829a4aSRandall Stewart return (ENOMEM); 1072f8829a4aSRandall Stewart } 1073f8829a4aSRandall Stewart memset(asoc->mapping_array, 0, asoc->mapping_array_size); 1074b5c16493SMichael Tuexen SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size, 1075830d754dSRandall Stewart SCTP_M_MAP); 1076bf1be571SRandall Stewart if (asoc->nr_mapping_array == NULL) { 1077bf1be571SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1078bf1be571SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1079bf1be571SRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1080bf1be571SRandall Stewart return (ENOMEM); 1081bf1be571SRandall Stewart } 1082b5c16493SMichael Tuexen memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); 1083830d754dSRandall Stewart 1084f8829a4aSRandall Stewart /* Now the init of the other outqueues */ 1085f8829a4aSRandall Stewart TAILQ_INIT(&asoc->free_chunks); 1086f8829a4aSRandall Stewart TAILQ_INIT(&asoc->control_send_queue); 1087c54a18d2SRandall Stewart TAILQ_INIT(&asoc->asconf_send_queue); 1088f8829a4aSRandall Stewart TAILQ_INIT(&asoc->send_queue); 1089f8829a4aSRandall Stewart TAILQ_INIT(&asoc->sent_queue); 1090f8829a4aSRandall Stewart TAILQ_INIT(&asoc->reasmqueue); 1091f8829a4aSRandall Stewart TAILQ_INIT(&asoc->resetHead); 1092f8829a4aSRandall Stewart asoc->max_inbound_streams = m->sctp_ep.max_open_streams_intome; 1093f8829a4aSRandall Stewart TAILQ_INIT(&asoc->asconf_queue); 1094f8829a4aSRandall Stewart /* authentication fields */ 1095f8829a4aSRandall Stewart asoc->authinfo.random = NULL; 1096830d754dSRandall Stewart asoc->authinfo.active_keyid = 0; 1097f8829a4aSRandall Stewart asoc->authinfo.assoc_key = NULL; 1098f8829a4aSRandall Stewart asoc->authinfo.assoc_keyid = 0; 1099f8829a4aSRandall Stewart asoc->authinfo.recv_key = NULL; 1100f8829a4aSRandall Stewart asoc->authinfo.recv_keyid = 0; 1101f8829a4aSRandall Stewart LIST_INIT(&asoc->shared_keys); 1102f42a358aSRandall Stewart asoc->marked_retrans = 0; 1103c9c58059SMichael Tuexen asoc->port = m->sctp_ep.port; 1104f42a358aSRandall Stewart asoc->timoinit = 0; 1105f42a358aSRandall Stewart asoc->timodata = 0; 1106f42a358aSRandall Stewart asoc->timosack = 0; 1107f42a358aSRandall Stewart asoc->timoshutdown = 0; 1108f42a358aSRandall Stewart asoc->timoheartbeat = 0; 1109f42a358aSRandall Stewart asoc->timocookie = 0; 1110f42a358aSRandall Stewart asoc->timoshutdownack = 0; 11116e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&asoc->start_time); 11126e55db54SRandall Stewart asoc->discontinuity_time = asoc->start_time; 1113eacc51c5SRandall Stewart /* 1114eacc51c5SRandall Stewart * sa_ignore MEMLEAK {memory is put in the assoc mapping array and 111577acdc25SRandall Stewart * freed later when the association is freed. 1116eacc51c5SRandall Stewart */ 1117f8829a4aSRandall Stewart return (0); 1118f8829a4aSRandall Stewart } 1119f8829a4aSRandall Stewart 11200e13104dSRandall Stewart void 11210e13104dSRandall Stewart sctp_print_mapping_array(struct sctp_association *asoc) 11220e13104dSRandall Stewart { 1123aed5947cSMichael Tuexen unsigned int i, limit; 11240e13104dSRandall Stewart 1125cd3fd531SMichael Tuexen SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n", 11260e13104dSRandall Stewart asoc->mapping_array_size, 11270e13104dSRandall Stewart asoc->mapping_array_base_tsn, 11280e13104dSRandall Stewart asoc->cumulative_tsn, 1129aed5947cSMichael Tuexen asoc->highest_tsn_inside_map, 1130aed5947cSMichael Tuexen asoc->highest_tsn_inside_nr_map); 1131aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 113260990c0cSMichael Tuexen if (asoc->mapping_array[limit - 1] != 0) { 113377acdc25SRandall Stewart break; 113477acdc25SRandall Stewart } 113577acdc25SRandall Stewart } 1136cd3fd531SMichael Tuexen SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 113777acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1138cd3fd531SMichael Tuexen SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 113977acdc25SRandall Stewart } 1140aed5947cSMichael Tuexen if (limit % 16) 1141cd3fd531SMichael Tuexen SCTP_PRINTF("\n"); 1142aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 1143aed5947cSMichael Tuexen if (asoc->nr_mapping_array[limit - 1]) { 114477acdc25SRandall Stewart break; 114577acdc25SRandall Stewart } 114677acdc25SRandall Stewart } 1147cd3fd531SMichael Tuexen SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 114877acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1149cd3fd531SMichael Tuexen SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 11500e13104dSRandall Stewart } 1151aed5947cSMichael Tuexen if (limit % 16) 1152cd3fd531SMichael Tuexen SCTP_PRINTF("\n"); 11530e13104dSRandall Stewart } 11540e13104dSRandall Stewart 1155f8829a4aSRandall Stewart int 11560696e120SRandall Stewart sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed) 1157f8829a4aSRandall Stewart { 1158f8829a4aSRandall Stewart /* mapping array needs to grow */ 1159b5c16493SMichael Tuexen uint8_t *new_array1, *new_array2; 11600696e120SRandall Stewart uint32_t new_size; 1161f8829a4aSRandall Stewart 11620696e120SRandall Stewart new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR); 1163b5c16493SMichael Tuexen SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP); 1164b5c16493SMichael Tuexen SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP); 1165b5c16493SMichael Tuexen if ((new_array1 == NULL) || (new_array2 == NULL)) { 1166f8829a4aSRandall Stewart /* can't get more, forget it */ 1167b5c16493SMichael Tuexen SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size); 1168b5c16493SMichael Tuexen if (new_array1) { 1169b5c16493SMichael Tuexen SCTP_FREE(new_array1, SCTP_M_MAP); 1170b5c16493SMichael Tuexen } 1171b5c16493SMichael Tuexen if (new_array2) { 1172b5c16493SMichael Tuexen SCTP_FREE(new_array2, SCTP_M_MAP); 1173b5c16493SMichael Tuexen } 1174f8829a4aSRandall Stewart return (-1); 1175f8829a4aSRandall Stewart } 1176b5c16493SMichael Tuexen memset(new_array1, 0, new_size); 1177b5c16493SMichael Tuexen memset(new_array2, 0, new_size); 1178b5c16493SMichael Tuexen memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size); 1179b5c16493SMichael Tuexen memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size); 1180207304d4SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1181830d754dSRandall Stewart SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); 1182b5c16493SMichael Tuexen asoc->mapping_array = new_array1; 1183b5c16493SMichael Tuexen asoc->nr_mapping_array = new_array2; 1184b5c16493SMichael Tuexen asoc->mapping_array_size = new_size; 1185830d754dSRandall Stewart return (0); 1186830d754dSRandall Stewart } 1187830d754dSRandall Stewart 11888933fa13SRandall Stewart 118942551e99SRandall Stewart static void 119042551e99SRandall Stewart sctp_iterator_work(struct sctp_iterator *it) 119142551e99SRandall Stewart { 119242551e99SRandall Stewart int iteration_count = 0; 119342551e99SRandall Stewart int inp_skip = 0; 1194ec4c19fcSRandall Stewart int first_in = 1; 1195ec4c19fcSRandall Stewart struct sctp_inpcb *tinp; 119642551e99SRandall Stewart 1197ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 119842551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1199ad81507eSRandall Stewart if (it->inp) { 1200ec4c19fcSRandall Stewart SCTP_INP_RLOCK(it->inp); 120142551e99SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1202ad81507eSRandall Stewart } 120342551e99SRandall Stewart if (it->inp == NULL) { 120442551e99SRandall Stewart /* iterator is complete */ 120542551e99SRandall Stewart done_with_iterator: 120642551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1207ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 120842551e99SRandall Stewart if (it->function_atend != NULL) { 120942551e99SRandall Stewart (*it->function_atend) (it->pointer, it->val); 121042551e99SRandall Stewart } 1211207304d4SRandall Stewart SCTP_FREE(it, SCTP_M_ITER); 121242551e99SRandall Stewart return; 121342551e99SRandall Stewart } 121442551e99SRandall Stewart select_a_new_ep: 1215ec4c19fcSRandall Stewart if (first_in) { 1216ec4c19fcSRandall Stewart first_in = 0; 1217ec4c19fcSRandall Stewart } else { 1218f7517433SRandall Stewart SCTP_INP_RLOCK(it->inp); 1219ec4c19fcSRandall Stewart } 122042551e99SRandall Stewart while (((it->pcb_flags) && 122142551e99SRandall Stewart ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || 122242551e99SRandall Stewart ((it->pcb_features) && 122342551e99SRandall Stewart ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { 122442551e99SRandall Stewart /* endpoint flags or features don't match, so keep looking */ 122542551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1226f7517433SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 122742551e99SRandall Stewart goto done_with_iterator; 122842551e99SRandall Stewart } 1229ec4c19fcSRandall Stewart tinp = it->inp; 123042551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1231ec4c19fcSRandall Stewart SCTP_INP_RUNLOCK(tinp); 123242551e99SRandall Stewart if (it->inp == NULL) { 123342551e99SRandall Stewart goto done_with_iterator; 123442551e99SRandall Stewart } 123542551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1236f7517433SRandall Stewart } 123742551e99SRandall Stewart /* now go through each assoc which is in the desired state */ 123842551e99SRandall Stewart if (it->done_current_ep == 0) { 123942551e99SRandall Stewart if (it->function_inp != NULL) 124042551e99SRandall Stewart inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val); 124142551e99SRandall Stewart it->done_current_ep = 1; 124242551e99SRandall Stewart } 124342551e99SRandall Stewart if (it->stcb == NULL) { 124442551e99SRandall Stewart /* run the per instance function */ 124542551e99SRandall Stewart it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); 124642551e99SRandall Stewart } 124742551e99SRandall Stewart if ((inp_skip) || it->stcb == NULL) { 124842551e99SRandall Stewart if (it->function_inp_end != NULL) { 124942551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 125042551e99SRandall Stewart it->pointer, 125142551e99SRandall Stewart it->val); 125242551e99SRandall Stewart } 125342551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 125442551e99SRandall Stewart goto no_stcb; 125542551e99SRandall Stewart } 125642551e99SRandall Stewart while (it->stcb) { 125742551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 125842551e99SRandall Stewart if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { 125942551e99SRandall Stewart /* not in the right state... keep looking */ 126042551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 126142551e99SRandall Stewart goto next_assoc; 126242551e99SRandall Stewart } 126342551e99SRandall Stewart /* see if we have limited out the iterator loop */ 126442551e99SRandall Stewart iteration_count++; 126542551e99SRandall Stewart if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { 126642551e99SRandall Stewart /* Pause to let others grab the lock */ 126742551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, 1); 126842551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1269c4739e2fSRandall Stewart SCTP_INP_INCR_REF(it->inp); 127042551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 127142551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1272ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 1273ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 127442551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1275f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags) { 1276f7517433SRandall Stewart /* We won't be staying here */ 1277f7517433SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1278f7517433SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 1279f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1280f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_IT) { 1281f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT; 1282f7517433SRandall Stewart goto done_with_iterator; 1283f7517433SRandall Stewart } 1284f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1285f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_INP) { 1286f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP; 1287f7517433SRandall Stewart goto no_stcb; 1288f7517433SRandall Stewart } 1289f7517433SRandall Stewart /* If we reach here huh? */ 1290cd3fd531SMichael Tuexen SCTP_PRINTF("Unknown it ctl flag %x\n", 1291f7517433SRandall Stewart sctp_it_ctl.iterator_flags); 1292f7517433SRandall Stewart sctp_it_ctl.iterator_flags = 0; 1293f7517433SRandall Stewart } 129442551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1295c4739e2fSRandall Stewart SCTP_INP_DECR_REF(it->inp); 129642551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 129742551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 129842551e99SRandall Stewart iteration_count = 0; 129942551e99SRandall Stewart } 130042551e99SRandall Stewart /* run function on this one */ 130142551e99SRandall Stewart (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val); 130242551e99SRandall Stewart 130342551e99SRandall Stewart /* 130442551e99SRandall Stewart * we lie here, it really needs to have its own type but 130542551e99SRandall Stewart * first I must verify that this won't effect things :-0 130642551e99SRandall Stewart */ 130742551e99SRandall Stewart if (it->no_chunk_output == 0) 1308ceaad40aSRandall Stewart sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 130942551e99SRandall Stewart 131042551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 131142551e99SRandall Stewart next_assoc: 131242551e99SRandall Stewart it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); 131342551e99SRandall Stewart if (it->stcb == NULL) { 131442551e99SRandall Stewart /* Run last function */ 131542551e99SRandall Stewart if (it->function_inp_end != NULL) { 131642551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 131742551e99SRandall Stewart it->pointer, 131842551e99SRandall Stewart it->val); 131942551e99SRandall Stewart } 132042551e99SRandall Stewart } 132142551e99SRandall Stewart } 132242551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 132342551e99SRandall Stewart no_stcb: 132442551e99SRandall Stewart /* done with all assocs on this endpoint, move on to next endpoint */ 132542551e99SRandall Stewart it->done_current_ep = 0; 132642551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 132742551e99SRandall Stewart it->inp = NULL; 132842551e99SRandall Stewart } else { 132942551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 133042551e99SRandall Stewart } 133142551e99SRandall Stewart if (it->inp == NULL) { 133242551e99SRandall Stewart goto done_with_iterator; 133342551e99SRandall Stewart } 133442551e99SRandall Stewart goto select_a_new_ep; 133542551e99SRandall Stewart } 133642551e99SRandall Stewart 133742551e99SRandall Stewart void 133842551e99SRandall Stewart sctp_iterator_worker(void) 133942551e99SRandall Stewart { 13404a9ef3f8SMichael Tuexen struct sctp_iterator *it, *nit; 134142551e99SRandall Stewart 134242551e99SRandall Stewart /* This function is called with the WQ lock in place */ 134342551e99SRandall Stewart 1344f7517433SRandall Stewart sctp_it_ctl.iterator_running = 1; 13454a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { 13464a9ef3f8SMichael Tuexen sctp_it_ctl.cur_it = it; 134742551e99SRandall Stewart /* now lets work on this one */ 1348f7517433SRandall Stewart TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); 134942551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_UNLOCK(); 1350f7517433SRandall Stewart CURVNET_SET(it->vn); 135142551e99SRandall Stewart sctp_iterator_work(it); 1352f79aab18SRandall Stewart sctp_it_ctl.cur_it = NULL; 1353f7517433SRandall Stewart CURVNET_RESTORE(); 135442551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_LOCK(); 13553c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 135642551e99SRandall Stewart } 1357f7517433SRandall Stewart sctp_it_ctl.iterator_running = 0; 135842551e99SRandall Stewart return; 135942551e99SRandall Stewart } 136042551e99SRandall Stewart 1361f8829a4aSRandall Stewart 1362f8829a4aSRandall Stewart static void 1363f8829a4aSRandall Stewart sctp_handle_addr_wq(void) 1364f8829a4aSRandall Stewart { 1365f8829a4aSRandall Stewart /* deal with the ADDR wq from the rtsock calls */ 13664a9ef3f8SMichael Tuexen struct sctp_laddr *wi, *nwi; 136742551e99SRandall Stewart struct sctp_asconf_iterator *asc; 1368f8829a4aSRandall Stewart 136942551e99SRandall Stewart SCTP_MALLOC(asc, struct sctp_asconf_iterator *, 1370207304d4SRandall Stewart sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT); 137142551e99SRandall Stewart if (asc == NULL) { 137242551e99SRandall Stewart /* Try later, no memory */ 1373f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 1374f8829a4aSRandall Stewart (struct sctp_inpcb *)NULL, 1375f8829a4aSRandall Stewart (struct sctp_tcb *)NULL, 1376f8829a4aSRandall Stewart (struct sctp_nets *)NULL); 137742551e99SRandall Stewart return; 1378f8829a4aSRandall Stewart } 137942551e99SRandall Stewart LIST_INIT(&asc->list_of_work); 138042551e99SRandall Stewart asc->cnt = 0; 1381f7517433SRandall Stewart 1382f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 13834a9ef3f8SMichael Tuexen LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { 138442551e99SRandall Stewart LIST_REMOVE(wi, sctp_nxt_addr); 138542551e99SRandall Stewart LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); 138642551e99SRandall Stewart asc->cnt++; 1387f8829a4aSRandall Stewart } 1388f7517433SRandall Stewart SCTP_WQ_ADDR_UNLOCK(); 1389f7517433SRandall Stewart 139042551e99SRandall Stewart if (asc->cnt == 0) { 1391207304d4SRandall Stewart SCTP_FREE(asc, SCTP_M_ASC_IT); 139242551e99SRandall Stewart } else { 13931b649582SRandall Stewart (void)sctp_initiate_iterator(sctp_asconf_iterator_ep, 13941b649582SRandall Stewart sctp_asconf_iterator_stcb, 139542551e99SRandall Stewart NULL, /* No ep end for boundall */ 139642551e99SRandall Stewart SCTP_PCB_FLAGS_BOUNDALL, 139742551e99SRandall Stewart SCTP_PCB_ANY_FEATURES, 13981b649582SRandall Stewart SCTP_ASOC_ANY_STATE, 13991b649582SRandall Stewart (void *)asc, 0, 14001b649582SRandall Stewart sctp_asconf_iterator_end, NULL, 0); 140142551e99SRandall Stewart } 1402f8829a4aSRandall Stewart } 1403f8829a4aSRandall Stewart 1404f8829a4aSRandall Stewart void 1405f8829a4aSRandall Stewart sctp_timeout_handler(void *t) 1406f8829a4aSRandall Stewart { 1407f8829a4aSRandall Stewart struct sctp_inpcb *inp; 1408f8829a4aSRandall Stewart struct sctp_tcb *stcb; 1409f8829a4aSRandall Stewart struct sctp_nets *net; 1410f8829a4aSRandall Stewart struct sctp_timer *tmr; 1411ceaad40aSRandall Stewart 1412ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1413ceaad40aSRandall Stewart struct socket *so; 1414ceaad40aSRandall Stewart 1415ceaad40aSRandall Stewart #endif 1416d61374e1SRandall Stewart int did_output, type; 1417f8829a4aSRandall Stewart 1418f8829a4aSRandall Stewart tmr = (struct sctp_timer *)t; 1419f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)tmr->ep; 1420f8829a4aSRandall Stewart stcb = (struct sctp_tcb *)tmr->tcb; 1421f8829a4aSRandall Stewart net = (struct sctp_nets *)tmr->net; 14228518270eSMichael Tuexen CURVNET_SET((struct vnet *)tmr->vnet); 1423f8829a4aSRandall Stewart did_output = 1; 1424f8829a4aSRandall Stewart 1425f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1426f8829a4aSRandall Stewart sctp_audit_log(0xF0, (uint8_t) tmr->type); 1427f8829a4aSRandall Stewart sctp_auditing(3, inp, stcb, net); 1428f8829a4aSRandall Stewart #endif 1429f8829a4aSRandall Stewart 1430f8829a4aSRandall Stewart /* sanity checks... */ 1431f8829a4aSRandall Stewart if (tmr->self != (void *)tmr) { 1432f8829a4aSRandall Stewart /* 1433ad81507eSRandall Stewart * SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n", 1434dd294dceSMichael Tuexen * (void *)tmr); 1435f8829a4aSRandall Stewart */ 14368518270eSMichael Tuexen CURVNET_RESTORE(); 1437f8829a4aSRandall Stewart return; 1438f8829a4aSRandall Stewart } 1439a5d547adSRandall Stewart tmr->stopped_from = 0xa001; 1440f8829a4aSRandall Stewart if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) { 1441f8829a4aSRandall Stewart /* 1442ad81507eSRandall Stewart * SCTP_PRINTF("SCTP timer fired with invalid type: 0x%x\n", 1443f8829a4aSRandall Stewart * tmr->type); 1444f8829a4aSRandall Stewart */ 14458518270eSMichael Tuexen CURVNET_RESTORE(); 1446f8829a4aSRandall Stewart return; 1447f8829a4aSRandall Stewart } 1448a5d547adSRandall Stewart tmr->stopped_from = 0xa002; 1449f8829a4aSRandall Stewart if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) { 14508518270eSMichael Tuexen CURVNET_RESTORE(); 1451f8829a4aSRandall Stewart return; 1452f8829a4aSRandall Stewart } 1453f8829a4aSRandall Stewart /* if this is an iterator timeout, get the struct and clear inp */ 1454a5d547adSRandall Stewart tmr->stopped_from = 0xa003; 1455d61374e1SRandall Stewart type = tmr->type; 1456f8829a4aSRandall Stewart if (inp) { 1457f8829a4aSRandall Stewart SCTP_INP_INCR_REF(inp); 1458aa1808b7SMichael Tuexen if ((inp->sctp_socket == NULL) && 1459f8829a4aSRandall Stewart ((tmr->type != SCTP_TIMER_TYPE_INPKILL) && 1460810ec536SMichael Tuexen (tmr->type != SCTP_TIMER_TYPE_INIT) && 1461a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SEND) && 1462a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_RECV) && 1463a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) && 1464f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) && 1465f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) && 1466f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) && 1467f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_ASOCKILL)) 1468f8829a4aSRandall Stewart ) { 1469f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 14708518270eSMichael Tuexen CURVNET_RESTORE(); 1471f8829a4aSRandall Stewart return; 1472f8829a4aSRandall Stewart } 1473f8829a4aSRandall Stewart } 1474a5d547adSRandall Stewart tmr->stopped_from = 0xa004; 1475f8829a4aSRandall Stewart if (stcb) { 1476c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1477f8829a4aSRandall Stewart if (stcb->asoc.state == 0) { 1478c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1479f8829a4aSRandall Stewart if (inp) { 1480f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1481f8829a4aSRandall Stewart } 14828518270eSMichael Tuexen CURVNET_RESTORE(); 1483f8829a4aSRandall Stewart return; 1484f8829a4aSRandall Stewart } 1485f8829a4aSRandall Stewart } 1486a5d547adSRandall Stewart tmr->stopped_from = 0xa005; 1487ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", tmr->type); 1488139bc87fSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 1489f8829a4aSRandall Stewart if (inp) { 1490f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1491f8829a4aSRandall Stewart } 1492207304d4SRandall Stewart if (stcb) { 1493207304d4SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1494207304d4SRandall Stewart } 14958518270eSMichael Tuexen CURVNET_RESTORE(); 1496f8829a4aSRandall Stewart return; 1497f8829a4aSRandall Stewart } 1498a5d547adSRandall Stewart tmr->stopped_from = 0xa006; 1499a5d547adSRandall Stewart 1500f8829a4aSRandall Stewart if (stcb) { 1501f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 150250cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1503b54d3a6cSRandall Stewart if ((tmr->type != SCTP_TIMER_TYPE_ASOCKILL) && 1504b54d3a6cSRandall Stewart ((stcb->asoc.state == 0) || 1505b54d3a6cSRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { 1506b54d3a6cSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1507b54d3a6cSRandall Stewart if (inp) { 1508b54d3a6cSRandall Stewart SCTP_INP_DECR_REF(inp); 1509b54d3a6cSRandall Stewart } 15108518270eSMichael Tuexen CURVNET_RESTORE(); 1511b54d3a6cSRandall Stewart return; 1512b54d3a6cSRandall Stewart } 1513f8829a4aSRandall Stewart } 151444b7479bSRandall Stewart /* record in stopped what t-o occured */ 151544b7479bSRandall Stewart tmr->stopped_from = tmr->type; 151644b7479bSRandall Stewart 1517f8829a4aSRandall Stewart /* mark as being serviced now */ 151844b7479bSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 151944b7479bSRandall Stewart /* 152044b7479bSRandall Stewart * Callout has been rescheduled. 152144b7479bSRandall Stewart */ 152244b7479bSRandall Stewart goto get_out; 152344b7479bSRandall Stewart } 152444b7479bSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 152544b7479bSRandall Stewart /* 152644b7479bSRandall Stewart * Not active, so no action. 152744b7479bSRandall Stewart */ 152844b7479bSRandall Stewart goto get_out; 152944b7479bSRandall Stewart } 1530139bc87fSRandall Stewart SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); 1531f8829a4aSRandall Stewart 1532f8829a4aSRandall Stewart /* call the handler for the appropriate timer type */ 1533f8829a4aSRandall Stewart switch (tmr->type) { 1534d61a0ae0SRandall Stewart case SCTP_TIMER_TYPE_ZERO_COPY: 1535eacc51c5SRandall Stewart if (inp == NULL) { 1536eacc51c5SRandall Stewart break; 1537eacc51c5SRandall Stewart } 1538d61a0ae0SRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 1539d61a0ae0SRandall Stewart SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); 1540d61a0ae0SRandall Stewart } 1541d61a0ae0SRandall Stewart break; 1542ad21a364SRandall Stewart case SCTP_TIMER_TYPE_ZCOPY_SENDQ: 1543eacc51c5SRandall Stewart if (inp == NULL) { 1544eacc51c5SRandall Stewart break; 1545eacc51c5SRandall Stewart } 1546ad21a364SRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 1547ad21a364SRandall Stewart SCTP_ZERO_COPY_SENDQ_EVENT(inp, inp->sctp_socket); 1548ad21a364SRandall Stewart } 1549ad21a364SRandall Stewart break; 1550f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 1551f8829a4aSRandall Stewart sctp_handle_addr_wq(); 1552f8829a4aSRandall Stewart break; 1553f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 1554ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1555ad81507eSRandall Stewart break; 1556ad81507eSRandall Stewart } 1557f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timodata); 1558f42a358aSRandall Stewart stcb->asoc.timodata++; 1559f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 1560f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 1561f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 1562f8829a4aSRandall Stewart } 1563b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 156460990c0cSMichael Tuexen if (sctp_t3rxt_timer(inp, stcb, net)) { 1565f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1566f8829a4aSRandall Stewart 1567f8829a4aSRandall Stewart goto out_decr; 1568f8829a4aSRandall Stewart } 1569b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1570f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1571f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1572f8829a4aSRandall Stewart #endif 1573ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1574f8829a4aSRandall Stewart if ((stcb->asoc.num_send_timers_up == 0) && 15754a9ef3f8SMichael Tuexen (stcb->asoc.sent_queue_cnt > 0)) { 1576f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 1577f8829a4aSRandall Stewart 1578f8829a4aSRandall Stewart /* 1579f8829a4aSRandall Stewart * safeguard. If there on some on the sent queue 1580f8829a4aSRandall Stewart * somewhere but no timers running something is 1581f8829a4aSRandall Stewart * wrong... so we start a timer on the first chunk 1582f8829a4aSRandall Stewart * on the send queue on whatever net it is sent to. 1583f8829a4aSRandall Stewart */ 1584f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 1585f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, 1586f8829a4aSRandall Stewart chk->whoTo); 1587f8829a4aSRandall Stewart } 1588f8829a4aSRandall Stewart break; 1589f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 1590ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1591ad81507eSRandall Stewart break; 1592ad81507eSRandall Stewart } 1593f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinit); 1594f42a358aSRandall Stewart stcb->asoc.timoinit++; 1595f8829a4aSRandall Stewart if (sctp_t1init_timer(inp, stcb, net)) { 1596f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1597f8829a4aSRandall Stewart goto out_decr; 1598f8829a4aSRandall Stewart } 1599f8829a4aSRandall Stewart /* We do output but not here */ 1600f8829a4aSRandall Stewart did_output = 0; 1601f8829a4aSRandall Stewart break; 1602f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 1603ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1604ad81507eSRandall Stewart break; 1605ca85e948SMichael Tuexen } 1606f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosack); 1607f42a358aSRandall Stewart stcb->asoc.timosack++; 1608689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); 1609f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1610f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1611f8829a4aSRandall Stewart #endif 1612ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED); 1613f8829a4aSRandall Stewart break; 1614f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 1615ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1616ad81507eSRandall Stewart break; 1617ad81507eSRandall Stewart } 1618f8829a4aSRandall Stewart if (sctp_shutdown_timer(inp, stcb, net)) { 1619f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1620f8829a4aSRandall Stewart goto out_decr; 1621f8829a4aSRandall Stewart } 1622f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdown); 1623f42a358aSRandall Stewart stcb->asoc.timoshutdown++; 1624f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1625f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1626f8829a4aSRandall Stewart #endif 1627ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); 1628f8829a4aSRandall Stewart break; 1629f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 1630ca85e948SMichael Tuexen if ((stcb == NULL) || (inp == NULL) || (net == NULL)) { 1631ad81507eSRandall Stewart break; 1632ad81507eSRandall Stewart } 1633f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoheartbeat); 1634f42a358aSRandall Stewart stcb->asoc.timoheartbeat++; 1635ca85e948SMichael Tuexen if (sctp_heartbeat_timer(inp, stcb, net)) { 1636f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1637f8829a4aSRandall Stewart goto out_decr; 1638f8829a4aSRandall Stewart } 1639f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1640ca85e948SMichael Tuexen sctp_auditing(4, inp, stcb, net); 1641f8829a4aSRandall Stewart #endif 1642ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 1643629749b6SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 1644ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); 1645f8829a4aSRandall Stewart } 1646f8829a4aSRandall Stewart break; 1647f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 1648ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1649ad81507eSRandall Stewart break; 1650ad81507eSRandall Stewart } 1651f8829a4aSRandall Stewart if (sctp_cookie_timer(inp, stcb, net)) { 1652f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1653f8829a4aSRandall Stewart goto out_decr; 1654f8829a4aSRandall Stewart } 1655f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timocookie); 1656f42a358aSRandall Stewart stcb->asoc.timocookie++; 1657f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1658f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1659f8829a4aSRandall Stewart #endif 1660f8829a4aSRandall Stewart /* 1661f8829a4aSRandall Stewart * We consider T3 and Cookie timer pretty much the same with 1662f8829a4aSRandall Stewart * respect to where from in chunk_output. 1663f8829a4aSRandall Stewart */ 1664ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1665f8829a4aSRandall Stewart break; 1666f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 1667f8829a4aSRandall Stewart { 1668f8829a4aSRandall Stewart struct timeval tv; 1669f8829a4aSRandall Stewart int i, secret; 1670f8829a4aSRandall Stewart 1671ad81507eSRandall Stewart if (inp == NULL) { 1672ad81507eSRandall Stewart break; 1673ad81507eSRandall Stewart } 1674f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosecret); 16756e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tv); 1676f8829a4aSRandall Stewart SCTP_INP_WLOCK(inp); 1677f8829a4aSRandall Stewart inp->sctp_ep.time_of_secret_change = tv.tv_sec; 1678f8829a4aSRandall Stewart inp->sctp_ep.last_secret_number = 1679f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number; 1680f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number++; 1681f8829a4aSRandall Stewart if (inp->sctp_ep.current_secret_number >= 1682f8829a4aSRandall Stewart SCTP_HOW_MANY_SECRETS) { 1683f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number = 0; 1684f8829a4aSRandall Stewart } 1685f8829a4aSRandall Stewart secret = (int)inp->sctp_ep.current_secret_number; 1686f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) { 1687f8829a4aSRandall Stewart inp->sctp_ep.secret_key[secret][i] = 1688f8829a4aSRandall Stewart sctp_select_initial_TSN(&inp->sctp_ep); 1689f8829a4aSRandall Stewart } 1690f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(inp); 1691f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net); 1692f8829a4aSRandall Stewart } 1693f8829a4aSRandall Stewart did_output = 0; 1694f8829a4aSRandall Stewart break; 1695f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 1696ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1697ad81507eSRandall Stewart break; 1698ad81507eSRandall Stewart } 1699f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timopathmtu); 1700f8829a4aSRandall Stewart sctp_pathmtu_timer(inp, stcb, net); 1701f8829a4aSRandall Stewart did_output = 0; 1702f8829a4aSRandall Stewart break; 1703f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 1704ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1705ad81507eSRandall Stewart break; 1706ad81507eSRandall Stewart } 1707f8829a4aSRandall Stewart if (sctp_shutdownack_timer(inp, stcb, net)) { 1708f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1709f8829a4aSRandall Stewart goto out_decr; 1710f8829a4aSRandall Stewart } 1711f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownack); 1712f42a358aSRandall Stewart stcb->asoc.timoshutdownack++; 1713f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1714f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1715f8829a4aSRandall Stewart #endif 1716ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED); 1717f8829a4aSRandall Stewart break; 1718f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 1719ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1720ad81507eSRandall Stewart break; 1721ad81507eSRandall Stewart } 1722f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownguard); 1723a2b42326SMichael Tuexen sctp_abort_an_association(inp, stcb, NULL, SCTP_SO_NOT_LOCKED); 1724f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1725f8829a4aSRandall Stewart goto out_decr; 1726f8829a4aSRandall Stewart 1727f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 1728ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1729ad81507eSRandall Stewart break; 1730ad81507eSRandall Stewart } 1731f8829a4aSRandall Stewart if (sctp_strreset_timer(inp, stcb, net)) { 1732f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1733f8829a4aSRandall Stewart goto out_decr; 1734f8829a4aSRandall Stewart } 1735f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timostrmrst); 1736ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); 1737f8829a4aSRandall Stewart break; 1738f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 1739ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1740ad81507eSRandall Stewart break; 1741ad81507eSRandall Stewart } 1742f8829a4aSRandall Stewart if (sctp_asconf_timer(inp, stcb, net)) { 1743f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1744f8829a4aSRandall Stewart goto out_decr; 1745f8829a4aSRandall Stewart } 1746f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoasconf); 1747f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1748f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1749f8829a4aSRandall Stewart #endif 1750ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); 1751f8829a4aSRandall Stewart break; 1752851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 1753851b7298SRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1754851b7298SRandall Stewart break; 1755851b7298SRandall Stewart } 175604ee05e8SRandall Stewart sctp_delete_prim_timer(inp, stcb, net); 1757851b7298SRandall Stewart SCTP_STAT_INCR(sctps_timodelprim); 1758851b7298SRandall Stewart break; 1759f8829a4aSRandall Stewart 1760f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 1761ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1762ad81507eSRandall Stewart break; 1763ad81507eSRandall Stewart } 1764f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoautoclose); 1765f8829a4aSRandall Stewart sctp_autoclose_timer(inp, stcb, net); 1766ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); 1767f8829a4aSRandall Stewart did_output = 0; 1768f8829a4aSRandall Stewart break; 1769f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 1770ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1771ad81507eSRandall Stewart break; 1772ad81507eSRandall Stewart } 1773f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoassockill); 1774f8829a4aSRandall Stewart /* Can we free it yet? */ 1775f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1776a5d547adSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1); 1777ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1778ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 1779ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1780ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1781ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 1782ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 1783ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 1784ceaad40aSRandall Stewart #endif 1785c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2); 1786ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1787ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 1788ceaad40aSRandall Stewart #endif 1789f8829a4aSRandall Stewart /* 1790f8829a4aSRandall Stewart * free asoc, always unlocks (or destroy's) so prevent 1791f8829a4aSRandall Stewart * duplicate unlock or unlock of a free mtx :-0 1792f8829a4aSRandall Stewart */ 1793f8829a4aSRandall Stewart stcb = NULL; 1794f8829a4aSRandall Stewart goto out_no_decr; 1795f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 1796f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinpkill); 1797ad81507eSRandall Stewart if (inp == NULL) { 1798ad81507eSRandall Stewart break; 1799ad81507eSRandall Stewart } 1800f8829a4aSRandall Stewart /* 1801f8829a4aSRandall Stewart * special case, take away our increment since WE are the 1802f8829a4aSRandall Stewart * killer 1803f8829a4aSRandall Stewart */ 1804f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1805a5d547adSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_3); 1806b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 18070c7dc840SRandall Stewart SCTP_CALLED_FROM_INPKILL_TIMER); 1808d61374e1SRandall Stewart inp = NULL; 1809f8829a4aSRandall Stewart goto out_no_decr; 1810f8829a4aSRandall Stewart default: 1811ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n", 1812f8829a4aSRandall Stewart tmr->type); 1813f8829a4aSRandall Stewart break; 181460990c0cSMichael Tuexen } 1815f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1816f8829a4aSRandall Stewart sctp_audit_log(0xF1, (uint8_t) tmr->type); 1817f8829a4aSRandall Stewart if (inp) 1818f8829a4aSRandall Stewart sctp_auditing(5, inp, stcb, net); 1819f8829a4aSRandall Stewart #endif 1820f8829a4aSRandall Stewart if ((did_output) && stcb) { 1821f8829a4aSRandall Stewart /* 1822f8829a4aSRandall Stewart * Now we need to clean up the control chunk chain if an 1823f8829a4aSRandall Stewart * ECNE is on it. It must be marked as UNSENT again so next 1824f8829a4aSRandall Stewart * call will continue to send it until such time that we get 1825f8829a4aSRandall Stewart * a CWR, to remove it. It is, however, less likely that we 1826f8829a4aSRandall Stewart * will find a ecn echo on the chain though. 1827f8829a4aSRandall Stewart */ 1828f8829a4aSRandall Stewart sctp_fix_ecn_echo(&stcb->asoc); 1829f8829a4aSRandall Stewart } 183044b7479bSRandall Stewart get_out: 1831f8829a4aSRandall Stewart if (stcb) { 1832f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1833f8829a4aSRandall Stewart } 1834f8829a4aSRandall Stewart out_decr: 1835f8829a4aSRandall Stewart if (inp) { 1836f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1837f8829a4aSRandall Stewart } 1838f8829a4aSRandall Stewart out_no_decr: 1839ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n", 1840d61374e1SRandall Stewart type); 18418518270eSMichael Tuexen CURVNET_RESTORE(); 1842f8829a4aSRandall Stewart } 1843f8829a4aSRandall Stewart 1844ad81507eSRandall Stewart void 1845f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1846f8829a4aSRandall Stewart struct sctp_nets *net) 1847f8829a4aSRandall Stewart { 1848ca85e948SMichael Tuexen uint32_t to_ticks; 1849f8829a4aSRandall Stewart struct sctp_timer *tmr; 1850f8829a4aSRandall Stewart 1851139bc87fSRandall Stewart if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) 1852ad81507eSRandall Stewart return; 1853f8829a4aSRandall Stewart 1854f8829a4aSRandall Stewart tmr = NULL; 1855f8829a4aSRandall Stewart if (stcb) { 1856f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1857f8829a4aSRandall Stewart } 1858f8829a4aSRandall Stewart switch (t_type) { 1859d61a0ae0SRandall Stewart case SCTP_TIMER_TYPE_ZERO_COPY: 1860d61a0ae0SRandall Stewart tmr = &inp->sctp_ep.zero_copy_timer; 1861d61a0ae0SRandall Stewart to_ticks = SCTP_ZERO_COPY_TICK_DELAY; 1862d61a0ae0SRandall Stewart break; 1863ad21a364SRandall Stewart case SCTP_TIMER_TYPE_ZCOPY_SENDQ: 1864ad21a364SRandall Stewart tmr = &inp->sctp_ep.zero_copy_sendq_timer; 1865ad21a364SRandall Stewart to_ticks = SCTP_ZERO_COPY_SENDQ_TICK_DELAY; 1866ad21a364SRandall Stewart break; 1867f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 1868f8829a4aSRandall Stewart /* Only 1 tick away :-) */ 1869b3f1ea41SRandall Stewart tmr = &SCTP_BASE_INFO(addr_wq_timer); 187042551e99SRandall Stewart to_ticks = SCTP_ADDRESS_TICK_DELAY; 1871f8829a4aSRandall Stewart break; 1872f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 1873f8829a4aSRandall Stewart /* Here we use the RTO timer */ 1874f8829a4aSRandall Stewart { 1875f8829a4aSRandall Stewart int rto_val; 1876f8829a4aSRandall Stewart 1877f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1878ad81507eSRandall Stewart return; 1879f8829a4aSRandall Stewart } 1880f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1881f8829a4aSRandall Stewart if (net->RTO == 0) { 1882f8829a4aSRandall Stewart rto_val = stcb->asoc.initial_rto; 1883f8829a4aSRandall Stewart } else { 1884f8829a4aSRandall Stewart rto_val = net->RTO; 1885f8829a4aSRandall Stewart } 1886f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(rto_val); 1887f8829a4aSRandall Stewart } 1888f8829a4aSRandall Stewart break; 1889f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 1890f8829a4aSRandall Stewart /* 1891f8829a4aSRandall Stewart * Here we use the INIT timer default usually about 1 1892f8829a4aSRandall Stewart * minute. 1893f8829a4aSRandall Stewart */ 1894f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1895ad81507eSRandall Stewart return; 1896f8829a4aSRandall Stewart } 1897f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1898f8829a4aSRandall Stewart if (net->RTO == 0) { 1899f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 1900f8829a4aSRandall Stewart } else { 1901f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 1902f8829a4aSRandall Stewart } 1903f8829a4aSRandall Stewart break; 1904f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 1905f8829a4aSRandall Stewart /* 1906f8829a4aSRandall Stewart * Here we use the Delayed-Ack timer value from the inp 1907f8829a4aSRandall Stewart * ususually about 200ms. 1908f8829a4aSRandall Stewart */ 1909f8829a4aSRandall Stewart if (stcb == NULL) { 1910ad81507eSRandall Stewart return; 1911f8829a4aSRandall Stewart } 1912f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 1913f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack); 1914f8829a4aSRandall Stewart break; 1915f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 1916f8829a4aSRandall Stewart /* Here we use the RTO of the destination. */ 1917f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1918ad81507eSRandall Stewart return; 1919f8829a4aSRandall Stewart } 1920f8829a4aSRandall Stewart if (net->RTO == 0) { 1921f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 1922f8829a4aSRandall Stewart } else { 1923f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 1924f8829a4aSRandall Stewart } 1925f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1926f8829a4aSRandall Stewart break; 1927f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 1928f8829a4aSRandall Stewart /* 1929f8829a4aSRandall Stewart * the net is used here so that we can add in the RTO. Even 1930f8829a4aSRandall Stewart * though we use a different timer. We also add the HB timer 1931f8829a4aSRandall Stewart * PLUS a random jitter. 1932f8829a4aSRandall Stewart */ 1933ca85e948SMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 1934ad81507eSRandall Stewart return; 1935ad81507eSRandall Stewart } else { 1936f8829a4aSRandall Stewart uint32_t rndval; 1937ca85e948SMichael Tuexen uint32_t jitter; 1938f8829a4aSRandall Stewart 1939ca85e948SMichael Tuexen if ((net->dest_state & SCTP_ADDR_NOHB) && 1940ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 1941ad81507eSRandall Stewart return; 1942f8829a4aSRandall Stewart } 1943f8829a4aSRandall Stewart if (net->RTO == 0) { 1944ca85e948SMichael Tuexen to_ticks = stcb->asoc.initial_rto; 1945f8829a4aSRandall Stewart } else { 1946ca85e948SMichael Tuexen to_ticks = net->RTO; 1947f8829a4aSRandall Stewart } 1948ca85e948SMichael Tuexen rndval = sctp_select_initial_TSN(&inp->sctp_ep); 1949ca85e948SMichael Tuexen jitter = rndval % to_ticks; 1950ca85e948SMichael Tuexen if (jitter >= (to_ticks >> 1)) { 1951ca85e948SMichael Tuexen to_ticks = to_ticks + (jitter - (to_ticks >> 1)); 1952f8829a4aSRandall Stewart } else { 1953ca85e948SMichael Tuexen to_ticks = to_ticks - jitter; 1954f8829a4aSRandall Stewart } 1955ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 1956ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_PF)) { 1957ca85e948SMichael Tuexen to_ticks += net->heart_beat_delay; 1958f8829a4aSRandall Stewart } 1959f8829a4aSRandall Stewart /* 1960f8829a4aSRandall Stewart * Now we must convert the to_ticks that are now in 1961f8829a4aSRandall Stewart * ms to ticks. 1962f8829a4aSRandall Stewart */ 1963f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(to_ticks); 1964ca85e948SMichael Tuexen tmr = &net->hb_timer; 1965f8829a4aSRandall Stewart } 1966f8829a4aSRandall Stewart break; 1967f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 1968f8829a4aSRandall Stewart /* 1969f8829a4aSRandall Stewart * Here we can use the RTO timer from the network since one 1970f8829a4aSRandall Stewart * RTT was compelete. If a retran happened then we will be 1971f8829a4aSRandall Stewart * using the RTO initial value. 1972f8829a4aSRandall Stewart */ 1973f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1974ad81507eSRandall Stewart return; 1975f8829a4aSRandall Stewart } 1976f8829a4aSRandall Stewart if (net->RTO == 0) { 1977f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 1978f8829a4aSRandall Stewart } else { 1979f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 1980f8829a4aSRandall Stewart } 1981f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1982f8829a4aSRandall Stewart break; 1983f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 1984f8829a4aSRandall Stewart /* 1985f8829a4aSRandall Stewart * nothing needed but the endpoint here ususually about 60 1986f8829a4aSRandall Stewart * minutes. 1987f8829a4aSRandall Stewart */ 1988ad81507eSRandall Stewart if (inp == NULL) { 1989ad81507eSRandall Stewart return; 1990ad81507eSRandall Stewart } 1991f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 1992f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE]; 1993f8829a4aSRandall Stewart break; 1994f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 1995f8829a4aSRandall Stewart if (stcb == NULL) { 1996ad81507eSRandall Stewart return; 1997f8829a4aSRandall Stewart } 1998f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 1999f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT); 2000f8829a4aSRandall Stewart break; 2001f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 2002f8829a4aSRandall Stewart /* 2003f8829a4aSRandall Stewart * The inp is setup to die. We re-use the signature_chage 2004f8829a4aSRandall Stewart * timer since that has stopped and we are in the GONE 2005f8829a4aSRandall Stewart * state. 2006f8829a4aSRandall Stewart */ 2007ad81507eSRandall Stewart if (inp == NULL) { 2008ad81507eSRandall Stewart return; 2009ad81507eSRandall Stewart } 2010f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2011f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT); 2012f8829a4aSRandall Stewart break; 2013f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2014f8829a4aSRandall Stewart /* 2015f8829a4aSRandall Stewart * Here we use the value found in the EP for PMTU ususually 2016f8829a4aSRandall Stewart * about 10 minutes. 2017f8829a4aSRandall Stewart */ 2018ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 2019ad81507eSRandall Stewart return; 2020f8829a4aSRandall Stewart } 2021f8829a4aSRandall Stewart if (net == NULL) { 2022ad81507eSRandall Stewart return; 2023f8829a4aSRandall Stewart } 202480c79bbeSMichael Tuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 202580c79bbeSMichael Tuexen return; 202680c79bbeSMichael Tuexen } 2027f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU]; 2028f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2029f8829a4aSRandall Stewart break; 2030f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2031f8829a4aSRandall Stewart /* Here we use the RTO of the destination */ 2032f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2033ad81507eSRandall Stewart return; 2034f8829a4aSRandall Stewart } 2035f8829a4aSRandall Stewart if (net->RTO == 0) { 2036f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2037f8829a4aSRandall Stewart } else { 2038f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2039f8829a4aSRandall Stewart } 2040f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2041f8829a4aSRandall Stewart break; 2042f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2043f8829a4aSRandall Stewart /* 2044f8829a4aSRandall Stewart * Here we use the endpoints shutdown guard timer usually 2045f8829a4aSRandall Stewart * about 3 minutes. 2046f8829a4aSRandall Stewart */ 2047ad81507eSRandall Stewart if ((inp == NULL) || (stcb == NULL)) { 2048ad81507eSRandall Stewart return; 2049f8829a4aSRandall Stewart } 2050f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN]; 2051f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2052f8829a4aSRandall Stewart break; 2053f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2054f8829a4aSRandall Stewart /* 20551b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 20561b649582SRandall Stewart * the net's RTO. 2057f8829a4aSRandall Stewart */ 2058f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2059ad81507eSRandall Stewart return; 2060f8829a4aSRandall Stewart } 2061f8829a4aSRandall Stewart if (net->RTO == 0) { 2062f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2063f8829a4aSRandall Stewart } else { 2064f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2065f8829a4aSRandall Stewart } 2066f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2067f8829a4aSRandall Stewart break; 2068f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 2069f8829a4aSRandall Stewart /* 20701b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 20711b649582SRandall Stewart * the net's RTO. 2072f8829a4aSRandall Stewart */ 2073f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2074ad81507eSRandall Stewart return; 2075f8829a4aSRandall Stewart } 2076f8829a4aSRandall Stewart if (net->RTO == 0) { 2077f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2078f8829a4aSRandall Stewart } else { 2079f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2080f8829a4aSRandall Stewart } 2081f8829a4aSRandall Stewart tmr = &stcb->asoc.asconf_timer; 2082f8829a4aSRandall Stewart break; 2083851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2084851b7298SRandall Stewart if ((stcb == NULL) || (net != NULL)) { 2085851b7298SRandall Stewart return; 2086851b7298SRandall Stewart } 2087851b7298SRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2088851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2089851b7298SRandall Stewart break; 2090f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 2091f8829a4aSRandall Stewart if (stcb == NULL) { 2092ad81507eSRandall Stewart return; 2093f8829a4aSRandall Stewart } 2094f8829a4aSRandall Stewart if (stcb->asoc.sctp_autoclose_ticks == 0) { 2095f8829a4aSRandall Stewart /* 2096f8829a4aSRandall Stewart * Really an error since stcb is NOT set to 2097f8829a4aSRandall Stewart * autoclose 2098f8829a4aSRandall Stewart */ 2099ad81507eSRandall Stewart return; 2100f8829a4aSRandall Stewart } 2101f8829a4aSRandall Stewart to_ticks = stcb->asoc.sctp_autoclose_ticks; 2102f8829a4aSRandall Stewart tmr = &stcb->asoc.autoclose_timer; 2103f8829a4aSRandall Stewart break; 2104f8829a4aSRandall Stewart default: 2105ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n", 2106ad81507eSRandall Stewart __FUNCTION__, t_type); 2107ad81507eSRandall Stewart return; 2108f8829a4aSRandall Stewart break; 210960990c0cSMichael Tuexen } 2110f8829a4aSRandall Stewart if ((to_ticks <= 0) || (tmr == NULL)) { 2111ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n", 2112dd294dceSMichael Tuexen __FUNCTION__, t_type, to_ticks, (void *)tmr); 2113ad81507eSRandall Stewart return; 2114f8829a4aSRandall Stewart } 2115139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 2116f8829a4aSRandall Stewart /* 2117f8829a4aSRandall Stewart * we do NOT allow you to have it already running. if it is 2118f8829a4aSRandall Stewart * we leave the current one up unchanged 2119f8829a4aSRandall Stewart */ 2120ad81507eSRandall Stewart return; 2121f8829a4aSRandall Stewart } 2122f8829a4aSRandall Stewart /* At this point we can proceed */ 2123f8829a4aSRandall Stewart if (t_type == SCTP_TIMER_TYPE_SEND) { 2124f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up++; 2125f8829a4aSRandall Stewart } 2126a5d547adSRandall Stewart tmr->stopped_from = 0; 2127f8829a4aSRandall Stewart tmr->type = t_type; 2128f8829a4aSRandall Stewart tmr->ep = (void *)inp; 2129f8829a4aSRandall Stewart tmr->tcb = (void *)stcb; 2130f8829a4aSRandall Stewart tmr->net = (void *)net; 2131f8829a4aSRandall Stewart tmr->self = (void *)tmr; 21328518270eSMichael Tuexen tmr->vnet = (void *)curvnet; 2133c4739e2fSRandall Stewart tmr->ticks = sctp_get_tick_count(); 2134ad81507eSRandall Stewart (void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr); 2135ad81507eSRandall Stewart return; 2136f8829a4aSRandall Stewart } 2137f8829a4aSRandall Stewart 21386e55db54SRandall Stewart void 2139f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2140a5d547adSRandall Stewart struct sctp_nets *net, uint32_t from) 2141f8829a4aSRandall Stewart { 2142f8829a4aSRandall Stewart struct sctp_timer *tmr; 2143f8829a4aSRandall Stewart 2144f8829a4aSRandall Stewart if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && 2145f8829a4aSRandall Stewart (inp == NULL)) 21466e55db54SRandall Stewart return; 2147f8829a4aSRandall Stewart 2148f8829a4aSRandall Stewart tmr = NULL; 2149f8829a4aSRandall Stewart if (stcb) { 2150f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2151f8829a4aSRandall Stewart } 2152f8829a4aSRandall Stewart switch (t_type) { 2153d61a0ae0SRandall Stewart case SCTP_TIMER_TYPE_ZERO_COPY: 2154d61a0ae0SRandall Stewart tmr = &inp->sctp_ep.zero_copy_timer; 2155d61a0ae0SRandall Stewart break; 2156ad21a364SRandall Stewart case SCTP_TIMER_TYPE_ZCOPY_SENDQ: 2157ad21a364SRandall Stewart tmr = &inp->sctp_ep.zero_copy_sendq_timer; 2158ad21a364SRandall Stewart break; 2159f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 2160b3f1ea41SRandall Stewart tmr = &SCTP_BASE_INFO(addr_wq_timer); 2161f8829a4aSRandall Stewart break; 2162f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2163f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21646e55db54SRandall Stewart return; 2165f8829a4aSRandall Stewart } 2166f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2167f8829a4aSRandall Stewart break; 2168f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2169f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21706e55db54SRandall Stewart return; 2171f8829a4aSRandall Stewart } 2172f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2173f8829a4aSRandall Stewart break; 2174f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2175f8829a4aSRandall Stewart if (stcb == NULL) { 21766e55db54SRandall Stewart return; 2177f8829a4aSRandall Stewart } 2178f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2179f8829a4aSRandall Stewart break; 2180f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2181f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21826e55db54SRandall Stewart return; 2183f8829a4aSRandall Stewart } 2184f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2185f8829a4aSRandall Stewart break; 2186f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2187ca85e948SMichael Tuexen if ((stcb == NULL) || (net == NULL)) { 21886e55db54SRandall Stewart return; 2189f8829a4aSRandall Stewart } 2190ca85e948SMichael Tuexen tmr = &net->hb_timer; 2191f8829a4aSRandall Stewart break; 2192f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2193f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21946e55db54SRandall Stewart return; 2195f8829a4aSRandall Stewart } 2196f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2197f8829a4aSRandall Stewart break; 2198f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2199f8829a4aSRandall Stewart /* nothing needed but the endpoint here */ 2200f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2201f8829a4aSRandall Stewart /* 2202f8829a4aSRandall Stewart * We re-use the newcookie timer for the INP kill timer. We 2203f8829a4aSRandall Stewart * must assure that we do not kill it by accident. 2204f8829a4aSRandall Stewart */ 2205f8829a4aSRandall Stewart break; 2206f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 2207f8829a4aSRandall Stewart /* 2208f8829a4aSRandall Stewart * Stop the asoc kill timer. 2209f8829a4aSRandall Stewart */ 2210f8829a4aSRandall Stewart if (stcb == NULL) { 22116e55db54SRandall Stewart return; 2212f8829a4aSRandall Stewart } 2213f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2214f8829a4aSRandall Stewart break; 2215f8829a4aSRandall Stewart 2216f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 2217f8829a4aSRandall Stewart /* 2218f8829a4aSRandall Stewart * The inp is setup to die. We re-use the signature_chage 2219f8829a4aSRandall Stewart * timer since that has stopped and we are in the GONE 2220f8829a4aSRandall Stewart * state. 2221f8829a4aSRandall Stewart */ 2222f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2223f8829a4aSRandall Stewart break; 2224f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2225f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22266e55db54SRandall Stewart return; 2227f8829a4aSRandall Stewart } 2228f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2229f8829a4aSRandall Stewart break; 2230f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2231f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22326e55db54SRandall Stewart return; 2233f8829a4aSRandall Stewart } 2234f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2235f8829a4aSRandall Stewart break; 2236f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2237f8829a4aSRandall Stewart if (stcb == NULL) { 22386e55db54SRandall Stewart return; 2239f8829a4aSRandall Stewart } 2240f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2241f8829a4aSRandall Stewart break; 2242f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2243f8829a4aSRandall Stewart if (stcb == NULL) { 22446e55db54SRandall Stewart return; 2245f8829a4aSRandall Stewart } 2246f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2247f8829a4aSRandall Stewart break; 2248f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 2249f8829a4aSRandall Stewart if (stcb == NULL) { 22506e55db54SRandall Stewart return; 2251f8829a4aSRandall Stewart } 2252f8829a4aSRandall Stewart tmr = &stcb->asoc.asconf_timer; 2253f8829a4aSRandall Stewart break; 2254851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2255851b7298SRandall Stewart if (stcb == NULL) { 2256851b7298SRandall Stewart return; 2257851b7298SRandall Stewart } 2258851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2259851b7298SRandall Stewart break; 2260f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 2261f8829a4aSRandall Stewart if (stcb == NULL) { 22626e55db54SRandall Stewart return; 2263f8829a4aSRandall Stewart } 2264f8829a4aSRandall Stewart tmr = &stcb->asoc.autoclose_timer; 2265f8829a4aSRandall Stewart break; 2266f8829a4aSRandall Stewart default: 2267ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n", 2268ad81507eSRandall Stewart __FUNCTION__, t_type); 2269f8829a4aSRandall Stewart break; 227060990c0cSMichael Tuexen } 2271f8829a4aSRandall Stewart if (tmr == NULL) { 22726e55db54SRandall Stewart return; 2273f8829a4aSRandall Stewart } 2274f8829a4aSRandall Stewart if ((tmr->type != t_type) && tmr->type) { 2275f8829a4aSRandall Stewart /* 2276f8829a4aSRandall Stewart * Ok we have a timer that is under joint use. Cookie timer 2277f8829a4aSRandall Stewart * per chance with the SEND timer. We therefore are NOT 2278f8829a4aSRandall Stewart * running the timer that the caller wants stopped. So just 2279f8829a4aSRandall Stewart * return. 2280f8829a4aSRandall Stewart */ 22816e55db54SRandall Stewart return; 2282f8829a4aSRandall Stewart } 2283ad81507eSRandall Stewart if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) { 2284f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 2285f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 2286f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 2287f8829a4aSRandall Stewart } 2288f8829a4aSRandall Stewart } 2289f8829a4aSRandall Stewart tmr->self = NULL; 2290a5d547adSRandall Stewart tmr->stopped_from = from; 22916e55db54SRandall Stewart (void)SCTP_OS_TIMER_STOP(&tmr->timer); 22926e55db54SRandall Stewart return; 2293f8829a4aSRandall Stewart } 2294f8829a4aSRandall Stewart 2295f8829a4aSRandall Stewart uint32_t 2296f8829a4aSRandall Stewart sctp_calculate_len(struct mbuf *m) 2297f8829a4aSRandall Stewart { 2298f8829a4aSRandall Stewart uint32_t tlen = 0; 2299f8829a4aSRandall Stewart struct mbuf *at; 2300f8829a4aSRandall Stewart 2301f8829a4aSRandall Stewart at = m; 2302f8829a4aSRandall Stewart while (at) { 2303139bc87fSRandall Stewart tlen += SCTP_BUF_LEN(at); 2304139bc87fSRandall Stewart at = SCTP_BUF_NEXT(at); 2305f8829a4aSRandall Stewart } 2306f8829a4aSRandall Stewart return (tlen); 2307f8829a4aSRandall Stewart } 2308f8829a4aSRandall Stewart 2309f8829a4aSRandall Stewart void 2310f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp, 231144b7479bSRandall Stewart struct sctp_association *asoc, uint32_t mtu) 2312f8829a4aSRandall Stewart { 2313f8829a4aSRandall Stewart /* 2314f8829a4aSRandall Stewart * Reset the P-MTU size on this association, this involves changing 2315f8829a4aSRandall Stewart * the asoc MTU, going through ANY chunk+overhead larger than mtu to 2316f8829a4aSRandall Stewart * allow the DF flag to be cleared. 2317f8829a4aSRandall Stewart */ 2318f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 2319f8829a4aSRandall Stewart unsigned int eff_mtu, ovh; 2320f8829a4aSRandall Stewart 2321f8829a4aSRandall Stewart asoc->smallest_mtu = mtu; 2322f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2323f8829a4aSRandall Stewart ovh = SCTP_MIN_OVERHEAD; 2324f8829a4aSRandall Stewart } else { 2325f8829a4aSRandall Stewart ovh = SCTP_MIN_V4_OVERHEAD; 2326f8829a4aSRandall Stewart } 2327f8829a4aSRandall Stewart eff_mtu = mtu - ovh; 2328f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 2329f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2330f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2331f8829a4aSRandall Stewart } 2332f8829a4aSRandall Stewart } 2333f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 2334f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2335f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2336f8829a4aSRandall Stewart } 2337f8829a4aSRandall Stewart } 2338f8829a4aSRandall Stewart } 2339f8829a4aSRandall Stewart 2340f8829a4aSRandall Stewart 2341f8829a4aSRandall Stewart /* 2342f8829a4aSRandall Stewart * given an association and starting time of the current RTT period return 2343f42a358aSRandall Stewart * RTO in number of msecs net should point to the current network 2344f8829a4aSRandall Stewart */ 2345899288aeSRandall Stewart 2346f8829a4aSRandall Stewart uint32_t 2347f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb, 2348f8829a4aSRandall Stewart struct sctp_association *asoc, 2349f8829a4aSRandall Stewart struct sctp_nets *net, 235018e198d3SRandall Stewart struct timeval *told, 2351f79aab18SRandall Stewart int safe, int rtt_from_sack) 2352f8829a4aSRandall Stewart { 235318e198d3SRandall Stewart /*- 2354f8829a4aSRandall Stewart * given an association and the starting time of the current RTT 2355f42a358aSRandall Stewart * period (in value1/value2) return RTO in number of msecs. 2356f8829a4aSRandall Stewart */ 2357be1d9176SMichael Tuexen int32_t rtt; /* RTT in ms */ 2358be1d9176SMichael Tuexen uint32_t new_rto; 2359f8829a4aSRandall Stewart int first_measure = 0; 236018e198d3SRandall Stewart struct timeval now, then, *old; 2361f8829a4aSRandall Stewart 236218e198d3SRandall Stewart /* Copy it out for sparc64 */ 236318e198d3SRandall Stewart if (safe == sctp_align_unsafe_makecopy) { 236418e198d3SRandall Stewart old = &then; 236518e198d3SRandall Stewart memcpy(&then, told, sizeof(struct timeval)); 236618e198d3SRandall Stewart } else if (safe == sctp_align_safe_nocopy) { 236718e198d3SRandall Stewart old = told; 236818e198d3SRandall Stewart } else { 236918e198d3SRandall Stewart /* error */ 237018e198d3SRandall Stewart SCTP_PRINTF("Huh, bad rto calc call\n"); 237118e198d3SRandall Stewart return (0); 237218e198d3SRandall Stewart } 2373f8829a4aSRandall Stewart /************************/ 2374f8829a4aSRandall Stewart /* 1. calculate new RTT */ 2375f8829a4aSRandall Stewart /************************/ 2376f8829a4aSRandall Stewart /* get the current time */ 2377299108c5SRandall Stewart if (stcb->asoc.use_precise_time) { 2378299108c5SRandall Stewart (void)SCTP_GETPTIME_TIMEVAL(&now); 2379299108c5SRandall Stewart } else { 23806e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 2381299108c5SRandall Stewart } 2382be1d9176SMichael Tuexen timevalsub(&now, old); 2383be1d9176SMichael Tuexen /* store the current RTT in us */ 238481eb4e63SMichael Tuexen net->rtt = (uint64_t) 1000000 *(uint64_t) now.tv_sec + 2385be1d9176SMichael Tuexen (uint64_t) now.tv_usec; 2386be1d9176SMichael Tuexen 2387be1d9176SMichael Tuexen /* computer rtt in ms */ 2388be1d9176SMichael Tuexen rtt = net->rtt / 1000; 2389f79aab18SRandall Stewart if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) { 2390f79aab18SRandall Stewart /* 2391f79aab18SRandall Stewart * Tell the CC module that a new update has just occurred 2392f79aab18SRandall Stewart * from a sack 2393f79aab18SRandall Stewart */ 2394f79aab18SRandall Stewart (*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now); 2395f79aab18SRandall Stewart } 2396f79aab18SRandall Stewart /* 2397f79aab18SRandall Stewart * Do we need to determine the lan? We do this only on sacks i.e. 2398f79aab18SRandall Stewart * RTT being determined from data not non-data (HB/INIT->INITACK). 2399f79aab18SRandall Stewart */ 2400f79aab18SRandall Stewart if ((rtt_from_sack == SCTP_RTT_FROM_DATA) && 2401be1d9176SMichael Tuexen (net->lan_type == SCTP_LAN_UNKNOWN)) { 2402be1d9176SMichael Tuexen if (net->rtt > SCTP_LOCAL_LAN_RTT) { 2403899288aeSRandall Stewart net->lan_type = SCTP_LAN_INTERNET; 2404899288aeSRandall Stewart } else { 2405899288aeSRandall Stewart net->lan_type = SCTP_LAN_LOCAL; 2406899288aeSRandall Stewart } 2407899288aeSRandall Stewart } 2408f8829a4aSRandall Stewart /***************************/ 2409f8829a4aSRandall Stewart /* 2. update RTTVAR & SRTT */ 2410f8829a4aSRandall Stewart /***************************/ 2411be1d9176SMichael Tuexen /*- 2412be1d9176SMichael Tuexen * Compute the scaled average lastsa and the 2413be1d9176SMichael Tuexen * scaled variance lastsv as described in van Jacobson 2414be1d9176SMichael Tuexen * Paper "Congestion Avoidance and Control", Annex A. 2415be1d9176SMichael Tuexen * 2416be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt 2417be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar 2418be1d9176SMichael Tuexen */ 24199a972525SRandall Stewart if (net->RTO_measured) { 2420be1d9176SMichael Tuexen rtt -= (net->lastsa >> SCTP_RTT_SHIFT); 2421be1d9176SMichael Tuexen net->lastsa += rtt; 2422be1d9176SMichael Tuexen if (rtt < 0) { 2423be1d9176SMichael Tuexen rtt = -rtt; 2424be1d9176SMichael Tuexen } 2425be1d9176SMichael Tuexen rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); 2426be1d9176SMichael Tuexen net->lastsv += rtt; 2427b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2428f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_RTTVAR); 242980fefe0aSRandall Stewart } 2430f8829a4aSRandall Stewart } else { 2431f8829a4aSRandall Stewart /* First RTO measurment */ 24329a972525SRandall Stewart net->RTO_measured = 1; 2433f8829a4aSRandall Stewart first_measure = 1; 2434be1d9176SMichael Tuexen net->lastsa = rtt << SCTP_RTT_SHIFT; 2435be1d9176SMichael Tuexen net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT; 2436b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2437f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_INITIAL_RTT); 243880fefe0aSRandall Stewart } 2439f8829a4aSRandall Stewart } 2440be1d9176SMichael Tuexen if (net->lastsv == 0) { 2441be1d9176SMichael Tuexen net->lastsv = SCTP_CLOCK_GRANULARITY; 2442be1d9176SMichael Tuexen } 2443108df27cSRandall Stewart new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 2444f8829a4aSRandall Stewart if ((new_rto > SCTP_SAT_NETWORK_MIN) && 2445f8829a4aSRandall Stewart (stcb->asoc.sat_network_lockout == 0)) { 2446f8829a4aSRandall Stewart stcb->asoc.sat_network = 1; 2447f8829a4aSRandall Stewart } else if ((!first_measure) && stcb->asoc.sat_network) { 2448f8829a4aSRandall Stewart stcb->asoc.sat_network = 0; 2449f8829a4aSRandall Stewart stcb->asoc.sat_network_lockout = 1; 2450f8829a4aSRandall Stewart } 2451f8829a4aSRandall Stewart /* bound it, per C6/C7 in Section 5.3.1 */ 2452f8829a4aSRandall Stewart if (new_rto < stcb->asoc.minrto) { 2453f8829a4aSRandall Stewart new_rto = stcb->asoc.minrto; 2454f8829a4aSRandall Stewart } 2455f8829a4aSRandall Stewart if (new_rto > stcb->asoc.maxrto) { 2456f8829a4aSRandall Stewart new_rto = stcb->asoc.maxrto; 2457f8829a4aSRandall Stewart } 24585e54f665SRandall Stewart /* we are now returning the RTO */ 24595e54f665SRandall Stewart return (new_rto); 2460f8829a4aSRandall Stewart } 2461f8829a4aSRandall Stewart 2462f8829a4aSRandall Stewart /* 2463f8829a4aSRandall Stewart * return a pointer to a contiguous piece of data from the given mbuf chain 2464f8829a4aSRandall Stewart * starting at 'off' for 'len' bytes. If the desired piece spans more than 2465f8829a4aSRandall Stewart * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size 2466f8829a4aSRandall Stewart * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain. 2467f8829a4aSRandall Stewart */ 246872fb6fdbSRandall Stewart caddr_t 2469f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t * in_ptr) 2470f8829a4aSRandall Stewart { 2471f8829a4aSRandall Stewart uint32_t count; 2472f8829a4aSRandall Stewart uint8_t *ptr; 2473f8829a4aSRandall Stewart 2474f8829a4aSRandall Stewart ptr = in_ptr; 2475f8829a4aSRandall Stewart if ((off < 0) || (len <= 0)) 2476f8829a4aSRandall Stewart return (NULL); 2477f8829a4aSRandall Stewart 2478f8829a4aSRandall Stewart /* find the desired start location */ 2479f8829a4aSRandall Stewart while ((m != NULL) && (off > 0)) { 2480139bc87fSRandall Stewart if (off < SCTP_BUF_LEN(m)) 2481f8829a4aSRandall Stewart break; 2482139bc87fSRandall Stewart off -= SCTP_BUF_LEN(m); 2483139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2484f8829a4aSRandall Stewart } 2485f8829a4aSRandall Stewart if (m == NULL) 2486f8829a4aSRandall Stewart return (NULL); 2487f8829a4aSRandall Stewart 2488f8829a4aSRandall Stewart /* is the current mbuf large enough (eg. contiguous)? */ 2489139bc87fSRandall Stewart if ((SCTP_BUF_LEN(m) - off) >= len) { 2490f8829a4aSRandall Stewart return (mtod(m, caddr_t)+off); 2491f8829a4aSRandall Stewart } else { 2492f8829a4aSRandall Stewart /* else, it spans more than one mbuf, so save a temp copy... */ 2493f8829a4aSRandall Stewart while ((m != NULL) && (len > 0)) { 2494139bc87fSRandall Stewart count = min(SCTP_BUF_LEN(m) - off, len); 2495f8829a4aSRandall Stewart bcopy(mtod(m, caddr_t)+off, ptr, count); 2496f8829a4aSRandall Stewart len -= count; 2497f8829a4aSRandall Stewart ptr += count; 2498f8829a4aSRandall Stewart off = 0; 2499139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2500f8829a4aSRandall Stewart } 2501f8829a4aSRandall Stewart if ((m == NULL) && (len > 0)) 2502f8829a4aSRandall Stewart return (NULL); 2503f8829a4aSRandall Stewart else 2504f8829a4aSRandall Stewart return ((caddr_t)in_ptr); 2505f8829a4aSRandall Stewart } 2506f8829a4aSRandall Stewart } 2507f8829a4aSRandall Stewart 2508f8829a4aSRandall Stewart 250944b7479bSRandall Stewart 2510f8829a4aSRandall Stewart struct sctp_paramhdr * 2511f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m, 2512f8829a4aSRandall Stewart int offset, 2513f8829a4aSRandall Stewart struct sctp_paramhdr *pull, 2514f8829a4aSRandall Stewart int pull_limit) 2515f8829a4aSRandall Stewart { 2516f8829a4aSRandall Stewart /* This just provides a typed signature to Peter's Pull routine */ 2517f8829a4aSRandall Stewart return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit, 2518f8829a4aSRandall Stewart (uint8_t *) pull)); 2519f8829a4aSRandall Stewart } 2520f8829a4aSRandall Stewart 2521f8829a4aSRandall Stewart 2522f8829a4aSRandall Stewart int 2523f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen) 2524f8829a4aSRandall Stewart { 2525f8829a4aSRandall Stewart /* 2526f8829a4aSRandall Stewart * add padlen bytes of 0 filled padding to the end of the mbuf. If 2527f8829a4aSRandall Stewart * padlen is > 3 this routine will fail. 2528f8829a4aSRandall Stewart */ 2529f8829a4aSRandall Stewart uint8_t *dp; 2530f8829a4aSRandall Stewart int i; 2531f8829a4aSRandall Stewart 2532f8829a4aSRandall Stewart if (padlen > 3) { 2533c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 2534f8829a4aSRandall Stewart return (ENOBUFS); 2535f8829a4aSRandall Stewart } 253641eee555SRandall Stewart if (padlen <= M_TRAILINGSPACE(m)) { 2537f8829a4aSRandall Stewart /* 2538f8829a4aSRandall Stewart * The easy way. We hope the majority of the time we hit 2539f8829a4aSRandall Stewart * here :) 2540f8829a4aSRandall Stewart */ 2541139bc87fSRandall Stewart dp = (uint8_t *) (mtod(m, caddr_t)+SCTP_BUF_LEN(m)); 2542139bc87fSRandall Stewart SCTP_BUF_LEN(m) += padlen; 2543f8829a4aSRandall Stewart } else { 2544f8829a4aSRandall Stewart /* Hard way we must grow the mbuf */ 2545f8829a4aSRandall Stewart struct mbuf *tmp; 2546f8829a4aSRandall Stewart 2547f8829a4aSRandall Stewart tmp = sctp_get_mbuf_for_msg(padlen, 0, M_DONTWAIT, 1, MT_DATA); 2548f8829a4aSRandall Stewart if (tmp == NULL) { 2549f8829a4aSRandall Stewart /* Out of space GAK! we are in big trouble. */ 2550953b6058SMichael Tuexen SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 2551953b6058SMichael Tuexen return (ENOBUFS); 2552f8829a4aSRandall Stewart } 2553f8829a4aSRandall Stewart /* setup and insert in middle */ 2554139bc87fSRandall Stewart SCTP_BUF_LEN(tmp) = padlen; 255541eee555SRandall Stewart SCTP_BUF_NEXT(tmp) = NULL; 2556139bc87fSRandall Stewart SCTP_BUF_NEXT(m) = tmp; 2557f8829a4aSRandall Stewart dp = mtod(tmp, uint8_t *); 2558f8829a4aSRandall Stewart } 2559f8829a4aSRandall Stewart /* zero out the pad */ 2560f8829a4aSRandall Stewart for (i = 0; i < padlen; i++) { 2561f8829a4aSRandall Stewart *dp = 0; 2562f8829a4aSRandall Stewart dp++; 2563f8829a4aSRandall Stewart } 2564f8829a4aSRandall Stewart return (0); 2565f8829a4aSRandall Stewart } 2566f8829a4aSRandall Stewart 2567f8829a4aSRandall Stewart int 2568f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) 2569f8829a4aSRandall Stewart { 2570f8829a4aSRandall Stewart /* find the last mbuf in chain and pad it */ 2571f8829a4aSRandall Stewart struct mbuf *m_at; 2572f8829a4aSRandall Stewart 2573f8829a4aSRandall Stewart if (last_mbuf) { 2574f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(last_mbuf, padval)); 2575f8829a4aSRandall Stewart } else { 257617267b32SMichael Tuexen for (m_at = m; m_at; m_at = SCTP_BUF_NEXT(m_at)) { 2577139bc87fSRandall Stewart if (SCTP_BUF_NEXT(m_at) == NULL) { 2578f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(m_at, padval)); 2579f8829a4aSRandall Stewart } 2580f8829a4aSRandall Stewart } 2581f8829a4aSRandall Stewart } 2582c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 2583f8829a4aSRandall Stewart return (EFAULT); 2584f8829a4aSRandall Stewart } 2585f8829a4aSRandall Stewart 2586f8829a4aSRandall Stewart static void 2587c5b5675dSMichael Tuexen sctp_notify_assoc_change(uint16_t state, struct sctp_tcb *stcb, 2588410a3b1eSMichael Tuexen uint16_t error, struct sctp_abort_chunk *abort, uint8_t from_peer, int so_locked 2589ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2590ceaad40aSRandall Stewart SCTP_UNUSED 2591ceaad40aSRandall Stewart #endif 2592ceaad40aSRandall Stewart ) 2593f8829a4aSRandall Stewart { 2594f8829a4aSRandall Stewart struct mbuf *m_notify; 2595f8829a4aSRandall Stewart struct sctp_assoc_change *sac; 2596f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2597a2b42326SMichael Tuexen size_t notif_len, abort_len; 2598e06b67c7SMichael Tuexen unsigned int i; 2599f8829a4aSRandall Stewart 2600ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2601ceaad40aSRandall Stewart struct socket *so; 2602ceaad40aSRandall Stewart 2603ceaad40aSRandall Stewart #endif 2604ceaad40aSRandall Stewart 260558411b08SMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { 2606a2b42326SMichael Tuexen notif_len = sizeof(struct sctp_assoc_change); 2607a2b42326SMichael Tuexen if (abort != NULL) { 2608a2b42326SMichael Tuexen abort_len = htons(abort->ch.chunk_length); 2609a2b42326SMichael Tuexen } else { 2610a2b42326SMichael Tuexen abort_len = 0; 2611c5b5675dSMichael Tuexen } 2612a2b42326SMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 2613a2b42326SMichael Tuexen notif_len += SCTP_ASSOC_SUPPORTS_MAX; 2614a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 2615a2b42326SMichael Tuexen notif_len += abort_len; 2616a2b42326SMichael Tuexen } 2617a2b42326SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA); 2618a2b42326SMichael Tuexen if (m_notify == NULL) { 2619a2b42326SMichael Tuexen /* Retry with smaller value. */ 2620a2b42326SMichael Tuexen notif_len = sizeof(struct sctp_assoc_change); 2621a2b42326SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA); 2622a2b42326SMichael Tuexen if (m_notify == NULL) { 262358411b08SMichael Tuexen goto set_error; 2624a2b42326SMichael Tuexen } 2625a2b42326SMichael Tuexen } 2626a2b42326SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 2627f8829a4aSRandall Stewart sac = mtod(m_notify, struct sctp_assoc_change *); 2628f8829a4aSRandall Stewart sac->sac_type = SCTP_ASSOC_CHANGE; 2629f8829a4aSRandall Stewart sac->sac_flags = 0; 2630f8829a4aSRandall Stewart sac->sac_length = sizeof(struct sctp_assoc_change); 2631c5b5675dSMichael Tuexen sac->sac_state = state; 2632f8829a4aSRandall Stewart sac->sac_error = error; 2633f8829a4aSRandall Stewart /* XXX verify these stream counts */ 2634f8829a4aSRandall Stewart sac->sac_outbound_streams = stcb->asoc.streamoutcnt; 2635f8829a4aSRandall Stewart sac->sac_inbound_streams = stcb->asoc.streamincnt; 2636f8829a4aSRandall Stewart sac->sac_assoc_id = sctp_get_associd(stcb); 2637a2b42326SMichael Tuexen if (notif_len > sizeof(struct sctp_assoc_change)) { 2638c5b5675dSMichael Tuexen if ((state == SCTP_COMM_UP) || (state == SCTP_RESTART)) { 2639e06b67c7SMichael Tuexen i = 0; 2640e06b67c7SMichael Tuexen if (stcb->asoc.peer_supports_prsctp) { 2641e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_PR; 2642e06b67c7SMichael Tuexen } 2643e06b67c7SMichael Tuexen if (stcb->asoc.peer_supports_auth) { 2644e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_AUTH; 2645e06b67c7SMichael Tuexen } 2646e06b67c7SMichael Tuexen if (stcb->asoc.peer_supports_asconf) { 2647e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_ASCONF; 2648e06b67c7SMichael Tuexen } 2649e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_MULTIBUF; 2650e06b67c7SMichael Tuexen if (stcb->asoc.peer_supports_strreset) { 2651e06b67c7SMichael Tuexen sac->sac_info[i++] = SCTP_ASSOC_SUPPORTS_RE_CONFIG; 2652e06b67c7SMichael Tuexen } 2653e06b67c7SMichael Tuexen sac->sac_length += i; 2654a2b42326SMichael Tuexen } else if ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC)) { 2655a2b42326SMichael Tuexen memcpy(sac->sac_info, abort, abort_len); 2656a2b42326SMichael Tuexen sac->sac_length += abort_len; 2657a2b42326SMichael Tuexen } 2658c5b5675dSMichael Tuexen } 2659e06b67c7SMichael Tuexen SCTP_BUF_LEN(m_notify) = sac->sac_length; 2660f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 26617215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2662f8829a4aSRandall Stewart m_notify); 266358411b08SMichael Tuexen if (control != NULL) { 2664139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 2665f8829a4aSRandall Stewart /* not that we need this */ 2666f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2667139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2668f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2669f8829a4aSRandall Stewart control, 2670cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, 2671cfde3ff7SRandall Stewart so_locked); 267258411b08SMichael Tuexen } else { 267358411b08SMichael Tuexen sctp_m_freem(m_notify); 267458411b08SMichael Tuexen } 267558411b08SMichael Tuexen } 267658411b08SMichael Tuexen /* 267758411b08SMichael Tuexen * For 1-to-1 style sockets, we send up and error when an ABORT 267858411b08SMichael Tuexen * comes in. 267958411b08SMichael Tuexen */ 268058411b08SMichael Tuexen set_error: 268158411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 268258411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 268358411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 2684410a3b1eSMichael Tuexen if (from_peer) { 268558411b08SMichael Tuexen if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) { 268658411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); 268758411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNREFUSED; 268858411b08SMichael Tuexen } else { 268958411b08SMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 269058411b08SMichael Tuexen stcb->sctp_socket->so_error = ECONNRESET; 269158411b08SMichael Tuexen } 2692410a3b1eSMichael Tuexen } else { 2693410a3b1eSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNABORTED); 2694410a3b1eSMichael Tuexen stcb->sctp_socket->so_error = ECONNABORTED; 2695410a3b1eSMichael Tuexen } 269658411b08SMichael Tuexen } 269758411b08SMichael Tuexen /* Wake ANY sleepers */ 2698ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2699ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 2700ceaad40aSRandall Stewart if (!so_locked) { 2701ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 2702ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 2703ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 2704ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 2705ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 2706ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 2707ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2708ceaad40aSRandall Stewart return; 2709ceaad40aSRandall Stewart } 2710ceaad40aSRandall Stewart } 2711ceaad40aSRandall Stewart #endif 271258411b08SMichael Tuexen if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 271358411b08SMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 271458411b08SMichael Tuexen ((state == SCTP_COMM_LOST) || (state == SCTP_CANT_STR_ASSOC))) { 271558411b08SMichael Tuexen socantrcvmore(stcb->sctp_socket); 271658411b08SMichael Tuexen } 271758411b08SMichael Tuexen sorwakeup(stcb->sctp_socket); 271858411b08SMichael Tuexen sowwakeup(stcb->sctp_socket); 2719ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2720ceaad40aSRandall Stewart if (!so_locked) { 2721ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2722ceaad40aSRandall Stewart } 2723ceaad40aSRandall Stewart #endif 2724f8829a4aSRandall Stewart } 2725f8829a4aSRandall Stewart 2726f8829a4aSRandall Stewart static void 2727f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, 2728f8829a4aSRandall Stewart struct sockaddr *sa, uint32_t error) 2729f8829a4aSRandall Stewart { 2730f8829a4aSRandall Stewart struct mbuf *m_notify; 2731f8829a4aSRandall Stewart struct sctp_paddr_change *spc; 2732f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2733f8829a4aSRandall Stewart 273460990c0cSMichael Tuexen if ((stcb == NULL) || 273560990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { 2736f8829a4aSRandall Stewart /* event not enabled */ 2737f8829a4aSRandall Stewart return; 2738830d754dSRandall Stewart } 2739139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_DONTWAIT, 1, MT_DATA); 2740f8829a4aSRandall Stewart if (m_notify == NULL) 2741f8829a4aSRandall Stewart return; 2742139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2743f8829a4aSRandall Stewart spc = mtod(m_notify, struct sctp_paddr_change *); 2744f8829a4aSRandall Stewart spc->spc_type = SCTP_PEER_ADDR_CHANGE; 2745f8829a4aSRandall Stewart spc->spc_flags = 0; 2746f8829a4aSRandall Stewart spc->spc_length = sizeof(struct sctp_paddr_change); 27475e2c2d87SRandall Stewart switch (sa->sa_family) { 2748ea5eba11SMichael Tuexen #ifdef INET 27495e2c2d87SRandall Stewart case AF_INET: 2750f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 27515e2c2d87SRandall Stewart break; 2752ea5eba11SMichael Tuexen #endif 27535e2c2d87SRandall Stewart #ifdef INET6 27545e2c2d87SRandall Stewart case AF_INET6: 27555e2c2d87SRandall Stewart { 2756f42a358aSRandall Stewart struct sockaddr_in6 *sin6; 2757f42a358aSRandall Stewart 2758f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6)); 2759f42a358aSRandall Stewart 2760f42a358aSRandall Stewart sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; 2761f42a358aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 276242551e99SRandall Stewart if (sin6->sin6_scope_id == 0) { 276342551e99SRandall Stewart /* recover scope_id for user */ 2764f42a358aSRandall Stewart (void)sa6_recoverscope(sin6); 276542551e99SRandall Stewart } else { 276642551e99SRandall Stewart /* clear embedded scope_id for user */ 276742551e99SRandall Stewart in6_clearscope(&sin6->sin6_addr); 276842551e99SRandall Stewart } 2769f42a358aSRandall Stewart } 27705e2c2d87SRandall Stewart break; 27715e2c2d87SRandall Stewart } 27725e2c2d87SRandall Stewart #endif 27735e2c2d87SRandall Stewart default: 27745e2c2d87SRandall Stewart /* TSNH */ 27755e2c2d87SRandall Stewart break; 2776f8829a4aSRandall Stewart } 2777f8829a4aSRandall Stewart spc->spc_state = state; 2778f8829a4aSRandall Stewart spc->spc_error = error; 2779f8829a4aSRandall Stewart spc->spc_assoc_id = sctp_get_associd(stcb); 2780f8829a4aSRandall Stewart 2781139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change); 2782139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 2783f8829a4aSRandall Stewart 2784f8829a4aSRandall Stewart /* append to socket */ 2785f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 27867215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2787f8829a4aSRandall Stewart m_notify); 2788f8829a4aSRandall Stewart if (control == NULL) { 2789f8829a4aSRandall Stewart /* no memory */ 2790f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2791f8829a4aSRandall Stewart return; 2792f8829a4aSRandall Stewart } 2793139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 2794139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2795f8829a4aSRandall Stewart /* not that we need this */ 2796f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2797f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2798f8829a4aSRandall Stewart control, 2799cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 2800cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 2801cfde3ff7SRandall Stewart SCTP_SO_NOT_LOCKED); 2802f8829a4aSRandall Stewart } 2803f8829a4aSRandall Stewart 2804f8829a4aSRandall Stewart 2805f8829a4aSRandall Stewart static void 28061edc9dbaSMichael Tuexen sctp_notify_send_failed(struct sctp_tcb *stcb, uint8_t sent, uint32_t error, 2807ceaad40aSRandall Stewart struct sctp_tmit_chunk *chk, int so_locked 2808ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2809ceaad40aSRandall Stewart SCTP_UNUSED 2810ceaad40aSRandall Stewart #endif 2811ceaad40aSRandall Stewart ) 2812f8829a4aSRandall Stewart { 2813830d754dSRandall Stewart struct mbuf *m_notify; 2814f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 28159935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 2816f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2817f8829a4aSRandall Stewart int length; 2818f8829a4aSRandall Stewart 281960990c0cSMichael Tuexen if ((stcb == NULL) || 28209935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 28219935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 2822f8829a4aSRandall Stewart /* event not enabled */ 2823f8829a4aSRandall Stewart return; 2824830d754dSRandall Stewart } 28259935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 28269935403aSMichael Tuexen length = sizeof(struct sctp_send_failed_event); 28279935403aSMichael Tuexen } else { 28289935403aSMichael Tuexen length = sizeof(struct sctp_send_failed); 28299935403aSMichael Tuexen } 28309935403aSMichael Tuexen m_notify = sctp_get_mbuf_for_msg(length, 0, M_DONTWAIT, 1, MT_DATA); 2831f8829a4aSRandall Stewart if (m_notify == NULL) 2832f8829a4aSRandall Stewart /* no space left */ 2833f8829a4aSRandall Stewart return; 28349935403aSMichael Tuexen length += chk->send_size; 2835fc14de76SRandall Stewart length -= sizeof(struct sctp_data_chunk); 2836139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 28379935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 28389935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 28399935403aSMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 28401edc9dbaSMichael Tuexen if (sent) { 28419935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_SENT; 28421edc9dbaSMichael Tuexen } else { 28431edc9dbaSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 28441edc9dbaSMichael Tuexen } 28459935403aSMichael Tuexen ssfe->ssfe_length = length; 28469935403aSMichael Tuexen ssfe->ssfe_error = error; 28479935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 28489935403aSMichael Tuexen bzero(&ssfe->ssfe_info, sizeof(ssfe->ssfe_info)); 28499935403aSMichael Tuexen ssfe->ssfe_info.snd_sid = chk->rec.data.stream_number; 28509935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = chk->rec.data.rcv_flags; 28519935403aSMichael Tuexen ssfe->ssfe_info.snd_ppid = chk->rec.data.payloadtype; 28529935403aSMichael Tuexen ssfe->ssfe_info.snd_context = chk->rec.data.context; 28539935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 28549935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 28559935403aSMichael Tuexen SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event); 28569935403aSMichael Tuexen } else { 2857f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 2858f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 28591edc9dbaSMichael Tuexen if (sent) { 2860f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_SENT; 28611edc9dbaSMichael Tuexen } else { 28621edc9dbaSMichael Tuexen ssf->ssf_flags = SCTP_DATA_UNSENT; 28631edc9dbaSMichael Tuexen } 2864f8829a4aSRandall Stewart ssf->ssf_length = length; 2865f8829a4aSRandall Stewart ssf->ssf_error = error; 2866f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 2867d00aff5dSRandall Stewart bzero(&ssf->ssf_info, sizeof(ssf->ssf_info)); 2868f8829a4aSRandall Stewart ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number; 2869f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq; 2870f8829a4aSRandall Stewart ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; 2871f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype; 2872f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = chk->rec.data.context; 2873f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 2874f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 28759935403aSMichael Tuexen SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); 28769935403aSMichael Tuexen } 2877830d754dSRandall Stewart if (chk->data) { 2878830d754dSRandall Stewart /* 2879830d754dSRandall Stewart * trim off the sctp chunk header(it should be there) 2880830d754dSRandall Stewart */ 2881830d754dSRandall Stewart if (chk->send_size >= sizeof(struct sctp_data_chunk)) { 2882830d754dSRandall Stewart m_adj(chk->data, sizeof(struct sctp_data_chunk)); 2883830d754dSRandall Stewart sctp_mbuf_crush(chk->data); 2884830d754dSRandall Stewart chk->send_size -= sizeof(struct sctp_data_chunk); 2885830d754dSRandall Stewart } 2886830d754dSRandall Stewart } 2887810ec536SMichael Tuexen SCTP_BUF_NEXT(m_notify) = chk->data; 2888f8829a4aSRandall Stewart /* Steal off the mbuf */ 2889f8829a4aSRandall Stewart chk->data = NULL; 2890f8829a4aSRandall Stewart /* 2891f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 2892f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 2893f8829a4aSRandall Stewart * non-reader 2894f8829a4aSRandall Stewart */ 2895139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 2896f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2897f8829a4aSRandall Stewart return; 2898f8829a4aSRandall Stewart } 2899f8829a4aSRandall Stewart /* append to socket */ 2900f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 29017215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2902f8829a4aSRandall Stewart m_notify); 2903f8829a4aSRandall Stewart if (control == NULL) { 2904f8829a4aSRandall Stewart /* no memory */ 2905f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2906f8829a4aSRandall Stewart return; 2907f8829a4aSRandall Stewart } 2908139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2909f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2910f8829a4aSRandall Stewart control, 2911cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 2912cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 2913cfde3ff7SRandall Stewart so_locked); 2914f8829a4aSRandall Stewart } 2915f8829a4aSRandall Stewart 2916f8829a4aSRandall Stewart 2917f8829a4aSRandall Stewart static void 2918f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, 2919ceaad40aSRandall Stewart struct sctp_stream_queue_pending *sp, int so_locked 2920ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2921ceaad40aSRandall Stewart SCTP_UNUSED 2922ceaad40aSRandall Stewart #endif 2923ceaad40aSRandall Stewart ) 2924f8829a4aSRandall Stewart { 2925f8829a4aSRandall Stewart struct mbuf *m_notify; 2926f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 29279935403aSMichael Tuexen struct sctp_send_failed_event *ssfe; 2928f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2929f8829a4aSRandall Stewart int length; 2930f8829a4aSRandall Stewart 293160990c0cSMichael Tuexen if ((stcb == NULL) || 29329935403aSMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT) && 29339935403aSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT))) { 2934f8829a4aSRandall Stewart /* event not enabled */ 2935f8829a4aSRandall Stewart return; 2936830d754dSRandall Stewart } 29379935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 29389935403aSMichael Tuexen length = sizeof(struct sctp_send_failed_event); 29399935403aSMichael Tuexen } else { 29409935403aSMichael Tuexen length = sizeof(struct sctp_send_failed); 29419935403aSMichael Tuexen } 29429935403aSMichael Tuexen m_notify = sctp_get_mbuf_for_msg(length, 0, M_DONTWAIT, 1, MT_DATA); 29439935403aSMichael Tuexen if (m_notify == NULL) { 2944f8829a4aSRandall Stewart /* no space left */ 2945f8829a4aSRandall Stewart return; 29469935403aSMichael Tuexen } 29479935403aSMichael Tuexen length += sp->length; 2948139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 29499935403aSMichael Tuexen if (sctp_stcb_is_feature_on(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVNSENDFAILEVNT)) { 29509935403aSMichael Tuexen ssfe = mtod(m_notify, struct sctp_send_failed_event *); 2951ad83c8a5SMichael Tuexen ssfe->ssfe_type = SCTP_SEND_FAILED_EVENT; 29529935403aSMichael Tuexen ssfe->ssfe_flags = SCTP_DATA_UNSENT; 29539935403aSMichael Tuexen ssfe->ssfe_length = length; 29549935403aSMichael Tuexen ssfe->ssfe_error = error; 29559935403aSMichael Tuexen /* not exactly what the user sent in, but should be close :) */ 29569935403aSMichael Tuexen bzero(&ssfe->ssfe_info, sizeof(ssfe->ssfe_info)); 29579935403aSMichael Tuexen ssfe->ssfe_info.snd_sid = sp->stream; 29589935403aSMichael Tuexen if (sp->some_taken) { 29599935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_LAST_FRAG; 29609935403aSMichael Tuexen } else { 29619935403aSMichael Tuexen ssfe->ssfe_info.snd_flags = SCTP_DATA_NOT_FRAG; 29629935403aSMichael Tuexen } 29639935403aSMichael Tuexen ssfe->ssfe_info.snd_ppid = sp->ppid; 29649935403aSMichael Tuexen ssfe->ssfe_info.snd_context = sp->context; 29659935403aSMichael Tuexen ssfe->ssfe_info.snd_assoc_id = sctp_get_associd(stcb); 29669935403aSMichael Tuexen ssfe->ssfe_assoc_id = sctp_get_associd(stcb); 29679935403aSMichael Tuexen SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed_event); 29689935403aSMichael Tuexen } else { 2969f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 2970f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 2971f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_UNSENT; 2972f8829a4aSRandall Stewart ssf->ssf_length = length; 2973f8829a4aSRandall Stewart ssf->ssf_error = error; 2974f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 2975d00aff5dSRandall Stewart bzero(&ssf->ssf_info, sizeof(ssf->ssf_info)); 2976f8829a4aSRandall Stewart ssf->ssf_info.sinfo_stream = sp->stream; 2977f3b05218SMichael Tuexen ssf->ssf_info.sinfo_ssn = 0; 2978fc14de76SRandall Stewart if (sp->some_taken) { 2979fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG; 2980fc14de76SRandall Stewart } else { 2981fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG; 2982fc14de76SRandall Stewart } 2983f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = sp->ppid; 2984f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = sp->context; 2985f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 2986f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 2987139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); 29889935403aSMichael Tuexen } 29899935403aSMichael Tuexen SCTP_BUF_NEXT(m_notify) = sp->data; 2990f8829a4aSRandall Stewart 2991f8829a4aSRandall Stewart /* Steal off the mbuf */ 2992f8829a4aSRandall Stewart sp->data = NULL; 2993f8829a4aSRandall Stewart /* 2994f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 2995f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 2996f8829a4aSRandall Stewart * non-reader 2997f8829a4aSRandall Stewart */ 2998139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 2999f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3000f8829a4aSRandall Stewart return; 3001f8829a4aSRandall Stewart } 3002f8829a4aSRandall Stewart /* append to socket */ 3003f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 30047215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3005f8829a4aSRandall Stewart m_notify); 3006f8829a4aSRandall Stewart if (control == NULL) { 3007f8829a4aSRandall Stewart /* no memory */ 3008f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3009f8829a4aSRandall Stewart return; 3010f8829a4aSRandall Stewart } 3011139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3012f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3013f8829a4aSRandall Stewart control, 3014cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3015f8829a4aSRandall Stewart } 3016f8829a4aSRandall Stewart 3017f8829a4aSRandall Stewart 3018f8829a4aSRandall Stewart 3019f8829a4aSRandall Stewart static void 30207215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb) 3021f8829a4aSRandall Stewart { 3022f8829a4aSRandall Stewart struct mbuf *m_notify; 3023f8829a4aSRandall Stewart struct sctp_adaptation_event *sai; 3024f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3025f8829a4aSRandall Stewart 302660990c0cSMichael Tuexen if ((stcb == NULL) || 302760990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { 3028f8829a4aSRandall Stewart /* event not enabled */ 3029f8829a4aSRandall Stewart return; 3030830d754dSRandall Stewart } 3031139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_DONTWAIT, 1, MT_DATA); 3032f8829a4aSRandall Stewart if (m_notify == NULL) 3033f8829a4aSRandall Stewart /* no space left */ 3034f8829a4aSRandall Stewart return; 3035139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3036f8829a4aSRandall Stewart sai = mtod(m_notify, struct sctp_adaptation_event *); 3037f8829a4aSRandall Stewart sai->sai_type = SCTP_ADAPTATION_INDICATION; 3038f8829a4aSRandall Stewart sai->sai_flags = 0; 3039f8829a4aSRandall Stewart sai->sai_length = sizeof(struct sctp_adaptation_event); 30402afb3e84SRandall Stewart sai->sai_adaptation_ind = stcb->asoc.peers_adaptation; 3041f8829a4aSRandall Stewart sai->sai_assoc_id = sctp_get_associd(stcb); 3042f8829a4aSRandall Stewart 3043139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event); 3044139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3045f8829a4aSRandall Stewart 3046f8829a4aSRandall Stewart /* append to socket */ 3047f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 30487215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3049f8829a4aSRandall Stewart m_notify); 3050f8829a4aSRandall Stewart if (control == NULL) { 3051f8829a4aSRandall Stewart /* no memory */ 3052f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3053f8829a4aSRandall Stewart return; 3054f8829a4aSRandall Stewart } 3055139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3056139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3057f8829a4aSRandall Stewart /* not that we need this */ 3058f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3059f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3060f8829a4aSRandall Stewart control, 3061cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3062f8829a4aSRandall Stewart } 3063f8829a4aSRandall Stewart 306403b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */ 3065810ec536SMichael Tuexen static void 30662dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, 3067810ec536SMichael Tuexen uint32_t val, int so_locked 3068810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3069810ec536SMichael Tuexen SCTP_UNUSED 3070810ec536SMichael Tuexen #endif 3071810ec536SMichael Tuexen ) 3072f8829a4aSRandall Stewart { 3073f8829a4aSRandall Stewart struct mbuf *m_notify; 3074f8829a4aSRandall Stewart struct sctp_pdapi_event *pdapi; 3075f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 307603b0b021SRandall Stewart struct sockbuf *sb; 3077f8829a4aSRandall Stewart 307860990c0cSMichael Tuexen if ((stcb == NULL) || 307960990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { 3080f8829a4aSRandall Stewart /* event not enabled */ 3081f8829a4aSRandall Stewart return; 3082830d754dSRandall Stewart } 3083cd1386abSMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 3084cd1386abSMichael Tuexen return; 3085cd1386abSMichael Tuexen } 3086139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_DONTWAIT, 1, MT_DATA); 3087f8829a4aSRandall Stewart if (m_notify == NULL) 3088f8829a4aSRandall Stewart /* no space left */ 3089f8829a4aSRandall Stewart return; 3090139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3091f8829a4aSRandall Stewart pdapi = mtod(m_notify, struct sctp_pdapi_event *); 3092f8829a4aSRandall Stewart pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; 3093f8829a4aSRandall Stewart pdapi->pdapi_flags = 0; 3094f8829a4aSRandall Stewart pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); 3095f8829a4aSRandall Stewart pdapi->pdapi_indication = error; 30969a6142d8SRandall Stewart pdapi->pdapi_stream = (val >> 16); 30979a6142d8SRandall Stewart pdapi->pdapi_seq = (val & 0x0000ffff); 3098f8829a4aSRandall Stewart pdapi->pdapi_assoc_id = sctp_get_associd(stcb); 3099f8829a4aSRandall Stewart 3100139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); 3101139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3102f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 31037215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3104f8829a4aSRandall Stewart m_notify); 3105f8829a4aSRandall Stewart if (control == NULL) { 3106f8829a4aSRandall Stewart /* no memory */ 3107f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3108f8829a4aSRandall Stewart return; 3109f8829a4aSRandall Stewart } 3110139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3111139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3112f8829a4aSRandall Stewart /* not that we need this */ 3113f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 311403b0b021SRandall Stewart control->held_length = 0; 311503b0b021SRandall Stewart control->length = 0; 311603b0b021SRandall Stewart sb = &stcb->sctp_socket->so_rcv; 3117b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 3118139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify)); 311980fefe0aSRandall Stewart } 312003b0b021SRandall Stewart sctp_sballoc(stcb, sb, m_notify); 3121b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 312203b0b021SRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 312380fefe0aSRandall Stewart } 3124139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m_notify)); 312503b0b021SRandall Stewart control->end_added = 1; 312603b0b021SRandall Stewart if (stcb->asoc.control_pdapi) 312703b0b021SRandall Stewart TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); 312803b0b021SRandall Stewart else { 312903b0b021SRandall Stewart /* we really should not see this case */ 313003b0b021SRandall Stewart TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); 313103b0b021SRandall Stewart } 313203b0b021SRandall Stewart if (stcb->sctp_ep && stcb->sctp_socket) { 313303b0b021SRandall Stewart /* This should always be the case */ 3134810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3135810ec536SMichael Tuexen struct socket *so; 3136810ec536SMichael Tuexen 3137810ec536SMichael Tuexen so = SCTP_INP_SO(stcb->sctp_ep); 3138810ec536SMichael Tuexen if (!so_locked) { 3139810ec536SMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, 1); 3140810ec536SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 3141810ec536SMichael Tuexen SCTP_SOCKET_LOCK(so, 1); 3142810ec536SMichael Tuexen SCTP_TCB_LOCK(stcb); 3143810ec536SMichael Tuexen atomic_subtract_int(&stcb->asoc.refcnt, 1); 3144810ec536SMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3145810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3146810ec536SMichael Tuexen return; 3147810ec536SMichael Tuexen } 3148810ec536SMichael Tuexen } 3149810ec536SMichael Tuexen #endif 315003b0b021SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 3151810ec536SMichael Tuexen #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3152810ec536SMichael Tuexen if (!so_locked) { 3153810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3154810ec536SMichael Tuexen } 3155810ec536SMichael Tuexen #endif 3156f8829a4aSRandall Stewart } 3157f8829a4aSRandall Stewart } 3158f8829a4aSRandall Stewart 3159f8829a4aSRandall Stewart static void 3160f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb) 3161f8829a4aSRandall Stewart { 3162f8829a4aSRandall Stewart struct mbuf *m_notify; 3163f8829a4aSRandall Stewart struct sctp_shutdown_event *sse; 3164f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3165f8829a4aSRandall Stewart 3166f8829a4aSRandall Stewart /* 3167f8829a4aSRandall Stewart * For TCP model AND UDP connected sockets we will send an error up 3168f8829a4aSRandall Stewart * when an SHUTDOWN completes 3169f8829a4aSRandall Stewart */ 3170f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3171f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3172f8829a4aSRandall Stewart /* mark socket closed for read/write and wakeup! */ 3173ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3174ceaad40aSRandall Stewart struct socket *so; 3175ceaad40aSRandall Stewart 3176ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3177ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3178ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3179ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3180ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3181ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3182ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3183ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3184ceaad40aSRandall Stewart return; 3185ceaad40aSRandall Stewart } 3186ceaad40aSRandall Stewart #endif 3187f8829a4aSRandall Stewart socantsendmore(stcb->sctp_socket); 3188ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3189ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3190ceaad40aSRandall Stewart #endif 3191f8829a4aSRandall Stewart } 3192e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { 3193f8829a4aSRandall Stewart /* event not enabled */ 3194f8829a4aSRandall Stewart return; 3195830d754dSRandall Stewart } 3196139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_DONTWAIT, 1, MT_DATA); 3197f8829a4aSRandall Stewart if (m_notify == NULL) 3198f8829a4aSRandall Stewart /* no space left */ 3199f8829a4aSRandall Stewart return; 3200f8829a4aSRandall Stewart sse = mtod(m_notify, struct sctp_shutdown_event *); 3201f8829a4aSRandall Stewart sse->sse_type = SCTP_SHUTDOWN_EVENT; 3202f8829a4aSRandall Stewart sse->sse_flags = 0; 3203f8829a4aSRandall Stewart sse->sse_length = sizeof(struct sctp_shutdown_event); 3204f8829a4aSRandall Stewart sse->sse_assoc_id = sctp_get_associd(stcb); 3205f8829a4aSRandall Stewart 3206139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event); 3207139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3208f8829a4aSRandall Stewart 3209f8829a4aSRandall Stewart /* append to socket */ 3210f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 32117215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3212f8829a4aSRandall Stewart m_notify); 3213f8829a4aSRandall Stewart if (control == NULL) { 3214f8829a4aSRandall Stewart /* no memory */ 3215f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3216f8829a4aSRandall Stewart return; 3217f8829a4aSRandall Stewart } 3218139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3219139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3220f8829a4aSRandall Stewart /* not that we need this */ 3221f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3222f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3223f8829a4aSRandall Stewart control, 3224cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3225f8829a4aSRandall Stewart } 3226f8829a4aSRandall Stewart 3227f8829a4aSRandall Stewart static void 3228830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb, 3229830d754dSRandall Stewart int so_locked 3230830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3231830d754dSRandall Stewart SCTP_UNUSED 3232830d754dSRandall Stewart #endif 3233830d754dSRandall Stewart ) 3234830d754dSRandall Stewart { 3235830d754dSRandall Stewart struct mbuf *m_notify; 3236830d754dSRandall Stewart struct sctp_sender_dry_event *event; 3237830d754dSRandall Stewart struct sctp_queued_to_read *control; 3238830d754dSRandall Stewart 323960990c0cSMichael Tuexen if ((stcb == NULL) || 324060990c0cSMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { 3241830d754dSRandall Stewart /* event not enabled */ 3242830d754dSRandall Stewart return; 3243830d754dSRandall Stewart } 3244830d754dSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_DONTWAIT, 1, MT_DATA); 3245830d754dSRandall Stewart if (m_notify == NULL) { 3246830d754dSRandall Stewart /* no space left */ 3247830d754dSRandall Stewart return; 3248830d754dSRandall Stewart } 3249830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3250830d754dSRandall Stewart event = mtod(m_notify, struct sctp_sender_dry_event *); 3251830d754dSRandall Stewart event->sender_dry_type = SCTP_SENDER_DRY_EVENT; 3252830d754dSRandall Stewart event->sender_dry_flags = 0; 3253830d754dSRandall Stewart event->sender_dry_length = sizeof(struct sctp_sender_dry_event); 3254830d754dSRandall Stewart event->sender_dry_assoc_id = sctp_get_associd(stcb); 3255830d754dSRandall Stewart 3256830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event); 3257830d754dSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3258830d754dSRandall Stewart 3259830d754dSRandall Stewart /* append to socket */ 3260830d754dSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 32617215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 32627215cc1bSMichael Tuexen m_notify); 3263830d754dSRandall Stewart if (control == NULL) { 3264830d754dSRandall Stewart /* no memory */ 3265830d754dSRandall Stewart sctp_m_freem(m_notify); 3266830d754dSRandall Stewart return; 3267830d754dSRandall Stewart } 3268830d754dSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3269830d754dSRandall Stewart control->spec_flags = M_NOTIFICATION; 3270830d754dSRandall Stewart /* not that we need this */ 3271830d754dSRandall Stewart control->tail_mbuf = m_notify; 3272830d754dSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control, 3273cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3274830d754dSRandall Stewart } 3275830d754dSRandall Stewart 3276ea44232bSRandall Stewart 3277c4e848b7SRandall Stewart void 3278c4e848b7SRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, uint16_t numberin, uint16_t numberout, int flag) 3279ea44232bSRandall Stewart { 3280ea44232bSRandall Stewart struct mbuf *m_notify; 3281ea44232bSRandall Stewart struct sctp_queued_to_read *control; 3282c4e848b7SRandall Stewart struct sctp_stream_change_event *stradd; 3283ea44232bSRandall Stewart int len; 3284ea44232bSRandall Stewart 32858c501e51SMichael Tuexen if ((stcb == NULL) || 32868c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_CHANGEEVNT))) { 3287ea44232bSRandall Stewart /* event not enabled */ 3288ea44232bSRandall Stewart return; 3289ea44232bSRandall Stewart } 3290c4e848b7SRandall Stewart if ((stcb->asoc.peer_req_out) && flag) { 3291c4e848b7SRandall Stewart /* Peer made the request, don't tell the local user */ 3292c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3293c4e848b7SRandall Stewart return; 3294c4e848b7SRandall Stewart } 3295c4e848b7SRandall Stewart stcb->asoc.peer_req_out = 0; 3296ea44232bSRandall Stewart m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA); 3297ea44232bSRandall Stewart if (m_notify == NULL) 3298ea44232bSRandall Stewart /* no space left */ 3299ea44232bSRandall Stewart return; 3300ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3301c4e848b7SRandall Stewart len = sizeof(struct sctp_stream_change_event); 3302ea44232bSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3303ea44232bSRandall Stewart /* never enough room */ 3304ea44232bSRandall Stewart sctp_m_freem(m_notify); 3305ea44232bSRandall Stewart return; 3306ea44232bSRandall Stewart } 3307c4e848b7SRandall Stewart stradd = mtod(m_notify, struct sctp_stream_change_event *); 3308c4e848b7SRandall Stewart stradd->strchange_type = SCTP_STREAM_CHANGE_EVENT; 3309c4e848b7SRandall Stewart stradd->strchange_flags = flag; 3310c4e848b7SRandall Stewart stradd->strchange_length = len; 3311c4e848b7SRandall Stewart stradd->strchange_assoc_id = sctp_get_associd(stcb); 3312c4e848b7SRandall Stewart stradd->strchange_instrms = numberin; 3313c4e848b7SRandall Stewart stradd->strchange_outstrms = numberout; 3314ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3315ea44232bSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3316ea44232bSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3317ea44232bSRandall Stewart /* no space */ 3318ea44232bSRandall Stewart sctp_m_freem(m_notify); 3319ea44232bSRandall Stewart return; 3320ea44232bSRandall Stewart } 3321ea44232bSRandall Stewart /* append to socket */ 3322ea44232bSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 33237215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3324ea44232bSRandall Stewart m_notify); 3325ea44232bSRandall Stewart if (control == NULL) { 3326ea44232bSRandall Stewart /* no memory */ 3327ea44232bSRandall Stewart sctp_m_freem(m_notify); 3328ea44232bSRandall Stewart return; 3329ea44232bSRandall Stewart } 3330ea44232bSRandall Stewart control->spec_flags = M_NOTIFICATION; 3331ea44232bSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3332ea44232bSRandall Stewart /* not that we need this */ 3333ea44232bSRandall Stewart control->tail_mbuf = m_notify; 3334ea44232bSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3335ea44232bSRandall Stewart control, 3336cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3337ea44232bSRandall Stewart } 3338ea44232bSRandall Stewart 3339c4e848b7SRandall Stewart void 3340c4e848b7SRandall Stewart sctp_notify_stream_reset_tsn(struct sctp_tcb *stcb, uint32_t sending_tsn, uint32_t recv_tsn, int flag) 3341c4e848b7SRandall Stewart { 3342c4e848b7SRandall Stewart struct mbuf *m_notify; 3343c4e848b7SRandall Stewart struct sctp_queued_to_read *control; 3344c4e848b7SRandall Stewart struct sctp_assoc_reset_event *strasoc; 3345c4e848b7SRandall Stewart int len; 3346c4e848b7SRandall Stewart 33478c501e51SMichael Tuexen if ((stcb == NULL) || 33488c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ASSOC_RESETEVNT))) { 3349c4e848b7SRandall Stewart /* event not enabled */ 3350c4e848b7SRandall Stewart return; 3351c4e848b7SRandall Stewart } 3352c4e848b7SRandall Stewart m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA); 3353c4e848b7SRandall Stewart if (m_notify == NULL) 3354c4e848b7SRandall Stewart /* no space left */ 3355c4e848b7SRandall Stewart return; 3356c4e848b7SRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3357c4e848b7SRandall Stewart len = sizeof(struct sctp_assoc_reset_event); 3358c4e848b7SRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3359c4e848b7SRandall Stewart /* never enough room */ 3360c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3361c4e848b7SRandall Stewart return; 3362c4e848b7SRandall Stewart } 3363c4e848b7SRandall Stewart strasoc = mtod(m_notify, struct sctp_assoc_reset_event *); 3364c4e848b7SRandall Stewart strasoc->assocreset_type = SCTP_ASSOC_RESET_EVENT; 3365c4e848b7SRandall Stewart strasoc->assocreset_flags = flag; 3366c4e848b7SRandall Stewart strasoc->assocreset_length = len; 3367c4e848b7SRandall Stewart strasoc->assocreset_assoc_id = sctp_get_associd(stcb); 3368c4e848b7SRandall Stewart strasoc->assocreset_local_tsn = sending_tsn; 3369c4e848b7SRandall Stewart strasoc->assocreset_remote_tsn = recv_tsn; 3370c4e848b7SRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3371c4e848b7SRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3372c4e848b7SRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3373c4e848b7SRandall Stewart /* no space */ 3374c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3375c4e848b7SRandall Stewart return; 3376c4e848b7SRandall Stewart } 3377c4e848b7SRandall Stewart /* append to socket */ 3378c4e848b7SRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3379c4e848b7SRandall Stewart 0, 0, stcb->asoc.context, 0, 0, 0, 3380c4e848b7SRandall Stewart m_notify); 3381c4e848b7SRandall Stewart if (control == NULL) { 3382c4e848b7SRandall Stewart /* no memory */ 3383c4e848b7SRandall Stewart sctp_m_freem(m_notify); 3384c4e848b7SRandall Stewart return; 3385c4e848b7SRandall Stewart } 3386c4e848b7SRandall Stewart control->spec_flags = M_NOTIFICATION; 3387c4e848b7SRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3388c4e848b7SRandall Stewart /* not that we need this */ 3389c4e848b7SRandall Stewart control->tail_mbuf = m_notify; 3390c4e848b7SRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3391c4e848b7SRandall Stewart control, 3392c4e848b7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3393c4e848b7SRandall Stewart } 3394c4e848b7SRandall Stewart 3395c4e848b7SRandall Stewart 3396ea44232bSRandall Stewart 3397830d754dSRandall Stewart static void 3398f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb, 3399f8829a4aSRandall Stewart int number_entries, uint16_t * list, int flag) 3400f8829a4aSRandall Stewart { 3401f8829a4aSRandall Stewart struct mbuf *m_notify; 3402f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3403f8829a4aSRandall Stewart struct sctp_stream_reset_event *strreset; 3404f8829a4aSRandall Stewart int len; 3405f8829a4aSRandall Stewart 34068c501e51SMichael Tuexen if ((stcb == NULL) || 34078c501e51SMichael Tuexen (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT))) { 3408f8829a4aSRandall Stewart /* event not enabled */ 3409f8829a4aSRandall Stewart return; 3410830d754dSRandall Stewart } 3411139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA); 3412f8829a4aSRandall Stewart if (m_notify == NULL) 3413f8829a4aSRandall Stewart /* no space left */ 3414f8829a4aSRandall Stewart return; 3415139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3416f8829a4aSRandall Stewart len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); 3417f8829a4aSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3418f8829a4aSRandall Stewart /* never enough room */ 3419f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3420f8829a4aSRandall Stewart return; 3421f8829a4aSRandall Stewart } 3422f8829a4aSRandall Stewart strreset = mtod(m_notify, struct sctp_stream_reset_event *); 3423f8829a4aSRandall Stewart strreset->strreset_type = SCTP_STREAM_RESET_EVENT; 3424c4e848b7SRandall Stewart strreset->strreset_flags = flag; 3425f8829a4aSRandall Stewart strreset->strreset_length = len; 3426f8829a4aSRandall Stewart strreset->strreset_assoc_id = sctp_get_associd(stcb); 3427f8829a4aSRandall Stewart if (number_entries) { 3428f8829a4aSRandall Stewart int i; 3429f8829a4aSRandall Stewart 3430f8829a4aSRandall Stewart for (i = 0; i < number_entries; i++) { 3431c4e848b7SRandall Stewart strreset->strreset_stream_list[i] = ntohs(list[i]); 3432f8829a4aSRandall Stewart } 3433f8829a4aSRandall Stewart } 3434139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3435139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3436139bc87fSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3437f8829a4aSRandall Stewart /* no space */ 3438f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3439f8829a4aSRandall Stewart return; 3440f8829a4aSRandall Stewart } 3441f8829a4aSRandall Stewart /* append to socket */ 3442f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 34437215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3444f8829a4aSRandall Stewart m_notify); 3445f8829a4aSRandall Stewart if (control == NULL) { 3446f8829a4aSRandall Stewart /* no memory */ 3447f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3448f8829a4aSRandall Stewart return; 3449f8829a4aSRandall Stewart } 3450139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3451139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3452f8829a4aSRandall Stewart /* not that we need this */ 3453f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3454f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3455f8829a4aSRandall Stewart control, 3456cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3457f8829a4aSRandall Stewart } 3458f8829a4aSRandall Stewart 3459f8829a4aSRandall Stewart 3460389b1b11SMichael Tuexen static void 3461389b1b11SMichael Tuexen sctp_notify_remote_error(struct sctp_tcb *stcb, uint16_t error, struct sctp_error_chunk *chunk) 3462389b1b11SMichael Tuexen { 3463389b1b11SMichael Tuexen struct mbuf *m_notify; 3464389b1b11SMichael Tuexen struct sctp_remote_error *sre; 3465389b1b11SMichael Tuexen struct sctp_queued_to_read *control; 3466389b1b11SMichael Tuexen size_t notif_len, chunk_len; 3467389b1b11SMichael Tuexen 3468389b1b11SMichael Tuexen if ((stcb == NULL) || 3469389b1b11SMichael Tuexen sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPEERERR)) { 3470389b1b11SMichael Tuexen return; 3471389b1b11SMichael Tuexen } 3472389b1b11SMichael Tuexen if (chunk != NULL) { 3473389b1b11SMichael Tuexen chunk_len = htons(chunk->ch.chunk_length); 3474389b1b11SMichael Tuexen } else { 3475389b1b11SMichael Tuexen chunk_len = 0; 3476389b1b11SMichael Tuexen } 3477389b1b11SMichael Tuexen notif_len = sizeof(struct sctp_remote_error) + chunk_len; 3478389b1b11SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA); 3479389b1b11SMichael Tuexen if (m_notify == NULL) { 3480389b1b11SMichael Tuexen /* Retry with smaller value. */ 3481389b1b11SMichael Tuexen notif_len = sizeof(struct sctp_remote_error); 3482389b1b11SMichael Tuexen m_notify = sctp_get_mbuf_for_msg(notif_len, 0, M_DONTWAIT, 1, MT_DATA); 3483389b1b11SMichael Tuexen if (m_notify == NULL) { 3484389b1b11SMichael Tuexen return; 3485389b1b11SMichael Tuexen } 3486389b1b11SMichael Tuexen } 3487389b1b11SMichael Tuexen SCTP_BUF_NEXT(m_notify) = NULL; 3488389b1b11SMichael Tuexen sre = mtod(m_notify, struct sctp_remote_error *); 3489389b1b11SMichael Tuexen sre->sre_type = SCTP_REMOTE_ERROR; 3490389b1b11SMichael Tuexen sre->sre_flags = 0; 3491389b1b11SMichael Tuexen sre->sre_length = sizeof(struct sctp_remote_error); 3492389b1b11SMichael Tuexen sre->sre_error = error; 3493389b1b11SMichael Tuexen sre->sre_assoc_id = sctp_get_associd(stcb); 3494389b1b11SMichael Tuexen if (notif_len > sizeof(struct sctp_remote_error)) { 3495389b1b11SMichael Tuexen memcpy(sre->sre_data, chunk, chunk_len); 3496389b1b11SMichael Tuexen sre->sre_length += chunk_len; 3497389b1b11SMichael Tuexen } 3498389b1b11SMichael Tuexen SCTP_BUF_LEN(m_notify) = sre->sre_length; 3499389b1b11SMichael Tuexen control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3500389b1b11SMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3501389b1b11SMichael Tuexen m_notify); 3502389b1b11SMichael Tuexen if (control != NULL) { 3503389b1b11SMichael Tuexen control->length = SCTP_BUF_LEN(m_notify); 3504389b1b11SMichael Tuexen /* not that we need this */ 3505389b1b11SMichael Tuexen control->tail_mbuf = m_notify; 3506389b1b11SMichael Tuexen control->spec_flags = M_NOTIFICATION; 3507389b1b11SMichael Tuexen sctp_add_to_readq(stcb->sctp_ep, stcb, 3508389b1b11SMichael Tuexen control, 3509389b1b11SMichael Tuexen &stcb->sctp_socket->so_rcv, 1, 3510389b1b11SMichael Tuexen SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3511389b1b11SMichael Tuexen } else { 3512389b1b11SMichael Tuexen sctp_m_freem(m_notify); 3513389b1b11SMichael Tuexen } 3514389b1b11SMichael Tuexen } 3515389b1b11SMichael Tuexen 3516389b1b11SMichael Tuexen 3517f8829a4aSRandall Stewart void 3518f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, 3519ceaad40aSRandall Stewart uint32_t error, void *data, int so_locked 3520ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3521ceaad40aSRandall Stewart SCTP_UNUSED 3522ceaad40aSRandall Stewart #endif 3523ceaad40aSRandall Stewart ) 3524f8829a4aSRandall Stewart { 3525830d754dSRandall Stewart if ((stcb == NULL) || 3526830d754dSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3527f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3528830d754dSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 3529830d754dSRandall Stewart /* If the socket is gone we are out of here */ 3530f8829a4aSRandall Stewart return; 3531f8829a4aSRandall Stewart } 3532a99b6783SRandall Stewart if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { 3533a99b6783SRandall Stewart return; 3534a99b6783SRandall Stewart } 353517205eccSRandall Stewart if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || 353617205eccSRandall Stewart (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) { 353717205eccSRandall Stewart if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || 353817205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_UP) || 353917205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { 354017205eccSRandall Stewart /* Don't report these in front states */ 354117205eccSRandall Stewart return; 354217205eccSRandall Stewart } 354317205eccSRandall Stewart } 3544f8829a4aSRandall Stewart switch (notification) { 3545f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_UP: 3546f8829a4aSRandall Stewart if (stcb->asoc.assoc_up_sent == 0) { 3547410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, 0, so_locked); 3548f8829a4aSRandall Stewart stcb->asoc.assoc_up_sent = 1; 3549f8829a4aSRandall Stewart } 35502afb3e84SRandall Stewart if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { 35517215cc1bSMichael Tuexen sctp_notify_adaptation_layer(stcb); 35522afb3e84SRandall Stewart } 3553830d754dSRandall Stewart if (stcb->asoc.peer_supports_auth == 0) { 3554830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 3555830d754dSRandall Stewart NULL, so_locked); 3556830d754dSRandall Stewart } 3557f8829a4aSRandall Stewart break; 3558f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_DOWN: 3559410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, 0, so_locked); 3560f8829a4aSRandall Stewart break; 3561f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_DOWN: 3562f8829a4aSRandall Stewart { 3563f8829a4aSRandall Stewart struct sctp_nets *net; 3564f8829a4aSRandall Stewart 3565f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3566f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, 3567f8829a4aSRandall Stewart (struct sockaddr *)&net->ro._l_addr, error); 3568f8829a4aSRandall Stewart break; 3569f8829a4aSRandall Stewart } 3570f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_UP: 3571f8829a4aSRandall Stewart { 3572f8829a4aSRandall Stewart struct sctp_nets *net; 3573f8829a4aSRandall Stewart 3574f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3575f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, 3576f8829a4aSRandall Stewart (struct sockaddr *)&net->ro._l_addr, error); 3577f8829a4aSRandall Stewart break; 3578f8829a4aSRandall Stewart } 3579f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_CONFIRMED: 3580f8829a4aSRandall Stewart { 3581f8829a4aSRandall Stewart struct sctp_nets *net; 3582f8829a4aSRandall Stewart 3583f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3584f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, 3585f8829a4aSRandall Stewart (struct sockaddr *)&net->ro._l_addr, error); 3586f8829a4aSRandall Stewart break; 3587f8829a4aSRandall Stewart } 3588f8829a4aSRandall Stewart case SCTP_NOTIFY_SPECIAL_SP_FAIL: 3589f8829a4aSRandall Stewart sctp_notify_send_failed2(stcb, error, 3590ceaad40aSRandall Stewart (struct sctp_stream_queue_pending *)data, so_locked); 3591f8829a4aSRandall Stewart break; 35921edc9dbaSMichael Tuexen case SCTP_NOTIFY_SENT_DG_FAIL: 35931edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 1, error, 35941edc9dbaSMichael Tuexen (struct sctp_tmit_chunk *)data, so_locked); 35951edc9dbaSMichael Tuexen break; 35961edc9dbaSMichael Tuexen case SCTP_NOTIFY_UNSENT_DG_FAIL: 35971edc9dbaSMichael Tuexen sctp_notify_send_failed(stcb, 0, error, 3598ceaad40aSRandall Stewart (struct sctp_tmit_chunk *)data, so_locked); 3599f8829a4aSRandall Stewart break; 3600f8829a4aSRandall Stewart case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: 36019a6142d8SRandall Stewart { 36029a6142d8SRandall Stewart uint32_t val; 36039a6142d8SRandall Stewart 36049a6142d8SRandall Stewart val = *((uint32_t *) data); 36059a6142d8SRandall Stewart 3606810ec536SMichael Tuexen sctp_notify_partial_delivery_indication(stcb, error, val, so_locked); 3607f8829a4aSRandall Stewart break; 3608810ec536SMichael Tuexen } 3609410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_LOC_ABORTED: 3610c105859eSRandall Stewart if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) || 3611c105859eSRandall Stewart ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) { 3612410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 0, so_locked); 3613c105859eSRandall Stewart } else { 3614410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 0, so_locked); 3615410a3b1eSMichael Tuexen } 3616410a3b1eSMichael Tuexen break; 3617410a3b1eSMichael Tuexen case SCTP_NOTIFY_ASSOC_REM_ABORTED: 3618410a3b1eSMichael Tuexen if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) || 3619410a3b1eSMichael Tuexen ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) { 3620410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, data, 1, so_locked); 3621410a3b1eSMichael Tuexen } else { 3622410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, data, 1, so_locked); 3623c105859eSRandall Stewart } 3624f8829a4aSRandall Stewart break; 3625f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_RESTART: 3626410a3b1eSMichael Tuexen sctp_notify_assoc_change(SCTP_RESTART, stcb, error, NULL, 0, so_locked); 3627830d754dSRandall Stewart if (stcb->asoc.peer_supports_auth == 0) { 3628830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 3629830d754dSRandall Stewart NULL, so_locked); 3630830d754dSRandall Stewart } 3631f8829a4aSRandall Stewart break; 3632f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_SEND: 3633d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_OUTGOING_SSN); 3634f8829a4aSRandall Stewart break; 3635f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_RECV: 3636d7714577SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STREAM_RESET_INCOMING); 3637f8829a4aSRandall Stewart break; 3638f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_OUT: 3639c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), 3640d7714577SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_FAILED)); 3641f8829a4aSRandall Stewart break; 3642d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_OUT: 3643d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), 3644d4260646SMichael Tuexen (SCTP_STREAM_RESET_OUTGOING_SSN | SCTP_STREAM_RESET_DENIED)); 3645d4260646SMichael Tuexen break; 3646f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_IN: 3647c4e848b7SRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), 3648d7714577SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_FAILED)); 3649f8829a4aSRandall Stewart break; 3650d4260646SMichael Tuexen case SCTP_NOTIFY_STR_RESET_DENIED_IN: 3651d4260646SMichael Tuexen sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), 3652d4260646SMichael Tuexen (SCTP_STREAM_RESET_INCOMING | SCTP_STREAM_RESET_DENIED)); 3653d4260646SMichael Tuexen break; 3654f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_ADD_IP: 3655f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, 3656f8829a4aSRandall Stewart error); 3657f8829a4aSRandall Stewart break; 3658f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_DELETE_IP: 3659f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, 3660f8829a4aSRandall Stewart error); 3661f8829a4aSRandall Stewart break; 3662f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_SET_PRIMARY: 3663f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data, 3664f8829a4aSRandall Stewart error); 3665f8829a4aSRandall Stewart break; 3666f8829a4aSRandall Stewart case SCTP_NOTIFY_PEER_SHUTDOWN: 3667f8829a4aSRandall Stewart sctp_notify_shutdown_event(stcb); 3668f8829a4aSRandall Stewart break; 3669f8829a4aSRandall Stewart case SCTP_NOTIFY_AUTH_NEW_KEY: 367078f28045SMichael Tuexen sctp_notify_authentication(stcb, SCTP_AUTH_NEW_KEY, error, 3671830d754dSRandall Stewart (uint16_t) (uintptr_t) data, 3672830d754dSRandall Stewart so_locked); 3673f8829a4aSRandall Stewart break; 3674830d754dSRandall Stewart case SCTP_NOTIFY_AUTH_FREE_KEY: 3675830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, 3676830d754dSRandall Stewart (uint16_t) (uintptr_t) data, 3677830d754dSRandall Stewart so_locked); 3678f8829a4aSRandall Stewart break; 3679830d754dSRandall Stewart case SCTP_NOTIFY_NO_PEER_AUTH: 3680830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, 3681830d754dSRandall Stewart (uint16_t) (uintptr_t) data, 3682830d754dSRandall Stewart so_locked); 3683830d754dSRandall Stewart break; 3684830d754dSRandall Stewart case SCTP_NOTIFY_SENDER_DRY: 3685830d754dSRandall Stewart sctp_notify_sender_dry_event(stcb, so_locked); 3686830d754dSRandall Stewart break; 3687389b1b11SMichael Tuexen case SCTP_NOTIFY_REMOTE_ERROR: 3688389b1b11SMichael Tuexen sctp_notify_remote_error(stcb, error, data); 3689389b1b11SMichael Tuexen break; 3690f8829a4aSRandall Stewart default: 3691ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", 3692ad81507eSRandall Stewart __FUNCTION__, notification, notification); 3693f8829a4aSRandall Stewart break; 3694f8829a4aSRandall Stewart } /* end switch */ 3695f8829a4aSRandall Stewart } 3696f8829a4aSRandall Stewart 3697f8829a4aSRandall Stewart void 36981edc9dbaSMichael Tuexen sctp_report_all_outbound(struct sctp_tcb *stcb, uint16_t error, int holds_lock, int so_locked 3699ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3700ceaad40aSRandall Stewart SCTP_UNUSED 3701ceaad40aSRandall Stewart #endif 3702ceaad40aSRandall Stewart ) 3703f8829a4aSRandall Stewart { 3704f8829a4aSRandall Stewart struct sctp_association *asoc; 3705f8829a4aSRandall Stewart struct sctp_stream_out *outs; 37064a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk; 37074a9ef3f8SMichael Tuexen struct sctp_stream_queue_pending *sp, *nsp; 37087f34832bSRandall Stewart int i; 3709f8829a4aSRandall Stewart 3710ad81507eSRandall Stewart if (stcb == NULL) { 3711ad81507eSRandall Stewart return; 3712ad81507eSRandall Stewart } 37134a9ef3f8SMichael Tuexen asoc = &stcb->asoc; 37144a9ef3f8SMichael Tuexen if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { 3715478fbccbSRandall Stewart /* already being freed */ 3716478fbccbSRandall Stewart return; 3717478fbccbSRandall Stewart } 3718f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3719f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 37204a9ef3f8SMichael Tuexen (asoc->state & SCTP_STATE_CLOSED_SOCKET)) { 3721f8829a4aSRandall Stewart return; 3722f8829a4aSRandall Stewart } 3723f8829a4aSRandall Stewart /* now through all the gunk freeing chunks */ 3724ad81507eSRandall Stewart if (holds_lock == 0) { 37257f34832bSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 3726ad81507eSRandall Stewart } 3727d00aff5dSRandall Stewart /* sent queue SHOULD be empty */ 37284a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { 3729d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); 3730d00aff5dSRandall Stewart asoc->sent_queue_cnt--; 3731*325c8c46SMichael Tuexen if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { 3732a7ad6026SMichael Tuexen if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) { 3733a7ad6026SMichael Tuexen asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--; 3734a7ad6026SMichael Tuexen #ifdef INVARIANTS 3735a7ad6026SMichael Tuexen } else { 3736a7ad6026SMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number); 3737a7ad6026SMichael Tuexen #endif 3738a7ad6026SMichael Tuexen } 3739a7ad6026SMichael Tuexen } 37400c0982b8SRandall Stewart if (chk->data != NULL) { 3741d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 37421edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 37431edc9dbaSMichael Tuexen error, chk, so_locked); 3744810ec536SMichael Tuexen if (chk->data) { 3745d00aff5dSRandall Stewart sctp_m_freem(chk->data); 3746d00aff5dSRandall Stewart chk->data = NULL; 3747d00aff5dSRandall Stewart } 3748810ec536SMichael Tuexen } 3749689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 3750d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 3751d00aff5dSRandall Stewart } 3752d00aff5dSRandall Stewart /* pending send queue SHOULD be empty */ 37534a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { 3754d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); 3755d00aff5dSRandall Stewart asoc->send_queue_cnt--; 3756a7ad6026SMichael Tuexen if (asoc->strmout[chk->rec.data.stream_number].chunks_on_queues > 0) { 3757a7ad6026SMichael Tuexen asoc->strmout[chk->rec.data.stream_number].chunks_on_queues--; 3758a7ad6026SMichael Tuexen #ifdef INVARIANTS 3759a7ad6026SMichael Tuexen } else { 3760a7ad6026SMichael Tuexen panic("No chunks on the queues for sid %u.", chk->rec.data.stream_number); 3761a7ad6026SMichael Tuexen #endif 3762a7ad6026SMichael Tuexen } 37630c0982b8SRandall Stewart if (chk->data != NULL) { 3764d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 37651edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 37661edc9dbaSMichael Tuexen error, chk, so_locked); 3767810ec536SMichael Tuexen if (chk->data) { 3768d00aff5dSRandall Stewart sctp_m_freem(chk->data); 3769d00aff5dSRandall Stewart chk->data = NULL; 3770d00aff5dSRandall Stewart } 3771810ec536SMichael Tuexen } 3772689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 3773d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 3774d00aff5dSRandall Stewart } 37754a9ef3f8SMichael Tuexen for (i = 0; i < asoc->streamoutcnt; i++) { 37767f34832bSRandall Stewart /* For each stream */ 37774a9ef3f8SMichael Tuexen outs = &asoc->strmout[i]; 37787f34832bSRandall Stewart /* clean up any sends there */ 37794a9ef3f8SMichael Tuexen asoc->locked_on_sending = NULL; 37804a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { 37814a9ef3f8SMichael Tuexen asoc->stream_queue_cnt--; 3782f8829a4aSRandall Stewart TAILQ_REMOVE(&outs->outqueue, sp, next); 3783f8829a4aSRandall Stewart sctp_free_spbufspace(stcb, asoc, sp); 3784478fbccbSRandall Stewart if (sp->data) { 3785f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 37861edc9dbaSMichael Tuexen error, (void *)sp, so_locked); 3787f8829a4aSRandall Stewart if (sp->data) { 3788f8829a4aSRandall Stewart sctp_m_freem(sp->data); 3789f8829a4aSRandall Stewart sp->data = NULL; 3790d07b2ac6SMichael Tuexen sp->tail_mbuf = NULL; 3791d07b2ac6SMichael Tuexen sp->length = 0; 3792f8829a4aSRandall Stewart } 3793478fbccbSRandall Stewart } 37949eea4a2dSMichael Tuexen if (sp->net) { 3795f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 3796f8829a4aSRandall Stewart sp->net = NULL; 37979eea4a2dSMichael Tuexen } 3798f8829a4aSRandall Stewart /* Free the chunk */ 3799689e6a5fSMichael Tuexen sctp_free_a_strmoq(stcb, sp, so_locked); 38003c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 3801f8829a4aSRandall Stewart } 3802f8829a4aSRandall Stewart } 3803f8829a4aSRandall Stewart 3804ad81507eSRandall Stewart if (holds_lock == 0) { 38057f34832bSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 3806f8829a4aSRandall Stewart } 3807ad81507eSRandall Stewart } 3808f8829a4aSRandall Stewart 3809f8829a4aSRandall Stewart void 3810410a3b1eSMichael Tuexen sctp_abort_notification(struct sctp_tcb *stcb, uint8_t from_peer, uint16_t error, 3811a2b42326SMichael Tuexen struct sctp_abort_chunk *abort, int so_locked 3812ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3813ceaad40aSRandall Stewart SCTP_UNUSED 3814ceaad40aSRandall Stewart #endif 3815ceaad40aSRandall Stewart ) 3816f8829a4aSRandall Stewart { 3817ad81507eSRandall Stewart if (stcb == NULL) { 3818ad81507eSRandall Stewart return; 3819ad81507eSRandall Stewart } 3820c55b70ceSMichael Tuexen if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3821c55b70ceSMichael Tuexen ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3822c55b70ceSMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { 3823c55b70ceSMichael Tuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; 3824c55b70ceSMichael Tuexen } 3825f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3826f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3827f8829a4aSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 3828f8829a4aSRandall Stewart return; 3829f8829a4aSRandall Stewart } 3830f8829a4aSRandall Stewart /* Tell them we lost the asoc */ 38311edc9dbaSMichael Tuexen sctp_report_all_outbound(stcb, error, 1, so_locked); 3832410a3b1eSMichael Tuexen if (from_peer) { 3833410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_REM_ABORTED, stcb, error, abort, so_locked); 3834410a3b1eSMichael Tuexen } else { 3835410a3b1eSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_ASSOC_LOC_ABORTED, stcb, error, abort, so_locked); 3836410a3b1eSMichael Tuexen } 3837f8829a4aSRandall Stewart } 3838f8829a4aSRandall Stewart 3839f8829a4aSRandall Stewart void 3840f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 3841b1754ad1SMichael Tuexen struct mbuf *m, int iphlen, 3842b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 3843b1754ad1SMichael Tuexen struct sctphdr *sh, struct mbuf *op_err, 3844f30ac432SMichael Tuexen uint8_t use_mflowid, uint32_t mflowid, 3845c54a18d2SRandall Stewart uint32_t vrf_id, uint16_t port) 3846f8829a4aSRandall Stewart { 3847f8829a4aSRandall Stewart uint32_t vtag; 3848f8829a4aSRandall Stewart 3849ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3850ceaad40aSRandall Stewart struct socket *so; 3851ceaad40aSRandall Stewart 3852ceaad40aSRandall Stewart #endif 3853ceaad40aSRandall Stewart 3854f8829a4aSRandall Stewart vtag = 0; 3855f8829a4aSRandall Stewart if (stcb != NULL) { 3856f8829a4aSRandall Stewart /* We have a TCB to abort, send notification too */ 3857f8829a4aSRandall Stewart vtag = stcb->asoc.peer_vtag; 3858410a3b1eSMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, SCTP_SO_NOT_LOCKED); 385917205eccSRandall Stewart /* get the assoc vrf id and table id */ 386017205eccSRandall Stewart vrf_id = stcb->asoc.vrf_id; 386163981c2bSRandall Stewart stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; 3862f8829a4aSRandall Stewart } 3863b1754ad1SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, vtag, op_err, 3864f30ac432SMichael Tuexen use_mflowid, mflowid, 3865f30ac432SMichael Tuexen vrf_id, port); 3866f8829a4aSRandall Stewart if (stcb != NULL) { 3867f8829a4aSRandall Stewart /* Ok, now lets free it */ 3868ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3869ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 3870ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3871ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3872ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3873ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3874ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3875ceaad40aSRandall Stewart #endif 38760271d0cdSMichael Tuexen SCTP_STAT_INCR_COUNTER32(sctps_aborted); 38770271d0cdSMichael Tuexen if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 38780271d0cdSMichael Tuexen (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 38790271d0cdSMichael Tuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 38800271d0cdSMichael Tuexen } 3881c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4); 3882ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3883ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3884ceaad40aSRandall Stewart #endif 3885f8829a4aSRandall Stewart } 3886f8829a4aSRandall Stewart } 3887f8829a4aSRandall Stewart 3888f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 3889f1f73e57SRandall Stewart void 3890f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb) 3891f1f73e57SRandall Stewart { 389218e198d3SRandall Stewart #ifdef NOSIY_PRINTS 3893f1f73e57SRandall Stewart int i; 3894f1f73e57SRandall Stewart 3895ad81507eSRandall Stewart SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code); 3896ad81507eSRandall Stewart SCTP_PRINTF("IN bound TSN log-aaa\n"); 3897f1f73e57SRandall Stewart if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) { 3898ad81507eSRandall Stewart SCTP_PRINTF("None rcvd\n"); 3899f1f73e57SRandall Stewart goto none_in; 3900f1f73e57SRandall Stewart } 3901f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_wrapped) { 3902f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) { 3903ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3904f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 3905f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 3906f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 3907f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 3908f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 3909f1f73e57SRandall Stewart } 3910f1f73e57SRandall Stewart } 3911f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_at) { 3912f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_in_at; i++) { 3913ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3914f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 3915f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 3916f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 3917f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 3918f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 3919f1f73e57SRandall Stewart } 3920f1f73e57SRandall Stewart } 3921f1f73e57SRandall Stewart none_in: 3922ad81507eSRandall Stewart SCTP_PRINTF("OUT bound TSN log-aaa\n"); 3923ad81507eSRandall Stewart if ((stcb->asoc.tsn_out_at == 0) && 3924ad81507eSRandall Stewart (stcb->asoc.tsn_out_wrapped == 0)) { 3925ad81507eSRandall Stewart SCTP_PRINTF("None sent\n"); 3926f1f73e57SRandall Stewart } 3927f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_wrapped) { 3928f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) { 3929ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3930f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 3931f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 3932f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 3933f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 3934f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 3935f1f73e57SRandall Stewart } 3936f1f73e57SRandall Stewart } 3937f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_at) { 3938f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_out_at; i++) { 3939ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3940f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 3941f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 3942f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 3943f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 3944f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 3945f1f73e57SRandall Stewart } 3946f1f73e57SRandall Stewart } 394718e198d3SRandall Stewart #endif 3948f1f73e57SRandall Stewart } 3949f1f73e57SRandall Stewart 3950f1f73e57SRandall Stewart #endif 3951f1f73e57SRandall Stewart 3952f8829a4aSRandall Stewart void 3953f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 3954a2b42326SMichael Tuexen struct mbuf *op_err, 3955ceaad40aSRandall Stewart int so_locked 3956ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3957ceaad40aSRandall Stewart SCTP_UNUSED 3958ceaad40aSRandall Stewart #endif 3959ceaad40aSRandall Stewart ) 3960f8829a4aSRandall Stewart { 3961ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3962ceaad40aSRandall Stewart struct socket *so; 3963ceaad40aSRandall Stewart 3964ceaad40aSRandall Stewart #endif 3965ceaad40aSRandall Stewart 3966ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3967ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 3968ceaad40aSRandall Stewart #endif 3969f8829a4aSRandall Stewart if (stcb == NULL) { 3970f8829a4aSRandall Stewart /* Got to have a TCB */ 3971f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3972f8829a4aSRandall Stewart if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) { 3973b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 3974b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 3975f8829a4aSRandall Stewart } 3976f8829a4aSRandall Stewart } 3977f8829a4aSRandall Stewart return; 397863981c2bSRandall Stewart } else { 397963981c2bSRandall Stewart stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; 3980f8829a4aSRandall Stewart } 3981f8829a4aSRandall Stewart /* notify the ulp */ 3982a2b42326SMichael Tuexen if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { 3983410a3b1eSMichael Tuexen sctp_abort_notification(stcb, 0, 0, NULL, so_locked); 3984a2b42326SMichael Tuexen } 3985f8829a4aSRandall Stewart /* notify the peer */ 3986ceaad40aSRandall Stewart sctp_send_abort_tcb(stcb, op_err, so_locked); 3987f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_aborted); 3988f8829a4aSRandall Stewart if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 3989f8829a4aSRandall Stewart (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 3990f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 3991f8829a4aSRandall Stewart } 3992f8829a4aSRandall Stewart /* now free the asoc */ 3993f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 3994f1f73e57SRandall Stewart sctp_print_out_track_log(stcb); 3995f1f73e57SRandall Stewart #endif 3996ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3997ceaad40aSRandall Stewart if (!so_locked) { 3998ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3999ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4000ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4001ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4002ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4003ceaad40aSRandall Stewart } 4004ceaad40aSRandall Stewart #endif 4005c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5); 4006ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4007ceaad40aSRandall Stewart if (!so_locked) { 4008ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4009ceaad40aSRandall Stewart } 4010ceaad40aSRandall Stewart #endif 4011f8829a4aSRandall Stewart } 4012f8829a4aSRandall Stewart 4013f8829a4aSRandall Stewart void 4014b1754ad1SMichael Tuexen sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, 4015b1754ad1SMichael Tuexen struct sockaddr *src, struct sockaddr *dst, 4016b1754ad1SMichael Tuexen struct sctphdr *sh, struct sctp_inpcb *inp, 4017f30ac432SMichael Tuexen uint8_t use_mflowid, uint32_t mflowid, 4018f30ac432SMichael Tuexen uint32_t vrf_id, uint16_t port) 4019f8829a4aSRandall Stewart { 4020f8829a4aSRandall Stewart struct sctp_chunkhdr *ch, chunk_buf; 4021f8829a4aSRandall Stewart unsigned int chk_length; 4022c58e60beSMichael Tuexen int contains_init_chunk; 4023f8829a4aSRandall Stewart 4024f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue); 4025f8829a4aSRandall Stewart /* Generate a TO address for future reference */ 4026f8829a4aSRandall Stewart if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 4027f8829a4aSRandall Stewart if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) { 4028b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 4029b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 4030f8829a4aSRandall Stewart } 4031f8829a4aSRandall Stewart } 4032c58e60beSMichael Tuexen contains_init_chunk = 0; 4033f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4034f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *) & chunk_buf); 4035f8829a4aSRandall Stewart while (ch != NULL) { 4036f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4037f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4038f8829a4aSRandall Stewart /* break to abort land */ 4039f8829a4aSRandall Stewart break; 4040f8829a4aSRandall Stewart } 4041f8829a4aSRandall Stewart switch (ch->chunk_type) { 4042c58e60beSMichael Tuexen case SCTP_INIT: 4043c58e60beSMichael Tuexen contains_init_chunk = 1; 4044c58e60beSMichael Tuexen break; 4045d55b0b1bSRandall Stewart case SCTP_COOKIE_ECHO: 4046d55b0b1bSRandall Stewart /* We hit here only if the assoc is being freed */ 4047d55b0b1bSRandall Stewart return; 4048f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED: 4049f8829a4aSRandall Stewart /* we don't respond to pkt-dropped */ 4050f8829a4aSRandall Stewart return; 4051f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION: 4052f8829a4aSRandall Stewart /* we don't respond with an ABORT to an ABORT */ 4053f8829a4aSRandall Stewart return; 4054f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE: 4055f8829a4aSRandall Stewart /* 4056f8829a4aSRandall Stewart * we ignore it since we are not waiting for it and 4057f8829a4aSRandall Stewart * peer is gone 4058f8829a4aSRandall Stewart */ 4059f8829a4aSRandall Stewart return; 4060f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK: 4061b1754ad1SMichael Tuexen sctp_send_shutdown_complete2(src, dst, sh, 4062f30ac432SMichael Tuexen use_mflowid, mflowid, 4063f30ac432SMichael Tuexen vrf_id, port); 4064f8829a4aSRandall Stewart return; 4065f8829a4aSRandall Stewart default: 4066f8829a4aSRandall Stewart break; 4067f8829a4aSRandall Stewart } 4068f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4069f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4070f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *) & chunk_buf); 4071f8829a4aSRandall Stewart } 4072c58e60beSMichael Tuexen if ((SCTP_BASE_SYSCTL(sctp_blackhole) == 0) || 4073c58e60beSMichael Tuexen ((SCTP_BASE_SYSCTL(sctp_blackhole) == 1) && 4074c58e60beSMichael Tuexen (contains_init_chunk == 0))) { 4075b1754ad1SMichael Tuexen sctp_send_abort(m, iphlen, src, dst, sh, 0, NULL, 4076f30ac432SMichael Tuexen use_mflowid, mflowid, 4077f30ac432SMichael Tuexen vrf_id, port); 4078f8829a4aSRandall Stewart } 4079c58e60beSMichael Tuexen } 4080f8829a4aSRandall Stewart 4081f8829a4aSRandall Stewart /* 4082f8829a4aSRandall Stewart * check the inbound datagram to make sure there is not an abort inside it, 4083f8829a4aSRandall Stewart * if there is return 1, else return 0. 4084f8829a4aSRandall Stewart */ 4085f8829a4aSRandall Stewart int 4086f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t * vtagfill) 4087f8829a4aSRandall Stewart { 4088f8829a4aSRandall Stewart struct sctp_chunkhdr *ch; 4089f8829a4aSRandall Stewart struct sctp_init_chunk *init_chk, chunk_buf; 4090f8829a4aSRandall Stewart int offset; 4091f8829a4aSRandall Stewart unsigned int chk_length; 4092f8829a4aSRandall Stewart 4093f8829a4aSRandall Stewart offset = iphlen + sizeof(struct sctphdr); 4094f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), 4095f8829a4aSRandall Stewart (uint8_t *) & chunk_buf); 4096f8829a4aSRandall Stewart while (ch != NULL) { 4097f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 4098f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 4099f8829a4aSRandall Stewart /* packet is probably corrupt */ 4100f8829a4aSRandall Stewart break; 4101f8829a4aSRandall Stewart } 4102f8829a4aSRandall Stewart /* we seem to be ok, is it an abort? */ 4103f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) { 4104f8829a4aSRandall Stewart /* yep, tell them */ 4105f8829a4aSRandall Stewart return (1); 4106f8829a4aSRandall Stewart } 4107f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_INITIATION) { 4108f8829a4aSRandall Stewart /* need to update the Vtag */ 4109f8829a4aSRandall Stewart init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 4110f8829a4aSRandall Stewart offset, sizeof(*init_chk), (uint8_t *) & chunk_buf); 4111f8829a4aSRandall Stewart if (init_chk != NULL) { 4112f8829a4aSRandall Stewart *vtagfill = ntohl(init_chk->init.initiate_tag); 4113f8829a4aSRandall Stewart } 4114f8829a4aSRandall Stewart } 4115f8829a4aSRandall Stewart /* Nope, move to the next chunk */ 4116f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 4117f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 4118f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *) & chunk_buf); 4119f8829a4aSRandall Stewart } 4120f8829a4aSRandall Stewart return (0); 4121f8829a4aSRandall Stewart } 4122f8829a4aSRandall Stewart 4123f8829a4aSRandall Stewart /* 4124f8829a4aSRandall Stewart * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id 4125f8829a4aSRandall Stewart * set (i.e. it's 0) so, create this function to compare link local scopes 4126f8829a4aSRandall Stewart */ 41275e2c2d87SRandall Stewart #ifdef INET6 4128f8829a4aSRandall Stewart uint32_t 4129f8829a4aSRandall Stewart sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2) 4130f8829a4aSRandall Stewart { 4131f8829a4aSRandall Stewart struct sockaddr_in6 a, b; 4132f8829a4aSRandall Stewart 4133f8829a4aSRandall Stewart /* save copies */ 4134f8829a4aSRandall Stewart a = *addr1; 4135f8829a4aSRandall Stewart b = *addr2; 4136f8829a4aSRandall Stewart 4137f8829a4aSRandall Stewart if (a.sin6_scope_id == 0) 4138f8829a4aSRandall Stewart if (sa6_recoverscope(&a)) { 4139f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4140f8829a4aSRandall Stewart return (0); 4141f8829a4aSRandall Stewart } 4142f8829a4aSRandall Stewart if (b.sin6_scope_id == 0) 4143f8829a4aSRandall Stewart if (sa6_recoverscope(&b)) { 4144f8829a4aSRandall Stewart /* can't get scope, so can't match */ 4145f8829a4aSRandall Stewart return (0); 4146f8829a4aSRandall Stewart } 4147f8829a4aSRandall Stewart if (a.sin6_scope_id != b.sin6_scope_id) 4148f8829a4aSRandall Stewart return (0); 4149f8829a4aSRandall Stewart 4150f8829a4aSRandall Stewart return (1); 4151f8829a4aSRandall Stewart } 4152f8829a4aSRandall Stewart 4153f8829a4aSRandall Stewart /* 4154f8829a4aSRandall Stewart * returns a sockaddr_in6 with embedded scope recovered and removed 4155f8829a4aSRandall Stewart */ 4156f8829a4aSRandall Stewart struct sockaddr_in6 * 4157f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store) 4158f8829a4aSRandall Stewart { 4159f8829a4aSRandall Stewart /* check and strip embedded scope junk */ 4160f8829a4aSRandall Stewart if (addr->sin6_family == AF_INET6) { 4161f8829a4aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) { 4162f8829a4aSRandall Stewart if (addr->sin6_scope_id == 0) { 4163f8829a4aSRandall Stewart *store = *addr; 4164f8829a4aSRandall Stewart if (!sa6_recoverscope(store)) { 4165f8829a4aSRandall Stewart /* use the recovered scope */ 4166f8829a4aSRandall Stewart addr = store; 4167f8829a4aSRandall Stewart } 4168f42a358aSRandall Stewart } else { 4169f8829a4aSRandall Stewart /* else, return the original "to" addr */ 4170f42a358aSRandall Stewart in6_clearscope(&addr->sin6_addr); 4171f8829a4aSRandall Stewart } 4172f8829a4aSRandall Stewart } 4173f8829a4aSRandall Stewart } 4174f8829a4aSRandall Stewart return (addr); 4175f8829a4aSRandall Stewart } 4176f8829a4aSRandall Stewart 41775e2c2d87SRandall Stewart #endif 41785e2c2d87SRandall Stewart 4179f8829a4aSRandall Stewart /* 4180f8829a4aSRandall Stewart * are the two addresses the same? currently a "scopeless" check returns: 1 4181f8829a4aSRandall Stewart * if same, 0 if not 4182f8829a4aSRandall Stewart */ 418372fb6fdbSRandall Stewart int 4184f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2) 4185f8829a4aSRandall Stewart { 4186f8829a4aSRandall Stewart 4187f8829a4aSRandall Stewart /* must be valid */ 4188f8829a4aSRandall Stewart if (sa1 == NULL || sa2 == NULL) 4189f8829a4aSRandall Stewart return (0); 4190f8829a4aSRandall Stewart 4191f8829a4aSRandall Stewart /* must be the same family */ 4192f8829a4aSRandall Stewart if (sa1->sa_family != sa2->sa_family) 4193f8829a4aSRandall Stewart return (0); 4194f8829a4aSRandall Stewart 41955e2c2d87SRandall Stewart switch (sa1->sa_family) { 41965e2c2d87SRandall Stewart #ifdef INET6 41975e2c2d87SRandall Stewart case AF_INET6: 41985e2c2d87SRandall Stewart { 4199f8829a4aSRandall Stewart /* IPv6 addresses */ 4200f8829a4aSRandall Stewart struct sockaddr_in6 *sin6_1, *sin6_2; 4201f8829a4aSRandall Stewart 4202f8829a4aSRandall Stewart sin6_1 = (struct sockaddr_in6 *)sa1; 4203f8829a4aSRandall Stewart sin6_2 = (struct sockaddr_in6 *)sa2; 4204c54a18d2SRandall Stewart return (SCTP6_ARE_ADDR_EQUAL(sin6_1, 4205c54a18d2SRandall Stewart sin6_2)); 42065e2c2d87SRandall Stewart } 42075e2c2d87SRandall Stewart #endif 4208ea5eba11SMichael Tuexen #ifdef INET 42095e2c2d87SRandall Stewart case AF_INET: 42105e2c2d87SRandall Stewart { 4211f8829a4aSRandall Stewart /* IPv4 addresses */ 4212f8829a4aSRandall Stewart struct sockaddr_in *sin_1, *sin_2; 4213f8829a4aSRandall Stewart 4214f8829a4aSRandall Stewart sin_1 = (struct sockaddr_in *)sa1; 4215f8829a4aSRandall Stewart sin_2 = (struct sockaddr_in *)sa2; 4216f8829a4aSRandall Stewart return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr); 42175e2c2d87SRandall Stewart } 4218ea5eba11SMichael Tuexen #endif 42195e2c2d87SRandall Stewart default: 4220f8829a4aSRandall Stewart /* we don't do these... */ 4221f8829a4aSRandall Stewart return (0); 4222f8829a4aSRandall Stewart } 4223f8829a4aSRandall Stewart } 4224f8829a4aSRandall Stewart 4225f8829a4aSRandall Stewart void 4226f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa) 4227f8829a4aSRandall Stewart { 42285e2c2d87SRandall Stewart #ifdef INET6 42297d32aa0cSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 4230f8829a4aSRandall Stewart 42315e2c2d87SRandall Stewart #endif 42325e2c2d87SRandall Stewart 42335e2c2d87SRandall Stewart switch (sa->sa_family) { 42345e2c2d87SRandall Stewart #ifdef INET6 42355e2c2d87SRandall Stewart case AF_INET6: 42365e2c2d87SRandall Stewart { 4237ad81507eSRandall Stewart struct sockaddr_in6 *sin6; 4238ad81507eSRandall Stewart 4239f8829a4aSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 4240ad81507eSRandall Stewart SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", 42417d32aa0cSBjoern A. Zeeb ip6_sprintf(ip6buf, &sin6->sin6_addr), 42427d32aa0cSBjoern A. Zeeb ntohs(sin6->sin6_port), 4243f8829a4aSRandall Stewart sin6->sin6_scope_id); 42445e2c2d87SRandall Stewart break; 42455e2c2d87SRandall Stewart } 42465e2c2d87SRandall Stewart #endif 4247ea5eba11SMichael Tuexen #ifdef INET 42485e2c2d87SRandall Stewart case AF_INET: 42495e2c2d87SRandall Stewart { 4250f8829a4aSRandall Stewart struct sockaddr_in *sin; 4251f8829a4aSRandall Stewart unsigned char *p; 4252f8829a4aSRandall Stewart 4253f8829a4aSRandall Stewart sin = (struct sockaddr_in *)sa; 4254f8829a4aSRandall Stewart p = (unsigned char *)&sin->sin_addr; 4255ad81507eSRandall Stewart SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n", 4256f8829a4aSRandall Stewart p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); 42575e2c2d87SRandall Stewart break; 42585e2c2d87SRandall Stewart } 4259ea5eba11SMichael Tuexen #endif 42605e2c2d87SRandall Stewart default: 4261ad81507eSRandall Stewart SCTP_PRINTF("?\n"); 42625e2c2d87SRandall Stewart break; 4263f8829a4aSRandall Stewart } 4264f8829a4aSRandall Stewart } 4265f8829a4aSRandall Stewart 4266f8829a4aSRandall Stewart void 4267f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, 4268f8829a4aSRandall Stewart struct sctp_inpcb *new_inp, 4269d06c82f1SRandall Stewart struct sctp_tcb *stcb, 4270d06c82f1SRandall Stewart int waitflags) 4271f8829a4aSRandall Stewart { 4272f8829a4aSRandall Stewart /* 4273f8829a4aSRandall Stewart * go through our old INP and pull off any control structures that 4274f8829a4aSRandall Stewart * belong to stcb and move then to the new inp. 4275f8829a4aSRandall Stewart */ 4276f8829a4aSRandall Stewart struct socket *old_so, *new_so; 4277f8829a4aSRandall Stewart struct sctp_queued_to_read *control, *nctl; 4278f8829a4aSRandall Stewart struct sctp_readhead tmp_queue; 4279f8829a4aSRandall Stewart struct mbuf *m; 4280bff64a4dSRandall Stewart int error = 0; 4281f8829a4aSRandall Stewart 4282f8829a4aSRandall Stewart old_so = old_inp->sctp_socket; 4283f8829a4aSRandall Stewart new_so = new_inp->sctp_socket; 4284f8829a4aSRandall Stewart TAILQ_INIT(&tmp_queue); 4285d06c82f1SRandall Stewart error = sblock(&old_so->so_rcv, waitflags); 4286f8829a4aSRandall Stewart if (error) { 4287f8829a4aSRandall Stewart /* 4288f8829a4aSRandall Stewart * Gak, can't get sblock, we have a problem. data will be 4289f8829a4aSRandall Stewart * left stranded.. and we don't dare look at it since the 4290f8829a4aSRandall Stewart * other thread may be reading something. Oh well, its a 4291f8829a4aSRandall Stewart * screwed up app that does a peeloff OR a accept while 4292f8829a4aSRandall Stewart * reading from the main socket... actually its only the 4293f8829a4aSRandall Stewart * peeloff() case, since I think read will fail on a 4294f8829a4aSRandall Stewart * listening socket.. 4295f8829a4aSRandall Stewart */ 4296f8829a4aSRandall Stewart return; 4297f8829a4aSRandall Stewart } 4298f8829a4aSRandall Stewart /* lock the socket buffers */ 4299f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(old_inp); 43004a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) { 4301f8829a4aSRandall Stewart /* Pull off all for out target stcb */ 4302f8829a4aSRandall Stewart if (control->stcb == stcb) { 4303f8829a4aSRandall Stewart /* remove it we want it */ 4304f8829a4aSRandall Stewart TAILQ_REMOVE(&old_inp->read_queue, control, next); 4305f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&tmp_queue, control, next); 4306f8829a4aSRandall Stewart m = control->data; 4307f8829a4aSRandall Stewart while (m) { 4308b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4309139bc87fSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 431080fefe0aSRandall Stewart } 4311f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &old_so->so_rcv, m); 4312b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4313f8829a4aSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 431480fefe0aSRandall Stewart } 4315139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4316f8829a4aSRandall Stewart } 4317f8829a4aSRandall Stewart } 4318f8829a4aSRandall Stewart } 4319f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(old_inp); 4320f8829a4aSRandall Stewart /* Remove the sb-lock on the old socket */ 4321f8829a4aSRandall Stewart 4322f8829a4aSRandall Stewart sbunlock(&old_so->so_rcv); 4323f8829a4aSRandall Stewart /* Now we move them over to the new socket buffer */ 4324f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(new_inp); 43254a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) { 4326f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next); 4327f8829a4aSRandall Stewart m = control->data; 4328f8829a4aSRandall Stewart while (m) { 4329b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4330139bc87fSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 433180fefe0aSRandall Stewart } 4332f8829a4aSRandall Stewart sctp_sballoc(stcb, &new_so->so_rcv, m); 4333b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4334f8829a4aSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 433580fefe0aSRandall Stewart } 4336139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4337f8829a4aSRandall Stewart } 4338f8829a4aSRandall Stewart } 4339f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(new_inp); 4340f8829a4aSRandall Stewart } 4341f8829a4aSRandall Stewart 4342f8829a4aSRandall Stewart void 4343f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp, 4344f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4345f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4346f8829a4aSRandall Stewart struct sockbuf *sb, 4347ceaad40aSRandall Stewart int end, 4348cfde3ff7SRandall Stewart int inp_read_lock_held, 4349ceaad40aSRandall Stewart int so_locked 4350ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4351ceaad40aSRandall Stewart SCTP_UNUSED 4352ceaad40aSRandall Stewart #endif 4353ceaad40aSRandall Stewart ) 4354f8829a4aSRandall Stewart { 4355f8829a4aSRandall Stewart /* 4356f8829a4aSRandall Stewart * Here we must place the control on the end of the socket read 4357f8829a4aSRandall Stewart * queue AND increment sb_cc so that select will work properly on 4358f8829a4aSRandall Stewart * read. 4359f8829a4aSRandall Stewart */ 4360f8829a4aSRandall Stewart struct mbuf *m, *prev = NULL; 4361f8829a4aSRandall Stewart 436203b0b021SRandall Stewart if (inp == NULL) { 436303b0b021SRandall Stewart /* Gak, TSNH!! */ 4364a5d547adSRandall Stewart #ifdef INVARIANTS 436503b0b021SRandall Stewart panic("Gak, inp NULL on add_to_readq"); 436603b0b021SRandall Stewart #endif 436703b0b021SRandall Stewart return; 436803b0b021SRandall Stewart } 4369cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4370f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4371cd1386abSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 4372cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4373cd1386abSMichael Tuexen if (control->data) { 4374cd1386abSMichael Tuexen sctp_m_freem(control->data); 4375cd1386abSMichael Tuexen control->data = NULL; 4376cd1386abSMichael Tuexen } 4377cd1386abSMichael Tuexen SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control); 4378cd1386abSMichael Tuexen if (inp_read_lock_held == 0) 4379cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4380cd1386abSMichael Tuexen return; 4381cd1386abSMichael Tuexen } 438242551e99SRandall Stewart if (!(control->spec_flags & M_NOTIFICATION)) { 4383a5d547adSRandall Stewart atomic_add_int(&inp->total_recvs, 1); 438442551e99SRandall Stewart if (!control->do_not_ref_stcb) { 4385a5d547adSRandall Stewart atomic_add_int(&stcb->total_recvs, 1); 438642551e99SRandall Stewart } 438742551e99SRandall Stewart } 4388f8829a4aSRandall Stewart m = control->data; 4389f8829a4aSRandall Stewart control->held_length = 0; 4390f8829a4aSRandall Stewart control->length = 0; 4391f8829a4aSRandall Stewart while (m) { 4392139bc87fSRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 4393f8829a4aSRandall Stewart /* Skip mbufs with NO length */ 4394f8829a4aSRandall Stewart if (prev == NULL) { 4395f8829a4aSRandall Stewart /* First one */ 4396f8829a4aSRandall Stewart control->data = sctp_m_free(m); 4397f8829a4aSRandall Stewart m = control->data; 4398f8829a4aSRandall Stewart } else { 4399139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 4400139bc87fSRandall Stewart m = SCTP_BUF_NEXT(prev); 4401f8829a4aSRandall Stewart } 4402f8829a4aSRandall Stewart if (m == NULL) { 4403c2ede4b3SMartin Blapp control->tail_mbuf = prev; 4404f8829a4aSRandall Stewart } 4405f8829a4aSRandall Stewart continue; 4406f8829a4aSRandall Stewart } 4407f8829a4aSRandall Stewart prev = m; 4408b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4409139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 441080fefe0aSRandall Stewart } 4411f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, m); 4412b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4413f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 441480fefe0aSRandall Stewart } 4415139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 4416139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4417f8829a4aSRandall Stewart } 4418f8829a4aSRandall Stewart if (prev != NULL) { 4419f8829a4aSRandall Stewart control->tail_mbuf = prev; 4420f8829a4aSRandall Stewart } else { 4421139bc87fSRandall Stewart /* Everything got collapsed out?? */ 4422cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4423cd1386abSMichael Tuexen SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control); 4424cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 442547a490cbSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4426f8829a4aSRandall Stewart return; 4427f8829a4aSRandall Stewart } 4428f8829a4aSRandall Stewart if (end) { 4429f8829a4aSRandall Stewart control->end_added = 1; 4430f8829a4aSRandall Stewart } 4431f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&inp->read_queue, control, next); 4432cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4433f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4434f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 443517205eccSRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 443617205eccSRandall Stewart SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); 4437ceaad40aSRandall Stewart } else { 4438ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4439ceaad40aSRandall Stewart struct socket *so; 4440ceaad40aSRandall Stewart 4441ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4442ceaad40aSRandall Stewart if (!so_locked) { 444360990c0cSMichael Tuexen if (stcb) { 4444ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4445ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 444660990c0cSMichael Tuexen } 4447ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 444860990c0cSMichael Tuexen if (stcb) { 4449ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4450ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 445160990c0cSMichael Tuexen } 4452ceaad40aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4453ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4454ceaad40aSRandall Stewart return; 4455ceaad40aSRandall Stewart } 4456ceaad40aSRandall Stewart } 4457ceaad40aSRandall Stewart #endif 4458f8829a4aSRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 4459ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4460ceaad40aSRandall Stewart if (!so_locked) { 4461ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4462ceaad40aSRandall Stewart } 4463ceaad40aSRandall Stewart #endif 4464ceaad40aSRandall Stewart } 4465f8829a4aSRandall Stewart } 4466f8829a4aSRandall Stewart } 4467f8829a4aSRandall Stewart 4468f8829a4aSRandall Stewart 4469f8829a4aSRandall Stewart int 4470f8829a4aSRandall Stewart sctp_append_to_readq(struct sctp_inpcb *inp, 4471f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4472f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4473f8829a4aSRandall Stewart struct mbuf *m, 4474f8829a4aSRandall Stewart int end, 4475f8829a4aSRandall Stewart int ctls_cumack, 4476f8829a4aSRandall Stewart struct sockbuf *sb) 4477f8829a4aSRandall Stewart { 4478f8829a4aSRandall Stewart /* 4479f8829a4aSRandall Stewart * A partial delivery API event is underway. OR we are appending on 4480f8829a4aSRandall Stewart * the reassembly queue. 4481f8829a4aSRandall Stewart * 4482f8829a4aSRandall Stewart * If PDAPI this means we need to add m to the end of the data. 4483f8829a4aSRandall Stewart * Increase the length in the control AND increment the sb_cc. 4484f8829a4aSRandall Stewart * Otherwise sb is NULL and all we need to do is put it at the end 4485f8829a4aSRandall Stewart * of the mbuf chain. 4486f8829a4aSRandall Stewart */ 4487f8829a4aSRandall Stewart int len = 0; 4488f8829a4aSRandall Stewart struct mbuf *mm, *tail = NULL, *prev = NULL; 4489f8829a4aSRandall Stewart 4490f8829a4aSRandall Stewart if (inp) { 4491f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4492f8829a4aSRandall Stewart } 4493f8829a4aSRandall Stewart if (control == NULL) { 4494f8829a4aSRandall Stewart get_out: 4495f8829a4aSRandall Stewart if (inp) { 4496f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4497f8829a4aSRandall Stewart } 4498f8829a4aSRandall Stewart return (-1); 4499f8829a4aSRandall Stewart } 4500cd1386abSMichael Tuexen if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) { 4501cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 450260990c0cSMichael Tuexen return (0); 4503cd1386abSMichael Tuexen } 4504139bc87fSRandall Stewart if (control->end_added) { 4505f8829a4aSRandall Stewart /* huh this one is complete? */ 4506f8829a4aSRandall Stewart goto get_out; 4507f8829a4aSRandall Stewart } 4508f8829a4aSRandall Stewart mm = m; 4509f8829a4aSRandall Stewart if (mm == NULL) { 4510f8829a4aSRandall Stewart goto get_out; 4511f8829a4aSRandall Stewart } 4512f8829a4aSRandall Stewart while (mm) { 4513139bc87fSRandall Stewart if (SCTP_BUF_LEN(mm) == 0) { 4514f8829a4aSRandall Stewart /* Skip mbufs with NO lenght */ 4515f8829a4aSRandall Stewart if (prev == NULL) { 4516f8829a4aSRandall Stewart /* First one */ 4517f8829a4aSRandall Stewart m = sctp_m_free(mm); 4518f8829a4aSRandall Stewart mm = m; 4519f8829a4aSRandall Stewart } else { 4520139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(mm); 4521139bc87fSRandall Stewart mm = SCTP_BUF_NEXT(prev); 4522f8829a4aSRandall Stewart } 4523f8829a4aSRandall Stewart continue; 4524f8829a4aSRandall Stewart } 4525f8829a4aSRandall Stewart prev = mm; 4526139bc87fSRandall Stewart len += SCTP_BUF_LEN(mm); 4527f8829a4aSRandall Stewart if (sb) { 4528b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4529139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(mm)); 453080fefe0aSRandall Stewart } 4531f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, mm); 4532b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4533f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 453480fefe0aSRandall Stewart } 4535f8829a4aSRandall Stewart } 4536139bc87fSRandall Stewart mm = SCTP_BUF_NEXT(mm); 4537f8829a4aSRandall Stewart } 4538f8829a4aSRandall Stewart if (prev) { 4539f8829a4aSRandall Stewart tail = prev; 4540f8829a4aSRandall Stewart } else { 4541f8829a4aSRandall Stewart /* Really there should always be a prev */ 4542f8829a4aSRandall Stewart if (m == NULL) { 4543f8829a4aSRandall Stewart /* Huh nothing left? */ 4544a5d547adSRandall Stewart #ifdef INVARIANTS 4545f8829a4aSRandall Stewart panic("Nothing left to add?"); 4546f8829a4aSRandall Stewart #else 4547f8829a4aSRandall Stewart goto get_out; 4548f8829a4aSRandall Stewart #endif 4549f8829a4aSRandall Stewart } 4550f8829a4aSRandall Stewart tail = m; 4551f8829a4aSRandall Stewart } 4552f8829a4aSRandall Stewart if (control->tail_mbuf) { 4553f8829a4aSRandall Stewart /* append */ 4554139bc87fSRandall Stewart SCTP_BUF_NEXT(control->tail_mbuf) = m; 4555f8829a4aSRandall Stewart control->tail_mbuf = tail; 4556f8829a4aSRandall Stewart } else { 4557f8829a4aSRandall Stewart /* nothing there */ 4558a5d547adSRandall Stewart #ifdef INVARIANTS 4559f8829a4aSRandall Stewart if (control->data != NULL) { 4560f8829a4aSRandall Stewart panic("This should NOT happen"); 4561f8829a4aSRandall Stewart } 4562f8829a4aSRandall Stewart #endif 4563f8829a4aSRandall Stewart control->data = m; 4564f8829a4aSRandall Stewart control->tail_mbuf = tail; 4565f8829a4aSRandall Stewart } 456618e198d3SRandall Stewart atomic_add_int(&control->length, len); 456718e198d3SRandall Stewart if (end) { 456818e198d3SRandall Stewart /* message is complete */ 456918e198d3SRandall Stewart if (stcb && (control == stcb->asoc.control_pdapi)) { 457018e198d3SRandall Stewart stcb->asoc.control_pdapi = NULL; 457118e198d3SRandall Stewart } 457218e198d3SRandall Stewart control->held_length = 0; 457318e198d3SRandall Stewart control->end_added = 1; 457418e198d3SRandall Stewart } 4575ad81507eSRandall Stewart if (stcb == NULL) { 4576ad81507eSRandall Stewart control->do_not_ref_stcb = 1; 4577ad81507eSRandall Stewart } 4578f8829a4aSRandall Stewart /* 4579f8829a4aSRandall Stewart * When we are appending in partial delivery, the cum-ack is used 4580f8829a4aSRandall Stewart * for the actual pd-api highest tsn on this mbuf. The true cum-ack 4581f8829a4aSRandall Stewart * is populated in the outbound sinfo structure from the true cumack 4582f8829a4aSRandall Stewart * if the association exists... 4583f8829a4aSRandall Stewart */ 4584f8829a4aSRandall Stewart control->sinfo_tsn = control->sinfo_cumtsn = ctls_cumack; 4585f8829a4aSRandall Stewart if (inp) { 4586f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4587f8829a4aSRandall Stewart } 4588f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 458917205eccSRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 459017205eccSRandall Stewart SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); 4591ceaad40aSRandall Stewart } else { 4592ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4593ceaad40aSRandall Stewart struct socket *so; 4594ceaad40aSRandall Stewart 4595ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 459660990c0cSMichael Tuexen if (stcb) { 4597ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4598ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 459960990c0cSMichael Tuexen } 4600ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 460160990c0cSMichael Tuexen if (stcb) { 4602ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4603ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 460460990c0cSMichael Tuexen } 4605ceaad40aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4606ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4607ceaad40aSRandall Stewart return (0); 4608ceaad40aSRandall Stewart } 4609ceaad40aSRandall Stewart #endif 4610f8829a4aSRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 4611ceaad40aSRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4612ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4613ceaad40aSRandall Stewart #endif 4614ceaad40aSRandall Stewart } 4615f8829a4aSRandall Stewart } 4616f8829a4aSRandall Stewart return (0); 4617f8829a4aSRandall Stewart } 4618f8829a4aSRandall Stewart 4619f8829a4aSRandall Stewart 4620f8829a4aSRandall Stewart 4621f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF 4622f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4623f8829a4aSRandall Stewart */ 4624f8829a4aSRandall Stewart 4625f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF 4626f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4627f8829a4aSRandall Stewart */ 4628f8829a4aSRandall Stewart 4629f8829a4aSRandall Stewart struct mbuf * 4630f8829a4aSRandall Stewart sctp_generate_invmanparam(int err) 4631f8829a4aSRandall Stewart { 4632f8829a4aSRandall Stewart /* Return a MBUF with a invalid mandatory parameter */ 4633f8829a4aSRandall Stewart struct mbuf *m; 4634f8829a4aSRandall Stewart 4635f8829a4aSRandall Stewart m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 4636f8829a4aSRandall Stewart if (m) { 4637f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 4638f8829a4aSRandall Stewart 4639139bc87fSRandall Stewart SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr); 4640f8829a4aSRandall Stewart ph = mtod(m, struct sctp_paramhdr *); 4641f8829a4aSRandall Stewart ph->param_length = htons(sizeof(struct sctp_paramhdr)); 4642f8829a4aSRandall Stewart ph->param_type = htons(err); 4643f8829a4aSRandall Stewart } 4644f8829a4aSRandall Stewart return (m); 4645f8829a4aSRandall Stewart } 4646f8829a4aSRandall Stewart 4647f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING 4648f8829a4aSRandall Stewart void 4649f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, 4650f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, int chk_cnt) 4651f8829a4aSRandall Stewart { 4652f8829a4aSRandall Stewart if (tp1->data == NULL) { 4653f8829a4aSRandall Stewart return; 4654f8829a4aSRandall Stewart } 4655f8829a4aSRandall Stewart asoc->chunks_on_out_queue -= chk_cnt; 4656b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { 4657f8829a4aSRandall Stewart sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, 4658f8829a4aSRandall Stewart asoc->total_output_queue_size, 4659f8829a4aSRandall Stewart tp1->book_size, 4660f8829a4aSRandall Stewart 0, 4661f8829a4aSRandall Stewart tp1->mbcnt); 466280fefe0aSRandall Stewart } 4663f8829a4aSRandall Stewart if (asoc->total_output_queue_size >= tp1->book_size) { 466444b7479bSRandall Stewart atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size); 4665f8829a4aSRandall Stewart } else { 4666f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 4667f8829a4aSRandall Stewart } 4668f8829a4aSRandall Stewart 4669f8829a4aSRandall Stewart if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || 4670f8829a4aSRandall Stewart ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { 4671f8829a4aSRandall Stewart if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { 4672f8829a4aSRandall Stewart stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size; 4673f8829a4aSRandall Stewart } else { 4674f8829a4aSRandall Stewart stcb->sctp_socket->so_snd.sb_cc = 0; 4675f8829a4aSRandall Stewart 4676f8829a4aSRandall Stewart } 4677f8829a4aSRandall Stewart } 4678f8829a4aSRandall Stewart } 4679f8829a4aSRandall Stewart 4680f8829a4aSRandall Stewart #endif 4681f8829a4aSRandall Stewart 4682f8829a4aSRandall Stewart int 4683f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, 46841edc9dbaSMichael Tuexen uint8_t sent, int so_locked 4685ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4686ceaad40aSRandall Stewart SCTP_UNUSED 4687ceaad40aSRandall Stewart #endif 4688ceaad40aSRandall Stewart ) 4689f8829a4aSRandall Stewart { 46900c0982b8SRandall Stewart struct sctp_stream_out *strq; 46914a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk = NULL, *tp2; 46920c0982b8SRandall Stewart struct sctp_stream_queue_pending *sp; 46930c0982b8SRandall Stewart uint16_t stream = 0, seq = 0; 46940c0982b8SRandall Stewart uint8_t foundeom = 0; 4695f8829a4aSRandall Stewart int ret_sz = 0; 4696f8829a4aSRandall Stewart int notdone; 46970c0982b8SRandall Stewart int do_wakeup_routine = 0; 4698f8829a4aSRandall Stewart 46990c0982b8SRandall Stewart stream = tp1->rec.data.stream_number; 47000c0982b8SRandall Stewart seq = tp1->rec.data.stream_seq; 4701f8829a4aSRandall Stewart do { 4702f8829a4aSRandall Stewart ret_sz += tp1->book_size; 47030c0982b8SRandall Stewart if (tp1->data != NULL) { 47048933fa13SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 4705830d754dSRandall Stewart sctp_flight_size_decrease(tp1); 4706830d754dSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 47078933fa13SRandall Stewart } 47088933fa13SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 47090c0982b8SRandall Stewart stcb->asoc.peers_rwnd += tp1->send_size; 47100c0982b8SRandall Stewart stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); 47111edc9dbaSMichael Tuexen if (sent) { 47121edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 47131edc9dbaSMichael Tuexen } else { 47141edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 47151edc9dbaSMichael Tuexen } 47162f99457bSMichael Tuexen if (tp1->data) { 4717f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 4718f8829a4aSRandall Stewart tp1->data = NULL; 47192f99457bSMichael Tuexen } 47200c0982b8SRandall Stewart do_wakeup_routine = 1; 4721f8829a4aSRandall Stewart if (PR_SCTP_BUF_ENABLED(tp1->flags)) { 4722f8829a4aSRandall Stewart stcb->asoc.sent_queue_cnt_removeable--; 4723f8829a4aSRandall Stewart } 4724f8829a4aSRandall Stewart } 47258933fa13SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 4726f8829a4aSRandall Stewart if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 4727f8829a4aSRandall Stewart SCTP_DATA_NOT_FRAG) { 4728f8829a4aSRandall Stewart /* not frag'ed we ae done */ 4729f8829a4aSRandall Stewart notdone = 0; 4730f8829a4aSRandall Stewart foundeom = 1; 4731f8829a4aSRandall Stewart } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 4732f8829a4aSRandall Stewart /* end of frag, we are done */ 4733f8829a4aSRandall Stewart notdone = 0; 4734f8829a4aSRandall Stewart foundeom = 1; 4735f8829a4aSRandall Stewart } else { 4736f8829a4aSRandall Stewart /* 4737f8829a4aSRandall Stewart * Its a begin or middle piece, we must mark all of 4738f8829a4aSRandall Stewart * it 4739f8829a4aSRandall Stewart */ 4740f8829a4aSRandall Stewart notdone = 1; 4741f8829a4aSRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next); 4742f8829a4aSRandall Stewart } 4743f8829a4aSRandall Stewart } while (tp1 && notdone); 47440c0982b8SRandall Stewart if (foundeom == 0) { 4745f8829a4aSRandall Stewart /* 4746f8829a4aSRandall Stewart * The multi-part message was scattered across the send and 4747f8829a4aSRandall Stewart * sent queue. 4748f8829a4aSRandall Stewart */ 47494a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) { 47504a9ef3f8SMichael Tuexen if ((tp1->rec.data.stream_number != stream) || 47514a9ef3f8SMichael Tuexen (tp1->rec.data.stream_seq != seq)) { 47524a9ef3f8SMichael Tuexen break; 47534a9ef3f8SMichael Tuexen } 47540c0982b8SRandall Stewart /* 47550c0982b8SRandall Stewart * save to chk in case we have some on stream out 47560c0982b8SRandall Stewart * queue. If so and we have an un-transmitted one we 47570c0982b8SRandall Stewart * don't have to fudge the TSN. 47580c0982b8SRandall Stewart */ 47590c0982b8SRandall Stewart chk = tp1; 47600c0982b8SRandall Stewart ret_sz += tp1->book_size; 47610c0982b8SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 47621edc9dbaSMichael Tuexen if (sent) { 47631edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_SENT_DG_FAIL, stcb, 0, tp1, so_locked); 47641edc9dbaSMichael Tuexen } else { 47651edc9dbaSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_UNSENT_DG_FAIL, stcb, 0, tp1, so_locked); 47661edc9dbaSMichael Tuexen } 47672f99457bSMichael Tuexen if (tp1->data) { 47680c0982b8SRandall Stewart sctp_m_freem(tp1->data); 47692f99457bSMichael Tuexen tp1->data = NULL; 47702f99457bSMichael Tuexen } 47718933fa13SRandall Stewart /* No flight involved here book the size to 0 */ 47728933fa13SRandall Stewart tp1->book_size = 0; 47730c0982b8SRandall Stewart if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 47740c0982b8SRandall Stewart foundeom = 1; 4775f8829a4aSRandall Stewart } 47760c0982b8SRandall Stewart do_wakeup_routine = 1; 47770c0982b8SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 47780c0982b8SRandall Stewart TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next); 47790c0982b8SRandall Stewart /* 47800c0982b8SRandall Stewart * on to the sent queue so we can wait for it to be 47810c0982b8SRandall Stewart * passed by. 47820c0982b8SRandall Stewart */ 47830c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1, 47840c0982b8SRandall Stewart sctp_next); 47850c0982b8SRandall Stewart stcb->asoc.send_queue_cnt--; 47860c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 47870c0982b8SRandall Stewart } 47880c0982b8SRandall Stewart } 47890c0982b8SRandall Stewart if (foundeom == 0) { 47900c0982b8SRandall Stewart /* 47910c0982b8SRandall Stewart * Still no eom found. That means there is stuff left on the 47920c0982b8SRandall Stewart * stream out queue.. yuck. 47930c0982b8SRandall Stewart */ 47940c0982b8SRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 4795f3b05218SMichael Tuexen strq = &stcb->asoc.strmout[stream]; 4796f3b05218SMichael Tuexen sp = TAILQ_FIRST(&strq->outqueue); 4797f3b05218SMichael Tuexen if (sp != NULL) { 47980c0982b8SRandall Stewart sp->discard_rest = 1; 47990c0982b8SRandall Stewart /* 4800f3b05218SMichael Tuexen * We may need to put a chunk on the queue that 4801f3b05218SMichael Tuexen * holds the TSN that would have been sent with the 4802f3b05218SMichael Tuexen * LAST bit. 48030c0982b8SRandall Stewart */ 48040c0982b8SRandall Stewart if (chk == NULL) { 48050c0982b8SRandall Stewart /* Yep, we have to */ 48060c0982b8SRandall Stewart sctp_alloc_a_chunk(stcb, chk); 48070c0982b8SRandall Stewart if (chk == NULL) { 48080c0982b8SRandall Stewart /* 4809f3b05218SMichael Tuexen * we are hosed. All we can do is 4810f3b05218SMichael Tuexen * nothing.. which will cause an 4811f3b05218SMichael Tuexen * abort if the peer is paying 48120c0982b8SRandall Stewart * attention. 48130c0982b8SRandall Stewart */ 48140c0982b8SRandall Stewart goto oh_well; 48150c0982b8SRandall Stewart } 48160c0982b8SRandall Stewart memset(chk, 0, sizeof(*chk)); 48170c0982b8SRandall Stewart chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG; 48180c0982b8SRandall Stewart chk->sent = SCTP_FORWARD_TSN_SKIP; 48190c0982b8SRandall Stewart chk->asoc = &stcb->asoc; 4820f3b05218SMichael Tuexen chk->rec.data.stream_seq = strq->next_sequence_send; 48210c0982b8SRandall Stewart chk->rec.data.stream_number = sp->stream; 48220c0982b8SRandall Stewart chk->rec.data.payloadtype = sp->ppid; 48230c0982b8SRandall Stewart chk->rec.data.context = sp->context; 48240c0982b8SRandall Stewart chk->flags = sp->act_flags; 48259eea4a2dSMichael Tuexen if (sp->net) 48260c0982b8SRandall Stewart chk->whoTo = sp->net; 48279eea4a2dSMichael Tuexen else 48289eea4a2dSMichael Tuexen chk->whoTo = stcb->asoc.primary_destination; 48290c0982b8SRandall Stewart atomic_add_int(&chk->whoTo->ref_count, 1); 48300c0982b8SRandall Stewart chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); 48310c0982b8SRandall Stewart stcb->asoc.pr_sctp_cnt++; 48320c0982b8SRandall Stewart chk->pr_sctp_on = 1; 48330c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); 48340c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 48358933fa13SRandall Stewart stcb->asoc.pr_sctp_cnt++; 48360c0982b8SRandall Stewart } else { 48370c0982b8SRandall Stewart chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; 48380c0982b8SRandall Stewart } 4839f3b05218SMichael Tuexen strq->next_sequence_send++; 48400c0982b8SRandall Stewart oh_well: 48410c0982b8SRandall Stewart if (sp->data) { 48420c0982b8SRandall Stewart /* 4843f3b05218SMichael Tuexen * Pull any data to free up the SB and allow 4844f3b05218SMichael Tuexen * sender to "add more" while we will throw 4845f3b05218SMichael Tuexen * away :-) 48460c0982b8SRandall Stewart */ 4847f3b05218SMichael Tuexen sctp_free_spbufspace(stcb, &stcb->asoc, sp); 48480c0982b8SRandall Stewart ret_sz += sp->length; 48490c0982b8SRandall Stewart do_wakeup_routine = 1; 48500c0982b8SRandall Stewart sp->some_taken = 1; 48510c0982b8SRandall Stewart sctp_m_freem(sp->data); 48520c0982b8SRandall Stewart sp->data = NULL; 48530c0982b8SRandall Stewart sp->tail_mbuf = NULL; 4854d07b2ac6SMichael Tuexen sp->length = 0; 48550c0982b8SRandall Stewart } 48560c0982b8SRandall Stewart } 48570c0982b8SRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 48580c0982b8SRandall Stewart } 48590c0982b8SRandall Stewart if (do_wakeup_routine) { 48600c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 48618933fa13SRandall Stewart struct socket *so; 48628933fa13SRandall Stewart 48630c0982b8SRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 48640c0982b8SRandall Stewart if (!so_locked) { 48650c0982b8SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 48660c0982b8SRandall Stewart SCTP_TCB_UNLOCK(stcb); 48670c0982b8SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 48680c0982b8SRandall Stewart SCTP_TCB_LOCK(stcb); 48690c0982b8SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 48700c0982b8SRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 48710c0982b8SRandall Stewart /* assoc was freed while we were unlocked */ 48720c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 48730c0982b8SRandall Stewart return (ret_sz); 48740c0982b8SRandall Stewart } 48750c0982b8SRandall Stewart } 48760c0982b8SRandall Stewart #endif 48770c0982b8SRandall Stewart sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 48780c0982b8SRandall Stewart #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 48790c0982b8SRandall Stewart if (!so_locked) { 48800c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 48810c0982b8SRandall Stewart } 48820c0982b8SRandall Stewart #endif 4883f8829a4aSRandall Stewart } 4884f8829a4aSRandall Stewart return (ret_sz); 4885f8829a4aSRandall Stewart } 4886f8829a4aSRandall Stewart 4887f8829a4aSRandall Stewart /* 4888f8829a4aSRandall Stewart * checks to see if the given address, sa, is one that is currently known by 4889f8829a4aSRandall Stewart * the kernel note: can't distinguish the same address on multiple interfaces 4890f8829a4aSRandall Stewart * and doesn't handle multiple addresses with different zone/scope id's note: 4891f8829a4aSRandall Stewart * ifa_ifwithaddr() compares the entire sockaddr struct 4892f8829a4aSRandall Stewart */ 489342551e99SRandall Stewart struct sctp_ifa * 489480fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, 489580fefe0aSRandall Stewart int holds_lock) 4896f8829a4aSRandall Stewart { 489742551e99SRandall Stewart struct sctp_laddr *laddr; 4898f8829a4aSRandall Stewart 4899ad81507eSRandall Stewart if (holds_lock == 0) { 490042551e99SRandall Stewart SCTP_INP_RLOCK(inp); 4901ad81507eSRandall Stewart } 490242551e99SRandall Stewart LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 490342551e99SRandall Stewart if (laddr->ifa == NULL) 4904f8829a4aSRandall Stewart continue; 490542551e99SRandall Stewart if (addr->sa_family != laddr->ifa->address.sa.sa_family) 490642551e99SRandall Stewart continue; 4907e6194c2eSMichael Tuexen #ifdef INET 490842551e99SRandall Stewart if (addr->sa_family == AF_INET) { 490942551e99SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 491042551e99SRandall Stewart laddr->ifa->address.sin.sin_addr.s_addr) { 491142551e99SRandall Stewart /* found him. */ 4912ad81507eSRandall Stewart if (holds_lock == 0) { 491342551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4914ad81507eSRandall Stewart } 491542551e99SRandall Stewart return (laddr->ifa); 491642551e99SRandall Stewart break; 491742551e99SRandall Stewart } 49185e2c2d87SRandall Stewart } 4919e6194c2eSMichael Tuexen #endif 49205e2c2d87SRandall Stewart #ifdef INET6 49215e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 4922c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 4923c54a18d2SRandall Stewart &laddr->ifa->address.sin6)) { 492442551e99SRandall Stewart /* found him. */ 4925ad81507eSRandall Stewart if (holds_lock == 0) { 492642551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4927ad81507eSRandall Stewart } 492842551e99SRandall Stewart return (laddr->ifa); 492942551e99SRandall Stewart break; 493042551e99SRandall Stewart } 493142551e99SRandall Stewart } 49325e2c2d87SRandall Stewart #endif 493342551e99SRandall Stewart } 4934ad81507eSRandall Stewart if (holds_lock == 0) { 493542551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4936ad81507eSRandall Stewart } 493742551e99SRandall Stewart return (NULL); 493842551e99SRandall Stewart } 4939f8829a4aSRandall Stewart 49406a27c376SRandall Stewart uint32_t 49416a27c376SRandall Stewart sctp_get_ifa_hash_val(struct sockaddr *addr) 49426a27c376SRandall Stewart { 4943ea5eba11SMichael Tuexen switch (addr->sa_family) { 4944ea5eba11SMichael Tuexen #ifdef INET 4945ea5eba11SMichael Tuexen case AF_INET: 4946ea5eba11SMichael Tuexen { 49476a27c376SRandall Stewart struct sockaddr_in *sin; 49486a27c376SRandall Stewart 49496a27c376SRandall Stewart sin = (struct sockaddr_in *)addr; 49506a27c376SRandall Stewart return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); 4951ea5eba11SMichael Tuexen } 4952ea5eba11SMichael Tuexen #endif 4953ea5eba11SMichael Tuexen #ifdef INET6 4954ea5eba11SMichael Tuexen case INET6: 4955ea5eba11SMichael Tuexen { 49566a27c376SRandall Stewart struct sockaddr_in6 *sin6; 49576a27c376SRandall Stewart uint32_t hash_of_addr; 49586a27c376SRandall Stewart 49596a27c376SRandall Stewart sin6 = (struct sockaddr_in6 *)addr; 49606a27c376SRandall Stewart hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + 49616a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[1] + 49626a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[2] + 49636a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[3]); 49646a27c376SRandall Stewart hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); 49656a27c376SRandall Stewart return (hash_of_addr); 49666a27c376SRandall Stewart } 4967ea5eba11SMichael Tuexen #endif 4968ea5eba11SMichael Tuexen default: 4969ea5eba11SMichael Tuexen break; 4970ea5eba11SMichael Tuexen } 49716a27c376SRandall Stewart return (0); 49726a27c376SRandall Stewart } 49736a27c376SRandall Stewart 497442551e99SRandall Stewart struct sctp_ifa * 497542551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) 497642551e99SRandall Stewart { 497742551e99SRandall Stewart struct sctp_ifa *sctp_ifap; 497842551e99SRandall Stewart struct sctp_vrf *vrf; 49796a27c376SRandall Stewart struct sctp_ifalist *hash_head; 49806a27c376SRandall Stewart uint32_t hash_of_addr; 498142551e99SRandall Stewart 498242551e99SRandall Stewart if (holds_lock == 0) 4983c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 498442551e99SRandall Stewart 4985bff64a4dSRandall Stewart vrf = sctp_find_vrf(vrf_id); 4986bff64a4dSRandall Stewart if (vrf == NULL) { 4987df6e0cc3SRandall Stewart stage_right: 4988bff64a4dSRandall Stewart if (holds_lock == 0) 4989c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 4990bff64a4dSRandall Stewart return (NULL); 4991bff64a4dSRandall Stewart } 4992bff64a4dSRandall Stewart hash_of_addr = sctp_get_ifa_hash_val(addr); 4993bff64a4dSRandall Stewart 499417205eccSRandall Stewart hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; 4995bff64a4dSRandall Stewart if (hash_head == NULL) { 4996ad81507eSRandall Stewart SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ", 4997c99efcf6SRandall Stewart hash_of_addr, (uint32_t) vrf->vrf_addr_hashmark, 4998c99efcf6SRandall Stewart (uint32_t) (hash_of_addr & vrf->vrf_addr_hashmark)); 4999bff64a4dSRandall Stewart sctp_print_address(addr); 5000ad81507eSRandall Stewart SCTP_PRINTF("No such bucket for address\n"); 5001bff64a4dSRandall Stewart if (holds_lock == 0) 5002c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5003bff64a4dSRandall Stewart 5004bff64a4dSRandall Stewart return (NULL); 5005bff64a4dSRandall Stewart } 50066a27c376SRandall Stewart LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { 5007bff64a4dSRandall Stewart if (sctp_ifap == NULL) { 5008df6e0cc3SRandall Stewart #ifdef INVARIANTS 5009bff64a4dSRandall Stewart panic("Huh LIST_FOREACH corrupt"); 5010df6e0cc3SRandall Stewart goto stage_right; 5011df6e0cc3SRandall Stewart #else 5012df6e0cc3SRandall Stewart SCTP_PRINTF("LIST corrupt of sctp_ifap's?\n"); 5013df6e0cc3SRandall Stewart goto stage_right; 5014df6e0cc3SRandall Stewart #endif 5015bff64a4dSRandall Stewart } 50166a27c376SRandall Stewart if (addr->sa_family != sctp_ifap->address.sa.sa_family) 50176a27c376SRandall Stewart continue; 5018e6194c2eSMichael Tuexen #ifdef INET 50196a27c376SRandall Stewart if (addr->sa_family == AF_INET) { 50206a27c376SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 50216a27c376SRandall Stewart sctp_ifap->address.sin.sin_addr.s_addr) { 50226a27c376SRandall Stewart /* found him. */ 502342551e99SRandall Stewart if (holds_lock == 0) 5024c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 502542551e99SRandall Stewart return (sctp_ifap); 50266a27c376SRandall Stewart break; 50276a27c376SRandall Stewart } 50285e2c2d87SRandall Stewart } 5029e6194c2eSMichael Tuexen #endif 50305e2c2d87SRandall Stewart #ifdef INET6 50315e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 5032c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 5033c54a18d2SRandall Stewart &sctp_ifap->address.sin6)) { 50346a27c376SRandall Stewart /* found him. */ 50356a27c376SRandall Stewart if (holds_lock == 0) 5036c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 50376a27c376SRandall Stewart return (sctp_ifap); 50386a27c376SRandall Stewart break; 50396a27c376SRandall Stewart } 504042551e99SRandall Stewart } 50415e2c2d87SRandall Stewart #endif 504242551e99SRandall Stewart } 504342551e99SRandall Stewart if (holds_lock == 0) 5044c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 5045f8829a4aSRandall Stewart return (NULL); 5046f8829a4aSRandall Stewart } 5047f8829a4aSRandall Stewart 5048f8829a4aSRandall Stewart static void 50494c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock, 5050f8829a4aSRandall Stewart uint32_t rwnd_req) 5051f8829a4aSRandall Stewart { 5052f8829a4aSRandall Stewart /* User pulled some data, do we need a rwnd update? */ 5053f8829a4aSRandall Stewart int r_unlocked = 0; 5054f8829a4aSRandall Stewart uint32_t dif, rwnd; 5055f8829a4aSRandall Stewart struct socket *so = NULL; 5056f8829a4aSRandall Stewart 5057f8829a4aSRandall Stewart if (stcb == NULL) 5058f8829a4aSRandall Stewart return; 5059f8829a4aSRandall Stewart 506050cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5061f8829a4aSRandall Stewart 506262c1ff9cSRandall Stewart if (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | 506362c1ff9cSRandall Stewart SCTP_STATE_SHUTDOWN_RECEIVED | 50644c9179adSRandall Stewart SCTP_STATE_SHUTDOWN_ACK_SENT)) { 5065f8829a4aSRandall Stewart /* Pre-check If we are freeing no update */ 5066f8829a4aSRandall Stewart goto no_lock; 5067f8829a4aSRandall Stewart } 5068f8829a4aSRandall Stewart SCTP_INP_INCR_REF(stcb->sctp_ep); 5069f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5070f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5071f8829a4aSRandall Stewart goto out; 5072f8829a4aSRandall Stewart } 5073f8829a4aSRandall Stewart so = stcb->sctp_socket; 5074f8829a4aSRandall Stewart if (so == NULL) { 5075f8829a4aSRandall Stewart goto out; 5076f8829a4aSRandall Stewart } 5077f8829a4aSRandall Stewart atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); 5078f8829a4aSRandall Stewart /* Have you have freed enough to look */ 5079f8829a4aSRandall Stewart *freed_so_far = 0; 5080f8829a4aSRandall Stewart /* Yep, its worth a look and the lock overhead */ 5081f8829a4aSRandall Stewart 5082f8829a4aSRandall Stewart /* Figure out what the rwnd would be */ 5083f8829a4aSRandall Stewart rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); 5084f8829a4aSRandall Stewart if (rwnd >= stcb->asoc.my_last_reported_rwnd) { 5085f8829a4aSRandall Stewart dif = rwnd - stcb->asoc.my_last_reported_rwnd; 5086f8829a4aSRandall Stewart } else { 5087f8829a4aSRandall Stewart dif = 0; 5088f8829a4aSRandall Stewart } 5089f8829a4aSRandall Stewart if (dif >= rwnd_req) { 5090f8829a4aSRandall Stewart if (hold_rlock) { 5091f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 5092f8829a4aSRandall Stewart r_unlocked = 1; 5093f8829a4aSRandall Stewart } 5094f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5095f8829a4aSRandall Stewart /* 5096f8829a4aSRandall Stewart * One last check before we allow the guy possibly 5097f8829a4aSRandall Stewart * to get in. There is a race, where the guy has not 5098f8829a4aSRandall Stewart * reached the gate. In that case 5099f8829a4aSRandall Stewart */ 5100f8829a4aSRandall Stewart goto out; 5101f8829a4aSRandall Stewart } 5102f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 5103f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5104f8829a4aSRandall Stewart /* No reports here */ 5105f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5106f8829a4aSRandall Stewart goto out; 5107f8829a4aSRandall Stewart } 5108f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_wu_sacks_sent); 5109689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_LOCKED); 5110830d754dSRandall Stewart 5111f8829a4aSRandall Stewart sctp_chunk_output(stcb->sctp_ep, stcb, 5112ceaad40aSRandall Stewart SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); 5113f8829a4aSRandall Stewart /* make sure no timer is running */ 5114a5d547adSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_6); 5115f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 5116f8829a4aSRandall Stewart } else { 5117f8829a4aSRandall Stewart /* Update how much we have pending */ 5118f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = dif; 5119f8829a4aSRandall Stewart } 5120f8829a4aSRandall Stewart out: 5121f8829a4aSRandall Stewart if (so && r_unlocked && hold_rlock) { 5122f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 5123f8829a4aSRandall Stewart } 5124f8829a4aSRandall Stewart SCTP_INP_DECR_REF(stcb->sctp_ep); 5125f8829a4aSRandall Stewart no_lock: 512650cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 5127f8829a4aSRandall Stewart return; 5128f8829a4aSRandall Stewart } 5129f8829a4aSRandall Stewart 5130f8829a4aSRandall Stewart int 5131f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so, 5132f8829a4aSRandall Stewart struct uio *uio, 5133f8829a4aSRandall Stewart struct mbuf **mp, 5134f8829a4aSRandall Stewart struct sockaddr *from, 5135f8829a4aSRandall Stewart int fromlen, 5136f8829a4aSRandall Stewart int *msg_flags, 5137f8829a4aSRandall Stewart struct sctp_sndrcvinfo *sinfo, 5138f8829a4aSRandall Stewart int filling_sinfo) 5139f8829a4aSRandall Stewart { 5140f8829a4aSRandall Stewart /* 5141f8829a4aSRandall Stewart * MSG flags we will look at MSG_DONTWAIT - non-blocking IO. 5142f8829a4aSRandall Stewart * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy 5143f8829a4aSRandall Stewart * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ?? 5144f8829a4aSRandall Stewart * On the way out we may send out any combination of: 5145f8829a4aSRandall Stewart * MSG_NOTIFICATION MSG_EOR 5146f8829a4aSRandall Stewart * 5147f8829a4aSRandall Stewart */ 5148f8829a4aSRandall Stewart struct sctp_inpcb *inp = NULL; 5149f8829a4aSRandall Stewart int my_len = 0; 5150f8829a4aSRandall Stewart int cp_len = 0, error = 0; 5151f8829a4aSRandall Stewart struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; 515294b0d969SMichael Tuexen struct mbuf *m = NULL; 5153f8829a4aSRandall Stewart struct sctp_tcb *stcb = NULL; 5154f8829a4aSRandall Stewart int wakeup_read_socket = 0; 5155f8829a4aSRandall Stewart int freecnt_applied = 0; 5156f8829a4aSRandall Stewart int out_flags = 0, in_flags = 0; 5157f8829a4aSRandall Stewart int block_allowed = 1; 51584c9179adSRandall Stewart uint32_t freed_so_far = 0; 515981aca91aSRandall Stewart uint32_t copied_so_far = 0; 516093164cf9SRandall Stewart int in_eeor_mode = 0; 5161f8829a4aSRandall Stewart int no_rcv_needed = 0; 5162f8829a4aSRandall Stewart uint32_t rwnd_req = 0; 5163f8829a4aSRandall Stewart int hold_sblock = 0; 5164f8829a4aSRandall Stewart int hold_rlock = 0; 516542551e99SRandall Stewart int slen = 0; 51664c9179adSRandall Stewart uint32_t held_length = 0; 51677abab911SRobert Watson int sockbuf_lock = 0; 5168f8829a4aSRandall Stewart 516917205eccSRandall Stewart if (uio == NULL) { 5170c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 517117205eccSRandall Stewart return (EINVAL); 517217205eccSRandall Stewart } 5173f8829a4aSRandall Stewart if (msg_flags) { 5174f8829a4aSRandall Stewart in_flags = *msg_flags; 5175c105859eSRandall Stewart if (in_flags & MSG_PEEK) 5176c105859eSRandall Stewart SCTP_STAT_INCR(sctps_read_peeks); 5177f8829a4aSRandall Stewart } else { 5178f8829a4aSRandall Stewart in_flags = 0; 5179f8829a4aSRandall Stewart } 5180f8829a4aSRandall Stewart slen = uio->uio_resid; 518117205eccSRandall Stewart 5182f8829a4aSRandall Stewart /* Pull in and set up our int flags */ 5183f8829a4aSRandall Stewart if (in_flags & MSG_OOB) { 5184f8829a4aSRandall Stewart /* Out of band's NOT supported */ 5185f8829a4aSRandall Stewart return (EOPNOTSUPP); 5186f8829a4aSRandall Stewart } 5187f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) && (mp != NULL)) { 5188c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 5189f8829a4aSRandall Stewart return (EINVAL); 5190f8829a4aSRandall Stewart } 5191f8829a4aSRandall Stewart if ((in_flags & (MSG_DONTWAIT 5192f8829a4aSRandall Stewart | MSG_NBIO 5193f8829a4aSRandall Stewart )) || 519442551e99SRandall Stewart SCTP_SO_IS_NBIO(so)) { 5195f8829a4aSRandall Stewart block_allowed = 0; 5196f8829a4aSRandall Stewart } 5197f8829a4aSRandall Stewart /* setup the endpoint */ 5198f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 5199f8829a4aSRandall Stewart if (inp == NULL) { 5200c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 5201f8829a4aSRandall Stewart return (EFAULT); 5202f8829a4aSRandall Stewart } 520362c1ff9cSRandall Stewart rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); 5204f8829a4aSRandall Stewart /* Must be at least a MTU's worth */ 5205f8829a4aSRandall Stewart if (rwnd_req < SCTP_MIN_RWND) 5206f8829a4aSRandall Stewart rwnd_req = SCTP_MIN_RWND; 5207f8829a4aSRandall Stewart in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 5208b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5209f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTER, 521017205eccSRandall Stewart rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid); 521180fefe0aSRandall Stewart } 5212b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5213f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTERPL, 521417205eccSRandall Stewart rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid); 521580fefe0aSRandall Stewart } 5216265de5bbSRobert Watson error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); 5217f8829a4aSRandall Stewart if (error) { 5218f8829a4aSRandall Stewart goto release_unlocked; 5219f8829a4aSRandall Stewart } 52208e1e6e5fSMateusz Guzik sockbuf_lock = 1; 5221f8829a4aSRandall Stewart restart: 52227abab911SRobert Watson 5223f8829a4aSRandall Stewart 5224f8829a4aSRandall Stewart restart_nosblocks: 5225f8829a4aSRandall Stewart if (hold_sblock == 0) { 5226f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5227f8829a4aSRandall Stewart hold_sblock = 1; 5228f8829a4aSRandall Stewart } 5229f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5230f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5231f8829a4aSRandall Stewart goto out; 5232f8829a4aSRandall Stewart } 523358411b08SMichael Tuexen if ((so->so_rcv.sb_state & SBS_CANTRCVMORE) && (so->so_rcv.sb_cc == 0)) { 5234f8829a4aSRandall Stewart if (so->so_error) { 5235f8829a4aSRandall Stewart error = so->so_error; 523644b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 523744b7479bSRandall Stewart so->so_error = 0; 52389f22f500SRandall Stewart goto out; 5239f8829a4aSRandall Stewart } else { 52409f22f500SRandall Stewart if (so->so_rcv.sb_cc == 0) { 52417924093fSRandall Stewart /* indicate EOF */ 52427924093fSRandall Stewart error = 0; 5243f8829a4aSRandall Stewart goto out; 5244f8829a4aSRandall Stewart } 52459f22f500SRandall Stewart } 52469f22f500SRandall Stewart } 5247f8829a4aSRandall Stewart if ((so->so_rcv.sb_cc <= held_length) && block_allowed) { 5248f8829a4aSRandall Stewart /* we need to wait for data */ 5249f8829a4aSRandall Stewart if ((so->so_rcv.sb_cc == 0) && 5250f8829a4aSRandall Stewart ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5251f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 5252f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 5253f8829a4aSRandall Stewart /* 5254f8829a4aSRandall Stewart * For active open side clear flags for 5255f8829a4aSRandall Stewart * re-use passive open is blocked by 5256f8829a4aSRandall Stewart * connect. 5257f8829a4aSRandall Stewart */ 5258f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 5259f8829a4aSRandall Stewart /* 5260f8829a4aSRandall Stewart * You were aborted, passive side 5261f8829a4aSRandall Stewart * always hits here 5262f8829a4aSRandall Stewart */ 5263c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 5264f8829a4aSRandall Stewart error = ECONNRESET; 5265f8829a4aSRandall Stewart } 5266f8829a4aSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 5267f8829a4aSRandall Stewart SS_ISDISCONNECTING | 5268f8829a4aSRandall Stewart SS_ISCONFIRMING | 5269f8829a4aSRandall Stewart SS_ISCONNECTED); 5270f8829a4aSRandall Stewart if (error == 0) { 5271f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5272c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 5273f8829a4aSRandall Stewart error = ENOTCONN; 5274f8829a4aSRandall Stewart } 5275f8829a4aSRandall Stewart } 5276f8829a4aSRandall Stewart goto out; 5277f8829a4aSRandall Stewart } 5278f8829a4aSRandall Stewart } 5279f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5280f8829a4aSRandall Stewart if (error) { 5281f8829a4aSRandall Stewart goto out; 5282f8829a4aSRandall Stewart } 5283f8829a4aSRandall Stewart held_length = 0; 5284f8829a4aSRandall Stewart goto restart_nosblocks; 5285f8829a4aSRandall Stewart } else if (so->so_rcv.sb_cc == 0) { 528644b7479bSRandall Stewart if (so->so_error) { 528744b7479bSRandall Stewart error = so->so_error; 528844b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 528944b7479bSRandall Stewart so->so_error = 0; 529044b7479bSRandall Stewart } else { 529144b7479bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 529244b7479bSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 529344b7479bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 529444b7479bSRandall Stewart /* 529544b7479bSRandall Stewart * For active open side clear flags 529644b7479bSRandall Stewart * for re-use passive open is 529744b7479bSRandall Stewart * blocked by connect. 529844b7479bSRandall Stewart */ 529944b7479bSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 530044b7479bSRandall Stewart /* 530144b7479bSRandall Stewart * You were aborted, passive 530244b7479bSRandall Stewart * side always hits here 530344b7479bSRandall Stewart */ 5304c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 530544b7479bSRandall Stewart error = ECONNRESET; 530644b7479bSRandall Stewart } 530744b7479bSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 530844b7479bSRandall Stewart SS_ISDISCONNECTING | 530944b7479bSRandall Stewart SS_ISCONFIRMING | 531044b7479bSRandall Stewart SS_ISCONNECTED); 531144b7479bSRandall Stewart if (error == 0) { 531244b7479bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5313c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 531444b7479bSRandall Stewart error = ENOTCONN; 531544b7479bSRandall Stewart } 531644b7479bSRandall Stewart } 531744b7479bSRandall Stewart goto out; 531844b7479bSRandall Stewart } 531944b7479bSRandall Stewart } 5320c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); 5321f8829a4aSRandall Stewart error = EWOULDBLOCK; 532244b7479bSRandall Stewart } 5323f8829a4aSRandall Stewart goto out; 5324f8829a4aSRandall Stewart } 5325d06c82f1SRandall Stewart if (hold_sblock == 1) { 5326d06c82f1SRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5327d06c82f1SRandall Stewart hold_sblock = 0; 5328d06c82f1SRandall Stewart } 5329f8829a4aSRandall Stewart /* we possibly have data we can read */ 53303c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 5331f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5332f8829a4aSRandall Stewart if (control == NULL) { 5333f8829a4aSRandall Stewart /* 5334f8829a4aSRandall Stewart * This could be happening since the appender did the 5335f8829a4aSRandall Stewart * increment but as not yet did the tailq insert onto the 5336f8829a4aSRandall Stewart * read_queue 5337f8829a4aSRandall Stewart */ 5338f8829a4aSRandall Stewart if (hold_rlock == 0) { 5339f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5340f8829a4aSRandall Stewart } 5341f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5342f8829a4aSRandall Stewart if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { 5343a5d547adSRandall Stewart #ifdef INVARIANTS 5344f8829a4aSRandall Stewart panic("Huh, its non zero and nothing on control?"); 5345f8829a4aSRandall Stewart #endif 5346f8829a4aSRandall Stewart so->so_rcv.sb_cc = 0; 5347f8829a4aSRandall Stewart } 5348f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5349f8829a4aSRandall Stewart hold_rlock = 0; 5350f8829a4aSRandall Stewart goto restart; 5351f8829a4aSRandall Stewart } 5352f8829a4aSRandall Stewart if ((control->length == 0) && 5353f8829a4aSRandall Stewart (control->do_not_ref_stcb)) { 5354f8829a4aSRandall Stewart /* 5355f8829a4aSRandall Stewart * Clean up code for freeing assoc that left behind a 5356f8829a4aSRandall Stewart * pdapi.. maybe a peer in EEOR that just closed after 5357f8829a4aSRandall Stewart * sending and never indicated a EOR. 5358f8829a4aSRandall Stewart */ 5359f8829a4aSRandall Stewart if (hold_rlock == 0) { 5360f8829a4aSRandall Stewart hold_rlock = 1; 5361f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5362f8829a4aSRandall Stewart } 5363f8829a4aSRandall Stewart control->held_length = 0; 5364f8829a4aSRandall Stewart if (control->data) { 5365f8829a4aSRandall Stewart /* Hmm there is data here .. fix */ 53664c9179adSRandall Stewart struct mbuf *m_tmp; 5367f8829a4aSRandall Stewart int cnt = 0; 5368f8829a4aSRandall Stewart 53694c9179adSRandall Stewart m_tmp = control->data; 53704c9179adSRandall Stewart while (m_tmp) { 53714c9179adSRandall Stewart cnt += SCTP_BUF_LEN(m_tmp); 53724c9179adSRandall Stewart if (SCTP_BUF_NEXT(m_tmp) == NULL) { 53734c9179adSRandall Stewart control->tail_mbuf = m_tmp; 5374f8829a4aSRandall Stewart control->end_added = 1; 5375f8829a4aSRandall Stewart } 53764c9179adSRandall Stewart m_tmp = SCTP_BUF_NEXT(m_tmp); 5377f8829a4aSRandall Stewart } 5378f8829a4aSRandall Stewart control->length = cnt; 5379f8829a4aSRandall Stewart } else { 5380f8829a4aSRandall Stewart /* remove it */ 5381f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5382f8829a4aSRandall Stewart /* Add back any hiddend data */ 5383f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5384f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5385f8829a4aSRandall Stewart } 5386f8829a4aSRandall Stewart if (hold_rlock) { 5387f8829a4aSRandall Stewart hold_rlock = 0; 5388f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5389f8829a4aSRandall Stewart } 5390f8829a4aSRandall Stewart goto restart; 5391f8829a4aSRandall Stewart } 5392810ec536SMichael Tuexen if ((control->length == 0) && 5393810ec536SMichael Tuexen (control->end_added == 1)) { 5394810ec536SMichael Tuexen /* 5395810ec536SMichael Tuexen * Do we also need to check for (control->pdapi_aborted == 5396810ec536SMichael Tuexen * 1)? 5397810ec536SMichael Tuexen */ 5398810ec536SMichael Tuexen if (hold_rlock == 0) { 5399810ec536SMichael Tuexen hold_rlock = 1; 5400810ec536SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5401810ec536SMichael Tuexen } 5402810ec536SMichael Tuexen TAILQ_REMOVE(&inp->read_queue, control, next); 5403810ec536SMichael Tuexen if (control->data) { 5404810ec536SMichael Tuexen #ifdef INVARIANTS 5405810ec536SMichael Tuexen panic("control->data not null but control->length == 0"); 5406810ec536SMichael Tuexen #else 5407810ec536SMichael Tuexen SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n"); 5408810ec536SMichael Tuexen sctp_m_freem(control->data); 5409810ec536SMichael Tuexen control->data = NULL; 5410810ec536SMichael Tuexen #endif 5411810ec536SMichael Tuexen } 5412810ec536SMichael Tuexen if (control->aux_data) { 5413810ec536SMichael Tuexen sctp_m_free(control->aux_data); 5414810ec536SMichael Tuexen control->aux_data = NULL; 5415810ec536SMichael Tuexen } 5416810ec536SMichael Tuexen sctp_free_remote_addr(control->whoFrom); 5417810ec536SMichael Tuexen sctp_free_a_readq(stcb, control); 5418810ec536SMichael Tuexen if (hold_rlock) { 5419810ec536SMichael Tuexen hold_rlock = 0; 5420810ec536SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 5421810ec536SMichael Tuexen } 5422810ec536SMichael Tuexen goto restart; 5423810ec536SMichael Tuexen } 5424f8829a4aSRandall Stewart if (control->length == 0) { 5425f8829a4aSRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && 5426f8829a4aSRandall Stewart (filling_sinfo)) { 5427f8829a4aSRandall Stewart /* find a more suitable one then this */ 5428f8829a4aSRandall Stewart ctl = TAILQ_NEXT(control, next); 5429f8829a4aSRandall Stewart while (ctl) { 54309a6142d8SRandall Stewart if ((ctl->stcb != control->stcb) && (ctl->length) && 54319a6142d8SRandall Stewart (ctl->some_taken || 54326114cd96SRandall Stewart (ctl->spec_flags & M_NOTIFICATION) || 54339a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 54349a6142d8SRandall Stewart (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) 54359a6142d8SRandall Stewart ) { 54369a6142d8SRandall Stewart /*- 54379a6142d8SRandall Stewart * If we have a different TCB next, and there is data 54389a6142d8SRandall Stewart * present. If we have already taken some (pdapi), OR we can 54399a6142d8SRandall Stewart * ref the tcb and no delivery as started on this stream, we 544017205eccSRandall Stewart * take it. Note we allow a notification on a different 544117205eccSRandall Stewart * assoc to be delivered.. 54429a6142d8SRandall Stewart */ 54439a6142d8SRandall Stewart control = ctl; 54449a6142d8SRandall Stewart goto found_one; 54459a6142d8SRandall Stewart } else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) && 54469a6142d8SRandall Stewart (ctl->length) && 54479a6142d8SRandall Stewart ((ctl->some_taken) || 54489a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 544917205eccSRandall Stewart ((ctl->spec_flags & M_NOTIFICATION) == 0) && 5450b5c16493SMichael Tuexen (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) { 54519a6142d8SRandall Stewart /*- 54529a6142d8SRandall Stewart * If we have the same tcb, and there is data present, and we 54539a6142d8SRandall Stewart * have the strm interleave feature present. Then if we have 54549a6142d8SRandall Stewart * taken some (pdapi) or we can refer to tht tcb AND we have 54559a6142d8SRandall Stewart * not started a delivery for this stream, we can take it. 545617205eccSRandall Stewart * Note we do NOT allow a notificaiton on the same assoc to 545717205eccSRandall Stewart * be delivered. 54589a6142d8SRandall Stewart */ 5459f8829a4aSRandall Stewart control = ctl; 5460f8829a4aSRandall Stewart goto found_one; 5461f8829a4aSRandall Stewart } 5462f8829a4aSRandall Stewart ctl = TAILQ_NEXT(ctl, next); 5463f8829a4aSRandall Stewart } 5464f8829a4aSRandall Stewart } 5465f8829a4aSRandall Stewart /* 5466f8829a4aSRandall Stewart * if we reach here, not suitable replacement is available 5467f8829a4aSRandall Stewart * <or> fragment interleave is NOT on. So stuff the sb_cc 5468f8829a4aSRandall Stewart * into the our held count, and its time to sleep again. 5469f8829a4aSRandall Stewart */ 5470f8829a4aSRandall Stewart held_length = so->so_rcv.sb_cc; 5471f8829a4aSRandall Stewart control->held_length = so->so_rcv.sb_cc; 5472f8829a4aSRandall Stewart goto restart; 5473f8829a4aSRandall Stewart } 5474f8829a4aSRandall Stewart /* Clear the held length since there is something to read */ 5475f8829a4aSRandall Stewart control->held_length = 0; 5476f8829a4aSRandall Stewart if (hold_rlock) { 5477f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5478f8829a4aSRandall Stewart hold_rlock = 0; 5479f8829a4aSRandall Stewart } 5480f8829a4aSRandall Stewart found_one: 5481f8829a4aSRandall Stewart /* 5482f8829a4aSRandall Stewart * If we reach here, control has a some data for us to read off. 5483f8829a4aSRandall Stewart * Note that stcb COULD be NULL. 5484f8829a4aSRandall Stewart */ 54859c04b296SRandall Stewart control->some_taken++; 5486f8829a4aSRandall Stewart if (hold_sblock) { 5487f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5488f8829a4aSRandall Stewart hold_sblock = 0; 5489f8829a4aSRandall Stewart } 5490f8829a4aSRandall Stewart stcb = control->stcb; 5491f8829a4aSRandall Stewart if (stcb) { 54920696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 54930696e120SRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { 549450cec919SRandall Stewart if (freecnt_applied == 0) 5495f8829a4aSRandall Stewart stcb = NULL; 5496f8829a4aSRandall Stewart } else if (control->do_not_ref_stcb == 0) { 5497f8829a4aSRandall Stewart /* you can't free it on me please */ 5498f8829a4aSRandall Stewart /* 5499f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the 5500f8829a4aSRandall Stewart * free code will stop. But since we used the 5501f8829a4aSRandall Stewart * socketbuf lock and the sender uses the tcb_lock 5502f8829a4aSRandall Stewart * to increment, we need to use the atomic add to 5503f8829a4aSRandall Stewart * the refcnt 5504f8829a4aSRandall Stewart */ 5505d55b0b1bSRandall Stewart if (freecnt_applied) { 5506d55b0b1bSRandall Stewart #ifdef INVARIANTS 5507207304d4SRandall Stewart panic("refcnt already incremented"); 5508d55b0b1bSRandall Stewart #else 5509cd3fd531SMichael Tuexen SCTP_PRINTF("refcnt already incremented?\n"); 5510d55b0b1bSRandall Stewart #endif 5511d55b0b1bSRandall Stewart } else { 551250cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5513f8829a4aSRandall Stewart freecnt_applied = 1; 5514d55b0b1bSRandall Stewart } 5515f8829a4aSRandall Stewart /* 5516f8829a4aSRandall Stewart * Setup to remember how much we have not yet told 5517f8829a4aSRandall Stewart * the peer our rwnd has opened up. Note we grab the 5518f8829a4aSRandall Stewart * value from the tcb from last time. Note too that 55190696e120SRandall Stewart * sack sending clears this when a sack is sent, 5520f8829a4aSRandall Stewart * which is fine. Once we hit the rwnd_req, we then 5521f8829a4aSRandall Stewart * will go to the sctp_user_rcvd() that will not 5522f8829a4aSRandall Stewart * lock until it KNOWs it MUST send a WUP-SACK. 5523f8829a4aSRandall Stewart */ 5524f8829a4aSRandall Stewart freed_so_far = stcb->freed_by_sorcv_sincelast; 5525f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = 0; 5526f8829a4aSRandall Stewart } 5527f8829a4aSRandall Stewart } 55286114cd96SRandall Stewart if (stcb && 55296114cd96SRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0) && 55306114cd96SRandall Stewart control->do_not_ref_stcb == 0) { 5531d06c82f1SRandall Stewart stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; 5532d06c82f1SRandall Stewart } 5533f8829a4aSRandall Stewart /* First lets get off the sinfo and sockaddr info */ 5534f8829a4aSRandall Stewart if ((sinfo) && filling_sinfo) { 5535f8829a4aSRandall Stewart memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo)); 5536f8829a4aSRandall Stewart nxt = TAILQ_NEXT(control, next); 5537e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 5538e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { 5539f8829a4aSRandall Stewart struct sctp_extrcvinfo *s_extra; 5540f8829a4aSRandall Stewart 5541f8829a4aSRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 55429a6142d8SRandall Stewart if ((nxt) && 55439a6142d8SRandall Stewart (nxt->length)) { 55449a6142d8SRandall Stewart s_extra->sreinfo_next_flags = SCTP_NEXT_MSG_AVAIL; 5545f8829a4aSRandall Stewart if (nxt->sinfo_flags & SCTP_UNORDERED) { 55469a6142d8SRandall Stewart s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED; 5547f8829a4aSRandall Stewart } 5548f42a358aSRandall Stewart if (nxt->spec_flags & M_NOTIFICATION) { 55499a6142d8SRandall Stewart s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION; 5550f42a358aSRandall Stewart } 55519a6142d8SRandall Stewart s_extra->sreinfo_next_aid = nxt->sinfo_assoc_id; 55529a6142d8SRandall Stewart s_extra->sreinfo_next_length = nxt->length; 55539a6142d8SRandall Stewart s_extra->sreinfo_next_ppid = nxt->sinfo_ppid; 55549a6142d8SRandall Stewart s_extra->sreinfo_next_stream = nxt->sinfo_stream; 5555f8829a4aSRandall Stewart if (nxt->tail_mbuf != NULL) { 5556139bc87fSRandall Stewart if (nxt->end_added) { 55579a6142d8SRandall Stewart s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE; 5558f8829a4aSRandall Stewart } 5559f8829a4aSRandall Stewart } 5560f8829a4aSRandall Stewart } else { 5561f8829a4aSRandall Stewart /* 5562f8829a4aSRandall Stewart * we explicitly 0 this, since the memcpy 5563f8829a4aSRandall Stewart * got some other things beyond the older 5564f8829a4aSRandall Stewart * sinfo_ that is on the control's structure 5565f8829a4aSRandall Stewart * :-D 5566f8829a4aSRandall Stewart */ 55679a6142d8SRandall Stewart nxt = NULL; 55689a6142d8SRandall Stewart s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG; 55699a6142d8SRandall Stewart s_extra->sreinfo_next_aid = 0; 55709a6142d8SRandall Stewart s_extra->sreinfo_next_length = 0; 55719a6142d8SRandall Stewart s_extra->sreinfo_next_ppid = 0; 55729a6142d8SRandall Stewart s_extra->sreinfo_next_stream = 0; 5573f8829a4aSRandall Stewart } 5574f8829a4aSRandall Stewart } 5575f8829a4aSRandall Stewart /* 5576f8829a4aSRandall Stewart * update off the real current cum-ack, if we have an stcb. 5577f8829a4aSRandall Stewart */ 55780696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb) 5579f8829a4aSRandall Stewart sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 5580f8829a4aSRandall Stewart /* 5581f8829a4aSRandall Stewart * mask off the high bits, we keep the actual chunk bits in 5582f8829a4aSRandall Stewart * there. 5583f8829a4aSRandall Stewart */ 5584f8829a4aSRandall Stewart sinfo->sinfo_flags &= 0x00ff; 55855f26a41dSRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { 55865f26a41dSRandall Stewart sinfo->sinfo_flags |= SCTP_UNORDERED; 55875f26a41dSRandall Stewart } 5588f8829a4aSRandall Stewart } 558918e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 559018e198d3SRandall Stewart { 559118e198d3SRandall Stewart int index, newindex; 559218e198d3SRandall Stewart struct sctp_pcbtsn_rlog *entry; 559318e198d3SRandall Stewart 559418e198d3SRandall Stewart do { 559518e198d3SRandall Stewart index = inp->readlog_index; 559618e198d3SRandall Stewart newindex = index + 1; 559718e198d3SRandall Stewart if (newindex >= SCTP_READ_LOG_SIZE) { 559818e198d3SRandall Stewart newindex = 0; 559918e198d3SRandall Stewart } 560018e198d3SRandall Stewart } while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0); 560118e198d3SRandall Stewart entry = &inp->readlog[index]; 560218e198d3SRandall Stewart entry->vtag = control->sinfo_assoc_id; 560318e198d3SRandall Stewart entry->strm = control->sinfo_stream; 560418e198d3SRandall Stewart entry->seq = control->sinfo_ssn; 560518e198d3SRandall Stewart entry->sz = control->length; 560618e198d3SRandall Stewart entry->flgs = control->sinfo_flags; 560718e198d3SRandall Stewart } 560818e198d3SRandall Stewart #endif 5609f8829a4aSRandall Stewart if (fromlen && from) { 5610b5b6e5c2SMichael Tuexen cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sa.sa_len); 5611b5b6e5c2SMichael Tuexen switch (control->whoFrom->ro._l_addr.sa.sa_family) { 5612b5b6e5c2SMichael Tuexen #ifdef INET6 5613b5b6e5c2SMichael Tuexen case AF_INET6: 5614f8829a4aSRandall Stewart ((struct sockaddr_in6 *)from)->sin6_port = control->port_from; 5615b5b6e5c2SMichael Tuexen break; 5616f8829a4aSRandall Stewart #endif 5617b5b6e5c2SMichael Tuexen #ifdef INET 5618b5b6e5c2SMichael Tuexen case AF_INET: 5619b5b6e5c2SMichael Tuexen ((struct sockaddr_in *)from)->sin_port = control->port_from; 5620b5b6e5c2SMichael Tuexen break; 5621b5b6e5c2SMichael Tuexen #endif 5622b5b6e5c2SMichael Tuexen default: 5623b5b6e5c2SMichael Tuexen break; 5624b5b6e5c2SMichael Tuexen } 5625b5b6e5c2SMichael Tuexen memcpy(from, &control->whoFrom->ro._l_addr, cp_len); 5626f8829a4aSRandall Stewart 562742551e99SRandall Stewart #if defined(INET) && defined(INET6) 56285e2c2d87SRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 5629b5b6e5c2SMichael Tuexen (from->sa_family == AF_INET) && 5630f8829a4aSRandall Stewart ((size_t)fromlen >= sizeof(struct sockaddr_in6))) { 5631f8829a4aSRandall Stewart struct sockaddr_in *sin; 5632f8829a4aSRandall Stewart struct sockaddr_in6 sin6; 5633f8829a4aSRandall Stewart 5634b5b6e5c2SMichael Tuexen sin = (struct sockaddr_in *)from; 5635f8829a4aSRandall Stewart bzero(&sin6, sizeof(sin6)); 5636f8829a4aSRandall Stewart sin6.sin6_family = AF_INET6; 5637f8829a4aSRandall Stewart sin6.sin6_len = sizeof(struct sockaddr_in6); 5638d6af161aSRandall Stewart sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); 5639f8829a4aSRandall Stewart bcopy(&sin->sin_addr, 5640d6af161aSRandall Stewart &sin6.sin6_addr.s6_addr32[3], 5641d6af161aSRandall Stewart sizeof(sin6.sin6_addr.s6_addr32[3])); 5642f8829a4aSRandall Stewart sin6.sin6_port = sin->sin_port; 5643b5b6e5c2SMichael Tuexen memcpy(from, &sin6, sizeof(struct sockaddr_in6)); 5644f8829a4aSRandall Stewart } 5645f8829a4aSRandall Stewart #endif 5646e0e00a4dSMichael Tuexen #ifdef INET6 5647f8829a4aSRandall Stewart { 5648b5b6e5c2SMichael Tuexen struct sockaddr_in6 lsa6, *from6; 5649f8829a4aSRandall Stewart 5650b5b6e5c2SMichael Tuexen from6 = (struct sockaddr_in6 *)from; 5651b5b6e5c2SMichael Tuexen sctp_recover_scope_mac(from6, (&lsa6)); 5652f8829a4aSRandall Stewart } 5653f8829a4aSRandall Stewart #endif 5654f8829a4aSRandall Stewart } 5655f8829a4aSRandall Stewart /* now copy out what data we can */ 5656f8829a4aSRandall Stewart if (mp == NULL) { 5657f8829a4aSRandall Stewart /* copy out each mbuf in the chain up to length */ 5658f8829a4aSRandall Stewart get_more_data: 5659f8829a4aSRandall Stewart m = control->data; 5660f8829a4aSRandall Stewart while (m) { 5661f8829a4aSRandall Stewart /* Move out all we can */ 5662f8829a4aSRandall Stewart cp_len = (int)uio->uio_resid; 5663139bc87fSRandall Stewart my_len = (int)SCTP_BUF_LEN(m); 5664f8829a4aSRandall Stewart if (cp_len > my_len) { 5665f8829a4aSRandall Stewart /* not enough in this buf */ 5666f8829a4aSRandall Stewart cp_len = my_len; 5667f8829a4aSRandall Stewart } 5668f8829a4aSRandall Stewart if (hold_rlock) { 5669f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5670f8829a4aSRandall Stewart hold_rlock = 0; 5671f8829a4aSRandall Stewart } 5672f8829a4aSRandall Stewart if (cp_len > 0) 5673f8829a4aSRandall Stewart error = uiomove(mtod(m, char *), cp_len, uio); 5674f8829a4aSRandall Stewart /* re-read */ 5675f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 5676f8829a4aSRandall Stewart goto release; 5677f8829a4aSRandall Stewart } 56780696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb && 5679f8829a4aSRandall Stewart stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5680f8829a4aSRandall Stewart no_rcv_needed = 1; 5681f8829a4aSRandall Stewart } 5682f8829a4aSRandall Stewart if (error) { 5683f8829a4aSRandall Stewart /* error we are out of here */ 5684f8829a4aSRandall Stewart goto release; 5685f8829a4aSRandall Stewart } 5686139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 5687139bc87fSRandall Stewart (cp_len >= SCTP_BUF_LEN(m)) && 5688f8829a4aSRandall Stewart ((control->end_added == 0) || 56890696e120SRandall Stewart (control->end_added && 56900696e120SRandall Stewart (TAILQ_NEXT(control, next) == NULL))) 5691f8829a4aSRandall Stewart ) { 5692f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5693f8829a4aSRandall Stewart hold_rlock = 1; 5694f8829a4aSRandall Stewart } 5695139bc87fSRandall Stewart if (cp_len == SCTP_BUF_LEN(m)) { 5696139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 5697139bc87fSRandall Stewart (control->end_added)) { 5698f8829a4aSRandall Stewart out_flags |= MSG_EOR; 569952129fcdSRandall Stewart if ((control->do_not_ref_stcb == 0) && 570052129fcdSRandall Stewart (control->stcb != NULL) && 570152129fcdSRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0)) 5702ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 5703f8829a4aSRandall Stewart } 5704139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5705f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5706f8829a4aSRandall Stewart } 5707f8829a4aSRandall Stewart /* we ate up the mbuf */ 5708f8829a4aSRandall Stewart if (in_flags & MSG_PEEK) { 5709f8829a4aSRandall Stewart /* just looking */ 5710139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 5711f8829a4aSRandall Stewart copied_so_far += cp_len; 5712f8829a4aSRandall Stewart } else { 5713f8829a4aSRandall Stewart /* dispose of the mbuf */ 5714b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5715f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5716139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 571780fefe0aSRandall Stewart } 5718f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 5719b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5720f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5721f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 572280fefe0aSRandall Stewart } 5723f8829a4aSRandall Stewart copied_so_far += cp_len; 5724f8829a4aSRandall Stewart freed_so_far += cp_len; 5725c4739e2fSRandall Stewart freed_so_far += MSIZE; 572618e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 5727f8829a4aSRandall Stewart control->data = sctp_m_free(m); 5728f8829a4aSRandall Stewart m = control->data; 5729f8829a4aSRandall Stewart /* 5730f8829a4aSRandall Stewart * been through it all, must hold sb 5731f8829a4aSRandall Stewart * lock ok to null tail 5732f8829a4aSRandall Stewart */ 5733f8829a4aSRandall Stewart if (control->data == NULL) { 5734a5d547adSRandall Stewart #ifdef INVARIANTS 5735f8829a4aSRandall Stewart if ((control->end_added == 0) || 5736f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 5737f8829a4aSRandall Stewart /* 5738f8829a4aSRandall Stewart * If the end is not 5739f8829a4aSRandall Stewart * added, OR the 5740f8829a4aSRandall Stewart * next is NOT null 5741f8829a4aSRandall Stewart * we MUST have the 5742f8829a4aSRandall Stewart * lock. 5743f8829a4aSRandall Stewart */ 5744f8829a4aSRandall Stewart if (mtx_owned(&inp->inp_rdata_mtx) == 0) { 5745f8829a4aSRandall Stewart panic("Hmm we don't own the lock?"); 5746f8829a4aSRandall Stewart } 5747f8829a4aSRandall Stewart } 5748f8829a4aSRandall Stewart #endif 5749f8829a4aSRandall Stewart control->tail_mbuf = NULL; 5750a5d547adSRandall Stewart #ifdef INVARIANTS 5751f8829a4aSRandall Stewart if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { 5752f8829a4aSRandall Stewart panic("end_added, nothing left and no MSG_EOR"); 5753f8829a4aSRandall Stewart } 5754f8829a4aSRandall Stewart #endif 5755f8829a4aSRandall Stewart } 5756f8829a4aSRandall Stewart } 5757f8829a4aSRandall Stewart } else { 5758f8829a4aSRandall Stewart /* Do we need to trim the mbuf? */ 5759139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5760f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5761f8829a4aSRandall Stewart } 5762f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) == 0) { 5763139bc87fSRandall Stewart SCTP_BUF_RESV_UF(m, cp_len); 5764139bc87fSRandall Stewart SCTP_BUF_LEN(m) -= cp_len; 5765b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5766f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len); 576780fefe0aSRandall Stewart } 5768f8829a4aSRandall Stewart atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); 57690696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 57700696e120SRandall Stewart stcb) { 5771f8829a4aSRandall Stewart atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); 5772f8829a4aSRandall Stewart } 5773f8829a4aSRandall Stewart copied_so_far += cp_len; 5774f8829a4aSRandall Stewart freed_so_far += cp_len; 5775c4739e2fSRandall Stewart freed_so_far += MSIZE; 5776b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5777f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, 5778f8829a4aSRandall Stewart SCTP_LOG_SBRESULT, 0); 577980fefe0aSRandall Stewart } 578018e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 5781f8829a4aSRandall Stewart } else { 5782f8829a4aSRandall Stewart copied_so_far += cp_len; 5783f8829a4aSRandall Stewart } 5784f8829a4aSRandall Stewart } 5785d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { 5786f8829a4aSRandall Stewart break; 5787f8829a4aSRandall Stewart } 5788f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 5789f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 5790f8829a4aSRandall Stewart (freed_so_far >= rwnd_req)) { 5791f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5792f8829a4aSRandall Stewart } 5793f8829a4aSRandall Stewart } /* end while(m) */ 5794f8829a4aSRandall Stewart /* 5795f8829a4aSRandall Stewart * At this point we have looked at it all and we either have 5796f8829a4aSRandall Stewart * a MSG_EOR/or read all the user wants... <OR> 5797f8829a4aSRandall Stewart * control->length == 0. 5798f8829a4aSRandall Stewart */ 5799d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) { 5800f8829a4aSRandall Stewart /* we are done with this control */ 5801f8829a4aSRandall Stewart if (control->length == 0) { 5802f8829a4aSRandall Stewart if (control->data) { 5803a5d547adSRandall Stewart #ifdef INVARIANTS 5804f8829a4aSRandall Stewart panic("control->data not null at read eor?"); 5805f8829a4aSRandall Stewart #else 5806ad81507eSRandall Stewart SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n"); 5807f8829a4aSRandall Stewart sctp_m_freem(control->data); 5808f8829a4aSRandall Stewart control->data = NULL; 5809f8829a4aSRandall Stewart #endif 5810f8829a4aSRandall Stewart } 5811f8829a4aSRandall Stewart done_with_control: 5812f8829a4aSRandall Stewart if (TAILQ_NEXT(control, next) == NULL) { 5813f8829a4aSRandall Stewart /* 5814f8829a4aSRandall Stewart * If we don't have a next we need a 5815b201f536SRandall Stewart * lock, if there is a next 5816b201f536SRandall Stewart * interrupt is filling ahead of us 5817b201f536SRandall Stewart * and we don't need a lock to 5818b201f536SRandall Stewart * remove this guy (which is the 5819b201f536SRandall Stewart * head of the queue). 5820f8829a4aSRandall Stewart */ 5821f8829a4aSRandall Stewart if (hold_rlock == 0) { 5822f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5823f8829a4aSRandall Stewart hold_rlock = 1; 5824f8829a4aSRandall Stewart } 5825f8829a4aSRandall Stewart } 5826f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5827f8829a4aSRandall Stewart /* Add back any hiddend data */ 5828f8829a4aSRandall Stewart if (control->held_length) { 5829f8829a4aSRandall Stewart held_length = 0; 5830f8829a4aSRandall Stewart control->held_length = 0; 5831f8829a4aSRandall Stewart wakeup_read_socket = 1; 5832f8829a4aSRandall Stewart } 583317205eccSRandall Stewart if (control->aux_data) { 583417205eccSRandall Stewart sctp_m_free(control->aux_data); 583517205eccSRandall Stewart control->aux_data = NULL; 583617205eccSRandall Stewart } 5837f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 5838f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5839f8829a4aSRandall Stewart control->data = NULL; 5840f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5841f8829a4aSRandall Stewart control = NULL; 58420696e120SRandall Stewart if ((freed_so_far >= rwnd_req) && 58430696e120SRandall Stewart (no_rcv_needed == 0)) 5844f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5845f8829a4aSRandall Stewart 5846f8829a4aSRandall Stewart } else { 5847f8829a4aSRandall Stewart /* 5848f8829a4aSRandall Stewart * The user did not read all of this 5849f8829a4aSRandall Stewart * message, turn off the returned MSG_EOR 5850f8829a4aSRandall Stewart * since we are leaving more behind on the 5851f8829a4aSRandall Stewart * control to read. 5852f8829a4aSRandall Stewart */ 5853a5d547adSRandall Stewart #ifdef INVARIANTS 58540696e120SRandall Stewart if (control->end_added && 58550696e120SRandall Stewart (control->data == NULL) && 5856f8829a4aSRandall Stewart (control->tail_mbuf == NULL)) { 5857f8829a4aSRandall Stewart panic("Gak, control->length is corrupt?"); 5858f8829a4aSRandall Stewart } 5859f8829a4aSRandall Stewart #endif 5860f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 5861f8829a4aSRandall Stewart out_flags &= ~MSG_EOR; 5862f8829a4aSRandall Stewart } 5863f8829a4aSRandall Stewart } 5864f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 5865f8829a4aSRandall Stewart goto release; 5866f8829a4aSRandall Stewart } 5867f8829a4aSRandall Stewart if ((uio->uio_resid == 0) || 5868f8829a4aSRandall Stewart ((in_eeor_mode) && (copied_so_far >= max(so->so_rcv.sb_lowat, 1))) 5869f8829a4aSRandall Stewart ) { 5870f8829a4aSRandall Stewart goto release; 5871f8829a4aSRandall Stewart } 5872f8829a4aSRandall Stewart /* 5873f8829a4aSRandall Stewart * If I hit here the receiver wants more and this message is 5874f8829a4aSRandall Stewart * NOT done (pd-api). So two questions. Can we block? if not 5875f8829a4aSRandall Stewart * we are done. Did the user NOT set MSG_WAITALL? 5876f8829a4aSRandall Stewart */ 5877f8829a4aSRandall Stewart if (block_allowed == 0) { 5878f8829a4aSRandall Stewart goto release; 5879f8829a4aSRandall Stewart } 5880f8829a4aSRandall Stewart /* 5881f8829a4aSRandall Stewart * We need to wait for more data a few things: - We don't 5882f8829a4aSRandall Stewart * sbunlock() so we don't get someone else reading. - We 5883f8829a4aSRandall Stewart * must be sure to account for the case where what is added 5884f8829a4aSRandall Stewart * is NOT to our control when we wakeup. 5885f8829a4aSRandall Stewart */ 5886f8829a4aSRandall Stewart 5887f8829a4aSRandall Stewart /* 5888f8829a4aSRandall Stewart * Do we need to tell the transport a rwnd update might be 5889f8829a4aSRandall Stewart * needed before we go to sleep? 5890f8829a4aSRandall Stewart */ 5891f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 5892f8829a4aSRandall Stewart ((freed_so_far >= rwnd_req) && 5893f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 5894f8829a4aSRandall Stewart (no_rcv_needed == 0))) { 5895f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5896f8829a4aSRandall Stewart } 5897f8829a4aSRandall Stewart wait_some_more: 589844b7479bSRandall Stewart if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { 5899f8829a4aSRandall Stewart goto release; 5900f8829a4aSRandall Stewart } 5901f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) 5902f8829a4aSRandall Stewart goto release; 5903f8829a4aSRandall Stewart 5904f8829a4aSRandall Stewart if (hold_rlock == 1) { 5905f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5906f8829a4aSRandall Stewart hold_rlock = 0; 5907f8829a4aSRandall Stewart } 5908f8829a4aSRandall Stewart if (hold_sblock == 0) { 5909f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5910f8829a4aSRandall Stewart hold_sblock = 1; 5911f8829a4aSRandall Stewart } 5912851b7298SRandall Stewart if ((copied_so_far) && (control->length == 0) && 5913b5c16493SMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) { 5914851b7298SRandall Stewart goto release; 5915851b7298SRandall Stewart } 5916f8829a4aSRandall Stewart if (so->so_rcv.sb_cc <= control->held_length) { 5917f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5918f8829a4aSRandall Stewart if (error) { 5919f8829a4aSRandall Stewart goto release; 5920f8829a4aSRandall Stewart } 5921f8829a4aSRandall Stewart control->held_length = 0; 5922f8829a4aSRandall Stewart } 5923f8829a4aSRandall Stewart if (hold_sblock) { 5924f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5925f8829a4aSRandall Stewart hold_sblock = 0; 5926f8829a4aSRandall Stewart } 5927f8829a4aSRandall Stewart if (control->length == 0) { 5928f8829a4aSRandall Stewart /* still nothing here */ 5929f8829a4aSRandall Stewart if (control->end_added == 1) { 5930f8829a4aSRandall Stewart /* he aborted, or is done i.e.did a shutdown */ 5931f8829a4aSRandall Stewart out_flags |= MSG_EOR; 59329a6142d8SRandall Stewart if (control->pdapi_aborted) { 59336114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5934ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 59359a6142d8SRandall Stewart 593603b0b021SRandall Stewart out_flags |= MSG_TRUNC; 59379a6142d8SRandall Stewart } else { 59386114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5939ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 59409a6142d8SRandall Stewart } 5941f8829a4aSRandall Stewart goto done_with_control; 5942f8829a4aSRandall Stewart } 5943f8829a4aSRandall Stewart if (so->so_rcv.sb_cc > held_length) { 5944f8829a4aSRandall Stewart control->held_length = so->so_rcv.sb_cc; 5945f8829a4aSRandall Stewart held_length = 0; 5946f8829a4aSRandall Stewart } 5947f8829a4aSRandall Stewart goto wait_some_more; 5948f8829a4aSRandall Stewart } else if (control->data == NULL) { 594950cec919SRandall Stewart /* 595050cec919SRandall Stewart * we must re-sync since data is probably being 595150cec919SRandall Stewart * added 595250cec919SRandall Stewart */ 595350cec919SRandall Stewart SCTP_INP_READ_LOCK(inp); 595450cec919SRandall Stewart if ((control->length > 0) && (control->data == NULL)) { 595550cec919SRandall Stewart /* 595650cec919SRandall Stewart * big trouble.. we have the lock and its 595750cec919SRandall Stewart * corrupt? 595850cec919SRandall Stewart */ 59599c04b296SRandall Stewart #ifdef INVARIANTS 5960f8829a4aSRandall Stewart panic("Impossible data==NULL length !=0"); 59619c04b296SRandall Stewart #endif 59629c04b296SRandall Stewart out_flags |= MSG_EOR; 59639c04b296SRandall Stewart out_flags |= MSG_TRUNC; 59649c04b296SRandall Stewart control->length = 0; 59659c04b296SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 59669c04b296SRandall Stewart goto done_with_control; 5967f8829a4aSRandall Stewart } 596850cec919SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 596950cec919SRandall Stewart /* We will fall around to get more data */ 597050cec919SRandall Stewart } 5971f8829a4aSRandall Stewart goto get_more_data; 5972f8829a4aSRandall Stewart } else { 597317205eccSRandall Stewart /*- 597417205eccSRandall Stewart * Give caller back the mbuf chain, 597517205eccSRandall Stewart * store in uio_resid the length 5976f8829a4aSRandall Stewart */ 597717205eccSRandall Stewart wakeup_read_socket = 0; 5978f8829a4aSRandall Stewart if ((control->end_added == 0) || 5979f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 5980f8829a4aSRandall Stewart /* Need to get rlock */ 5981f8829a4aSRandall Stewart if (hold_rlock == 0) { 5982f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5983f8829a4aSRandall Stewart hold_rlock = 1; 5984f8829a4aSRandall Stewart } 5985f8829a4aSRandall Stewart } 5986139bc87fSRandall Stewart if (control->end_added) { 5987f8829a4aSRandall Stewart out_flags |= MSG_EOR; 598860990c0cSMichael Tuexen if ((control->do_not_ref_stcb == 0) && 598960990c0cSMichael Tuexen (control->stcb != NULL) && 599060990c0cSMichael Tuexen ((control->spec_flags & M_NOTIFICATION) == 0)) 5991ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 5992f8829a4aSRandall Stewart } 5993139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5994f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5995f8829a4aSRandall Stewart } 599617205eccSRandall Stewart uio->uio_resid = control->length; 5997f8829a4aSRandall Stewart *mp = control->data; 5998f8829a4aSRandall Stewart m = control->data; 5999f8829a4aSRandall Stewart while (m) { 6000b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6001f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6002139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 600380fefe0aSRandall Stewart } 6004f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 6005139bc87fSRandall Stewart freed_so_far += SCTP_BUF_LEN(m); 6006c4739e2fSRandall Stewart freed_so_far += MSIZE; 6007b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 6008f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 6009f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 601080fefe0aSRandall Stewart } 6011139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 6012f8829a4aSRandall Stewart } 6013f8829a4aSRandall Stewart control->data = control->tail_mbuf = NULL; 6014f8829a4aSRandall Stewart control->length = 0; 6015f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 6016f8829a4aSRandall Stewart /* Done with this control */ 6017f8829a4aSRandall Stewart goto done_with_control; 6018f8829a4aSRandall Stewart } 6019f8829a4aSRandall Stewart } 6020f8829a4aSRandall Stewart release: 6021f8829a4aSRandall Stewart if (hold_rlock == 1) { 6022f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6023f8829a4aSRandall Stewart hold_rlock = 0; 6024f8829a4aSRandall Stewart } 60257abab911SRobert Watson if (hold_sblock == 1) { 60267abab911SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 60277abab911SRobert Watson hold_sblock = 0; 6028f8829a4aSRandall Stewart } 6029f8829a4aSRandall Stewart sbunlock(&so->so_rcv); 60307abab911SRobert Watson sockbuf_lock = 0; 6031f8829a4aSRandall Stewart 6032f8829a4aSRandall Stewart release_unlocked: 6033f8829a4aSRandall Stewart if (hold_sblock) { 6034f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6035f8829a4aSRandall Stewart hold_sblock = 0; 6036f8829a4aSRandall Stewart } 6037f8829a4aSRandall Stewart if ((stcb) && (in_flags & MSG_PEEK) == 0) { 6038f8829a4aSRandall Stewart if ((freed_so_far >= rwnd_req) && 6039f8829a4aSRandall Stewart (control && (control->do_not_ref_stcb == 0)) && 6040f8829a4aSRandall Stewart (no_rcv_needed == 0)) 6041f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 6042f8829a4aSRandall Stewart } 6043f8829a4aSRandall Stewart out: 60441b9f62a0SRandall Stewart if (msg_flags) { 60451b9f62a0SRandall Stewart *msg_flags = out_flags; 60461b9f62a0SRandall Stewart } 60479a6142d8SRandall Stewart if (((out_flags & MSG_EOR) == 0) && 60489a6142d8SRandall Stewart ((in_flags & MSG_PEEK) == 0) && 60499a6142d8SRandall Stewart (sinfo) && 6050e2e7c62eSMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 6051e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) { 60529a6142d8SRandall Stewart struct sctp_extrcvinfo *s_extra; 60539a6142d8SRandall Stewart 60549a6142d8SRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 60559a6142d8SRandall Stewart s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG; 60569a6142d8SRandall Stewart } 6057f8829a4aSRandall Stewart if (hold_rlock == 1) { 6058f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 6059f8829a4aSRandall Stewart } 6060f8829a4aSRandall Stewart if (hold_sblock) { 6061f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 6062f8829a4aSRandall Stewart } 60637abab911SRobert Watson if (sockbuf_lock) { 60647abab911SRobert Watson sbunlock(&so->so_rcv); 60657abab911SRobert Watson } 606650cec919SRandall Stewart if (freecnt_applied) { 6067f8829a4aSRandall Stewart /* 6068f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the free 6069f8829a4aSRandall Stewart * code will stop. But since we used the socketbuf lock and 6070f8829a4aSRandall Stewart * the sender uses the tcb_lock to increment, we need to use 6071f8829a4aSRandall Stewart * the atomic add to the refcnt. 6072f8829a4aSRandall Stewart */ 607350cec919SRandall Stewart if (stcb == NULL) { 6074df6e0cc3SRandall Stewart #ifdef INVARIANTS 607550cec919SRandall Stewart panic("stcb for refcnt has gone NULL?"); 6076df6e0cc3SRandall Stewart goto stage_left; 6077df6e0cc3SRandall Stewart #else 6078df6e0cc3SRandall Stewart goto stage_left; 6079df6e0cc3SRandall Stewart #endif 608050cec919SRandall Stewart } 608150cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 6082f8829a4aSRandall Stewart /* Save the value back for next time */ 6083f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = freed_so_far; 6084f8829a4aSRandall Stewart } 6085b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 6086f8829a4aSRandall Stewart if (stcb) { 6087f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6088f8829a4aSRandall Stewart freed_so_far, 6089f8829a4aSRandall Stewart ((uio) ? (slen - uio->uio_resid) : slen), 6090f8829a4aSRandall Stewart stcb->asoc.my_rwnd, 6091f8829a4aSRandall Stewart so->so_rcv.sb_cc); 6092f8829a4aSRandall Stewart } else { 6093f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 6094f8829a4aSRandall Stewart freed_so_far, 6095f8829a4aSRandall Stewart ((uio) ? (slen - uio->uio_resid) : slen), 6096f8829a4aSRandall Stewart 0, 6097f8829a4aSRandall Stewart so->so_rcv.sb_cc); 6098f8829a4aSRandall Stewart } 609980fefe0aSRandall Stewart } 6100df6e0cc3SRandall Stewart stage_left: 6101f8829a4aSRandall Stewart if (wakeup_read_socket) { 6102f8829a4aSRandall Stewart sctp_sorwakeup(inp, so); 6103f8829a4aSRandall Stewart } 6104f8829a4aSRandall Stewart return (error); 6105f8829a4aSRandall Stewart } 6106f8829a4aSRandall Stewart 6107f8829a4aSRandall Stewart 6108f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING 6109f8829a4aSRandall Stewart struct mbuf * 6110f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m) 6111f8829a4aSRandall Stewart { 6112b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 6113139bc87fSRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 6114f8829a4aSRandall Stewart sctp_log_mb(m, SCTP_MBUF_IFREE); 6115f8829a4aSRandall Stewart } 611680fefe0aSRandall Stewart } 6117f8829a4aSRandall Stewart return (m_free(m)); 6118f8829a4aSRandall Stewart } 6119f8829a4aSRandall Stewart 6120f8829a4aSRandall Stewart void 6121f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb) 6122f8829a4aSRandall Stewart { 6123f8829a4aSRandall Stewart while (mb != NULL) 6124f8829a4aSRandall Stewart mb = sctp_m_free(mb); 6125f8829a4aSRandall Stewart } 6126f8829a4aSRandall Stewart 6127f8829a4aSRandall Stewart #endif 6128f8829a4aSRandall Stewart 612942551e99SRandall Stewart int 613042551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) 613142551e99SRandall Stewart { 613242551e99SRandall Stewart /* 613342551e99SRandall Stewart * Given a local address. For all associations that holds the 613442551e99SRandall Stewart * address, request a peer-set-primary. 613542551e99SRandall Stewart */ 613642551e99SRandall Stewart struct sctp_ifa *ifa; 613742551e99SRandall Stewart struct sctp_laddr *wi; 613842551e99SRandall Stewart 613942551e99SRandall Stewart ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); 614042551e99SRandall Stewart if (ifa == NULL) { 6141c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); 614242551e99SRandall Stewart return (EADDRNOTAVAIL); 614342551e99SRandall Stewart } 614442551e99SRandall Stewart /* 614542551e99SRandall Stewart * Now that we have the ifa we must awaken the iterator with this 614642551e99SRandall Stewart * message. 614742551e99SRandall Stewart */ 6148b3f1ea41SRandall Stewart wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); 614942551e99SRandall Stewart if (wi == NULL) { 6150c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 615142551e99SRandall Stewart return (ENOMEM); 615242551e99SRandall Stewart } 615342551e99SRandall Stewart /* Now incr the count and int wi structure */ 615442551e99SRandall Stewart SCTP_INCR_LADDR_COUNT(); 615542551e99SRandall Stewart bzero(wi, sizeof(*wi)); 6156d61a0ae0SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); 615742551e99SRandall Stewart wi->ifa = ifa; 615842551e99SRandall Stewart wi->action = SCTP_SET_PRIM_ADDR; 615942551e99SRandall Stewart atomic_add_int(&ifa->refcount, 1); 616042551e99SRandall Stewart 616142551e99SRandall Stewart /* Now add it to the work queue */ 6162f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 616342551e99SRandall Stewart /* 616442551e99SRandall Stewart * Should this really be a tailq? As it is we will process the 616542551e99SRandall Stewart * newest first :-0 616642551e99SRandall Stewart */ 6167b3f1ea41SRandall Stewart LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 6168f7517433SRandall Stewart SCTP_WQ_ADDR_UNLOCK(); 616942551e99SRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 617042551e99SRandall Stewart (struct sctp_inpcb *)NULL, 617142551e99SRandall Stewart (struct sctp_tcb *)NULL, 617242551e99SRandall Stewart (struct sctp_nets *)NULL); 617342551e99SRandall Stewart return (0); 617442551e99SRandall Stewart } 617542551e99SRandall Stewart 617642551e99SRandall Stewart 6177f8829a4aSRandall Stewart int 617817205eccSRandall Stewart sctp_soreceive(struct socket *so, 617917205eccSRandall Stewart struct sockaddr **psa, 618017205eccSRandall Stewart struct uio *uio, 618117205eccSRandall Stewart struct mbuf **mp0, 618217205eccSRandall Stewart struct mbuf **controlp, 618317205eccSRandall Stewart int *flagsp) 6184f8829a4aSRandall Stewart { 6185f8829a4aSRandall Stewart int error, fromlen; 6186f8829a4aSRandall Stewart uint8_t sockbuf[256]; 6187f8829a4aSRandall Stewart struct sockaddr *from; 6188f8829a4aSRandall Stewart struct sctp_extrcvinfo sinfo; 6189f8829a4aSRandall Stewart int filling_sinfo = 1; 6190f8829a4aSRandall Stewart struct sctp_inpcb *inp; 6191f8829a4aSRandall Stewart 6192f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 6193f8829a4aSRandall Stewart /* pickup the assoc we are reading from */ 6194f8829a4aSRandall Stewart if (inp == NULL) { 6195c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6196f8829a4aSRandall Stewart return (EINVAL); 6197f8829a4aSRandall Stewart } 6198e2e7c62eSMichael Tuexen if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && 6199e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && 6200e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) || 6201f8829a4aSRandall Stewart (controlp == NULL)) { 6202f8829a4aSRandall Stewart /* user does not want the sndrcv ctl */ 6203f8829a4aSRandall Stewart filling_sinfo = 0; 6204f8829a4aSRandall Stewart } 6205f8829a4aSRandall Stewart if (psa) { 6206f8829a4aSRandall Stewart from = (struct sockaddr *)sockbuf; 6207f8829a4aSRandall Stewart fromlen = sizeof(sockbuf); 6208f8829a4aSRandall Stewart from->sa_len = 0; 6209f8829a4aSRandall Stewart } else { 6210f8829a4aSRandall Stewart from = NULL; 6211f8829a4aSRandall Stewart fromlen = 0; 6212f8829a4aSRandall Stewart } 6213f8829a4aSRandall Stewart 6214f8829a4aSRandall Stewart error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, flagsp, 6215f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo); 6216f8829a4aSRandall Stewart if ((controlp) && (filling_sinfo)) { 6217f8829a4aSRandall Stewart /* copy back the sinfo in a CMSG format */ 6218f8829a4aSRandall Stewart if (filling_sinfo) 6219f8829a4aSRandall Stewart *controlp = sctp_build_ctl_nchunk(inp, 6220f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo); 6221f8829a4aSRandall Stewart else 6222f8829a4aSRandall Stewart *controlp = NULL; 6223f8829a4aSRandall Stewart } 6224f8829a4aSRandall Stewart if (psa) { 6225f8829a4aSRandall Stewart /* copy back the address info */ 6226f8829a4aSRandall Stewart if (from && from->sa_len) { 6227f8829a4aSRandall Stewart *psa = sodupsockaddr(from, M_NOWAIT); 6228f8829a4aSRandall Stewart } else { 6229f8829a4aSRandall Stewart *psa = NULL; 6230f8829a4aSRandall Stewart } 6231f8829a4aSRandall Stewart } 6232f8829a4aSRandall Stewart return (error); 6233f8829a4aSRandall Stewart } 623417205eccSRandall Stewart 623517205eccSRandall Stewart 623617205eccSRandall Stewart 623717205eccSRandall Stewart 623817205eccSRandall Stewart 623917205eccSRandall Stewart int 6240d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, 6241d61a0ae0SRandall Stewart int totaddr, int *error) 624217205eccSRandall Stewart { 624317205eccSRandall Stewart int added = 0; 624417205eccSRandall Stewart int i; 624517205eccSRandall Stewart struct sctp_inpcb *inp; 624617205eccSRandall Stewart struct sockaddr *sa; 624717205eccSRandall Stewart size_t incr = 0; 624817205eccSRandall Stewart 624992776dfdSMichael Tuexen #ifdef INET 625092776dfdSMichael Tuexen struct sockaddr_in *sin; 625192776dfdSMichael Tuexen 625292776dfdSMichael Tuexen #endif 625392776dfdSMichael Tuexen #ifdef INET6 625492776dfdSMichael Tuexen struct sockaddr_in6 *sin6; 625592776dfdSMichael Tuexen 625692776dfdSMichael Tuexen #endif 625792776dfdSMichael Tuexen 625817205eccSRandall Stewart sa = addr; 625917205eccSRandall Stewart inp = stcb->sctp_ep; 626017205eccSRandall Stewart *error = 0; 626117205eccSRandall Stewart for (i = 0; i < totaddr; i++) { 6262ea5eba11SMichael Tuexen switch (sa->sa_family) { 6263ea5eba11SMichael Tuexen #ifdef INET 6264ea5eba11SMichael Tuexen case AF_INET: 626517205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 626692776dfdSMichael Tuexen sin = (struct sockaddr_in *)sa; 626792776dfdSMichael Tuexen if ((sin->sin_addr.s_addr == INADDR_ANY) || 626892776dfdSMichael Tuexen (sin->sin_addr.s_addr == INADDR_BROADCAST) || 626992776dfdSMichael Tuexen IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 627092776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 627192776dfdSMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 627292776dfdSMichael Tuexen *error = EINVAL; 627392776dfdSMichael Tuexen goto out_now; 627492776dfdSMichael Tuexen } 6275ca85e948SMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { 627617205eccSRandall Stewart /* assoc gone no un-lock */ 6277c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6278c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 627917205eccSRandall Stewart *error = ENOBUFS; 628017205eccSRandall Stewart goto out_now; 628117205eccSRandall Stewart } 628217205eccSRandall Stewart added++; 6283ea5eba11SMichael Tuexen break; 6284ea5eba11SMichael Tuexen #endif 6285ea5eba11SMichael Tuexen #ifdef INET6 6286ea5eba11SMichael Tuexen case AF_INET6: 628717205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 628892776dfdSMichael Tuexen sin6 = (struct sockaddr_in6 *)sa; 628992776dfdSMichael Tuexen if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 629092776dfdSMichael Tuexen IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 629192776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 629292776dfdSMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); 629392776dfdSMichael Tuexen *error = EINVAL; 629492776dfdSMichael Tuexen goto out_now; 629592776dfdSMichael Tuexen } 6296ca85e948SMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { 629717205eccSRandall Stewart /* assoc gone no un-lock */ 6298c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6299c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); 630017205eccSRandall Stewart *error = ENOBUFS; 630117205eccSRandall Stewart goto out_now; 630217205eccSRandall Stewart } 630317205eccSRandall Stewart added++; 6304ea5eba11SMichael Tuexen break; 6305ea5eba11SMichael Tuexen #endif 6306ea5eba11SMichael Tuexen default: 6307ea5eba11SMichael Tuexen break; 630817205eccSRandall Stewart } 630917205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 631017205eccSRandall Stewart } 631117205eccSRandall Stewart out_now: 631217205eccSRandall Stewart return (added); 631317205eccSRandall Stewart } 631417205eccSRandall Stewart 631517205eccSRandall Stewart struct sctp_tcb * 6316d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, 6317d61a0ae0SRandall Stewart int *totaddr, int *num_v4, int *num_v6, int *error, 6318d61a0ae0SRandall Stewart int limit, int *bad_addr) 631917205eccSRandall Stewart { 632017205eccSRandall Stewart struct sockaddr *sa; 632117205eccSRandall Stewart struct sctp_tcb *stcb = NULL; 632217205eccSRandall Stewart size_t incr, at, i; 632317205eccSRandall Stewart 632417205eccSRandall Stewart at = incr = 0; 632517205eccSRandall Stewart sa = addr; 6326ea5eba11SMichael Tuexen 632717205eccSRandall Stewart *error = *num_v6 = *num_v4 = 0; 632817205eccSRandall Stewart /* account and validate addresses */ 63294c9179adSRandall Stewart for (i = 0; i < (size_t)*totaddr; i++) { 6330ea5eba11SMichael Tuexen switch (sa->sa_family) { 6331ea5eba11SMichael Tuexen #ifdef INET 6332ea5eba11SMichael Tuexen case AF_INET: 633317205eccSRandall Stewart (*num_v4) += 1; 633417205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 6335d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6336c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6337d61a0ae0SRandall Stewart *error = EINVAL; 6338d61a0ae0SRandall Stewart *bad_addr = 1; 6339d61a0ae0SRandall Stewart return (NULL); 6340d61a0ae0SRandall Stewart } 6341ea5eba11SMichael Tuexen break; 6342ea5eba11SMichael Tuexen #endif 6343ea5eba11SMichael Tuexen #ifdef INET6 6344ea5eba11SMichael Tuexen case AF_INET6: 6345ea5eba11SMichael Tuexen { 634617205eccSRandall Stewart struct sockaddr_in6 *sin6; 634717205eccSRandall Stewart 634817205eccSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 634917205eccSRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 635017205eccSRandall Stewart /* Must be non-mapped for connectx */ 6351c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 635217205eccSRandall Stewart *error = EINVAL; 6353d61a0ae0SRandall Stewart *bad_addr = 1; 635417205eccSRandall Stewart return (NULL); 635517205eccSRandall Stewart } 635617205eccSRandall Stewart (*num_v6) += 1; 635717205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 6358d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6359c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6360d61a0ae0SRandall Stewart *error = EINVAL; 6361d61a0ae0SRandall Stewart *bad_addr = 1; 6362d61a0ae0SRandall Stewart return (NULL); 6363d61a0ae0SRandall Stewart } 6364ea5eba11SMichael Tuexen break; 6365ea5eba11SMichael Tuexen } 6366ea5eba11SMichael Tuexen #endif 6367ea5eba11SMichael Tuexen default: 636817205eccSRandall Stewart *totaddr = i; 636917205eccSRandall Stewart /* we are done */ 637017205eccSRandall Stewart break; 637117205eccSRandall Stewart } 6372ea5eba11SMichael Tuexen if (i == (size_t)*totaddr) { 6373ea5eba11SMichael Tuexen break; 6374ea5eba11SMichael Tuexen } 6375d61a0ae0SRandall Stewart SCTP_INP_INCR_REF(inp); 637617205eccSRandall Stewart stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 637717205eccSRandall Stewart if (stcb != NULL) { 637817205eccSRandall Stewart /* Already have or am bring up an association */ 637917205eccSRandall Stewart return (stcb); 6380d61a0ae0SRandall Stewart } else { 6381d61a0ae0SRandall Stewart SCTP_INP_DECR_REF(inp); 638217205eccSRandall Stewart } 63834c9179adSRandall Stewart if ((at + incr) > (size_t)limit) { 638417205eccSRandall Stewart *totaddr = i; 638517205eccSRandall Stewart break; 638617205eccSRandall Stewart } 638717205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 638817205eccSRandall Stewart } 638917205eccSRandall Stewart return ((struct sctp_tcb *)NULL); 639017205eccSRandall Stewart } 639135918f85SRandall Stewart 639235918f85SRandall Stewart /* 639335918f85SRandall Stewart * sctp_bindx(ADD) for one address. 639435918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 639535918f85SRandall Stewart */ 639635918f85SRandall Stewart void 639735918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, 639835918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 639935918f85SRandall Stewart uint32_t vrf_id, int *error, void *p) 640035918f85SRandall Stewart { 640135918f85SRandall Stewart struct sockaddr *addr_touse; 64025e2c2d87SRandall Stewart 64035e2c2d87SRandall Stewart #ifdef INET6 640435918f85SRandall Stewart struct sockaddr_in sin; 640535918f85SRandall Stewart 64065e2c2d87SRandall Stewart #endif 64075e2c2d87SRandall Stewart 640835918f85SRandall Stewart /* see if we're bound all already! */ 640935918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6410c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 641135918f85SRandall Stewart *error = EINVAL; 641235918f85SRandall Stewart return; 641335918f85SRandall Stewart } 641435918f85SRandall Stewart addr_touse = sa; 6415ea5eba11SMichael Tuexen #ifdef INET6 641635918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 641735918f85SRandall Stewart struct sockaddr_in6 *sin6; 641835918f85SRandall Stewart 641935918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6420c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 642135918f85SRandall Stewart *error = EINVAL; 642235918f85SRandall Stewart return; 642335918f85SRandall Stewart } 6424db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6425db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6426c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6427db4fd95bSRandall Stewart *error = EINVAL; 6428db4fd95bSRandall Stewart return; 6429db4fd95bSRandall Stewart } 643035918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 643135918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6432db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6433db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6434db4fd95bSRandall Stewart /* can't bind v4-mapped on PF_INET sockets */ 6435c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6436db4fd95bSRandall Stewart *error = EINVAL; 6437db4fd95bSRandall Stewart return; 6438db4fd95bSRandall Stewart } 643935918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 644035918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 644135918f85SRandall Stewart } 644235918f85SRandall Stewart } 644335918f85SRandall Stewart #endif 6444ea5eba11SMichael Tuexen #ifdef INET 644535918f85SRandall Stewart if (sa->sa_family == AF_INET) { 644635918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6447c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 644835918f85SRandall Stewart *error = EINVAL; 644935918f85SRandall Stewart return; 645035918f85SRandall Stewart } 6451db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6452db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6453db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6454c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6455db4fd95bSRandall Stewart *error = EINVAL; 6456db4fd95bSRandall Stewart return; 6457db4fd95bSRandall Stewart } 645835918f85SRandall Stewart } 6459ea5eba11SMichael Tuexen #endif 646035918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 646135918f85SRandall Stewart if (p == NULL) { 646235918f85SRandall Stewart /* Can't get proc for Net/Open BSD */ 6463c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 646435918f85SRandall Stewart *error = EINVAL; 646535918f85SRandall Stewart return; 646635918f85SRandall Stewart } 64671b649582SRandall Stewart *error = sctp_inpcb_bind(so, addr_touse, NULL, p); 646835918f85SRandall Stewart return; 646935918f85SRandall Stewart } 647035918f85SRandall Stewart /* 647135918f85SRandall Stewart * No locks required here since bind and mgmt_ep_sa all do their own 647235918f85SRandall Stewart * locking. If we do something for the FIX: below we may need to 647335918f85SRandall Stewart * lock in that case. 647435918f85SRandall Stewart */ 647535918f85SRandall Stewart if (assoc_id == 0) { 647635918f85SRandall Stewart /* add the address */ 647735918f85SRandall Stewart struct sctp_inpcb *lep; 647897c76f10SRandall Stewart struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse; 647935918f85SRandall Stewart 648097c76f10SRandall Stewart /* validate the incoming port */ 648197c76f10SRandall Stewart if ((lsin->sin_port != 0) && 648297c76f10SRandall Stewart (lsin->sin_port != inp->sctp_lport)) { 6483c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 648497c76f10SRandall Stewart *error = EINVAL; 648597c76f10SRandall Stewart return; 648697c76f10SRandall Stewart } else { 648797c76f10SRandall Stewart /* user specified 0 port, set it to existing port */ 648897c76f10SRandall Stewart lsin->sin_port = inp->sctp_lport; 648997c76f10SRandall Stewart } 649097c76f10SRandall Stewart 649135918f85SRandall Stewart lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id); 649235918f85SRandall Stewart if (lep != NULL) { 649335918f85SRandall Stewart /* 649435918f85SRandall Stewart * We must decrement the refcount since we have the 649535918f85SRandall Stewart * ep already and are binding. No remove going on 649635918f85SRandall Stewart * here. 649735918f85SRandall Stewart */ 64986d9e8f2bSRandall Stewart SCTP_INP_DECR_REF(lep); 649935918f85SRandall Stewart } 650035918f85SRandall Stewart if (lep == inp) { 650135918f85SRandall Stewart /* already bound to it.. ok */ 650235918f85SRandall Stewart return; 650335918f85SRandall Stewart } else if (lep == NULL) { 650435918f85SRandall Stewart ((struct sockaddr_in *)addr_touse)->sin_port = 0; 650535918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 650635918f85SRandall Stewart SCTP_ADD_IP_ADDRESS, 650780fefe0aSRandall Stewart vrf_id, NULL); 650835918f85SRandall Stewart } else { 650935918f85SRandall Stewart *error = EADDRINUSE; 651035918f85SRandall Stewart } 651135918f85SRandall Stewart if (*error) 651235918f85SRandall Stewart return; 651335918f85SRandall Stewart } else { 651435918f85SRandall Stewart /* 651535918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 651635918f85SRandall Stewart */ 651735918f85SRandall Stewart } 651835918f85SRandall Stewart } 651935918f85SRandall Stewart 652035918f85SRandall Stewart /* 652135918f85SRandall Stewart * sctp_bindx(DELETE) for one address. 652235918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 652335918f85SRandall Stewart */ 652435918f85SRandall Stewart void 65257215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp, 652635918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 652735918f85SRandall Stewart uint32_t vrf_id, int *error) 652835918f85SRandall Stewart { 652935918f85SRandall Stewart struct sockaddr *addr_touse; 65305e2c2d87SRandall Stewart 65315e2c2d87SRandall Stewart #ifdef INET6 653235918f85SRandall Stewart struct sockaddr_in sin; 653335918f85SRandall Stewart 65345e2c2d87SRandall Stewart #endif 65355e2c2d87SRandall Stewart 653635918f85SRandall Stewart /* see if we're bound all already! */ 653735918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6538c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 653935918f85SRandall Stewart *error = EINVAL; 654035918f85SRandall Stewart return; 654135918f85SRandall Stewart } 654235918f85SRandall Stewart addr_touse = sa; 6543e0e00a4dSMichael Tuexen #ifdef INET6 654435918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 654535918f85SRandall Stewart struct sockaddr_in6 *sin6; 654635918f85SRandall Stewart 654735918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6548c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 654935918f85SRandall Stewart *error = EINVAL; 655035918f85SRandall Stewart return; 655135918f85SRandall Stewart } 6552db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6553db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6554c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6555db4fd95bSRandall Stewart *error = EINVAL; 6556db4fd95bSRandall Stewart return; 6557db4fd95bSRandall Stewart } 655835918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 655935918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6560db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6561db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6562db4fd95bSRandall Stewart /* can't bind mapped-v4 on PF_INET sockets */ 6563c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6564db4fd95bSRandall Stewart *error = EINVAL; 6565db4fd95bSRandall Stewart return; 6566db4fd95bSRandall Stewart } 656735918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 656835918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 656935918f85SRandall Stewart } 657035918f85SRandall Stewart } 657135918f85SRandall Stewart #endif 6572ea5eba11SMichael Tuexen #ifdef INET 657335918f85SRandall Stewart if (sa->sa_family == AF_INET) { 657435918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6575c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 657635918f85SRandall Stewart *error = EINVAL; 657735918f85SRandall Stewart return; 657835918f85SRandall Stewart } 6579db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6580db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6581db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6582c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6583db4fd95bSRandall Stewart *error = EINVAL; 6584db4fd95bSRandall Stewart return; 6585db4fd95bSRandall Stewart } 658635918f85SRandall Stewart } 6587ea5eba11SMichael Tuexen #endif 658835918f85SRandall Stewart /* 658935918f85SRandall Stewart * No lock required mgmt_ep_sa does its own locking. If the FIX: 659035918f85SRandall Stewart * below is ever changed we may need to lock before calling 659135918f85SRandall Stewart * association level binding. 659235918f85SRandall Stewart */ 659335918f85SRandall Stewart if (assoc_id == 0) { 659435918f85SRandall Stewart /* delete the address */ 659535918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 659635918f85SRandall Stewart SCTP_DEL_IP_ADDRESS, 659780fefe0aSRandall Stewart vrf_id, NULL); 659835918f85SRandall Stewart } else { 659935918f85SRandall Stewart /* 660035918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 660135918f85SRandall Stewart */ 660235918f85SRandall Stewart } 660335918f85SRandall Stewart } 66041b649582SRandall Stewart 66051b649582SRandall Stewart /* 66061b649582SRandall Stewart * returns the valid local address count for an assoc, taking into account 66071b649582SRandall Stewart * all scoping rules 66081b649582SRandall Stewart */ 66091b649582SRandall Stewart int 66101b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb) 66111b649582SRandall Stewart { 66121b649582SRandall Stewart int loopback_scope, ipv4_local_scope, local_scope, site_scope; 66131b649582SRandall Stewart int ipv4_addr_legal, ipv6_addr_legal; 66141b649582SRandall Stewart struct sctp_vrf *vrf; 66151b649582SRandall Stewart struct sctp_ifn *sctp_ifn; 66161b649582SRandall Stewart struct sctp_ifa *sctp_ifa; 66171b649582SRandall Stewart int count = 0; 66181b649582SRandall Stewart 66191b649582SRandall Stewart /* Turn on all the appropriate scopes */ 66201b649582SRandall Stewart loopback_scope = stcb->asoc.loopback_scope; 66211b649582SRandall Stewart ipv4_local_scope = stcb->asoc.ipv4_local_scope; 66221b649582SRandall Stewart local_scope = stcb->asoc.local_scope; 66231b649582SRandall Stewart site_scope = stcb->asoc.site_scope; 66241b649582SRandall Stewart ipv4_addr_legal = ipv6_addr_legal = 0; 66251b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 66261b649582SRandall Stewart ipv6_addr_legal = 1; 66271b649582SRandall Stewart if (SCTP_IPV6_V6ONLY(stcb->sctp_ep) == 0) { 66281b649582SRandall Stewart ipv4_addr_legal = 1; 66291b649582SRandall Stewart } 66301b649582SRandall Stewart } else { 66311b649582SRandall Stewart ipv4_addr_legal = 1; 66321b649582SRandall Stewart } 66331b649582SRandall Stewart 6634c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 66351b649582SRandall Stewart vrf = sctp_find_vrf(stcb->asoc.vrf_id); 66361b649582SRandall Stewart if (vrf == NULL) { 66371b649582SRandall Stewart /* no vrf, no addresses */ 6638c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 66391b649582SRandall Stewart return (0); 66401b649582SRandall Stewart } 66411b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 66421b649582SRandall Stewart /* 66431b649582SRandall Stewart * bound all case: go through all ifns on the vrf 66441b649582SRandall Stewart */ 66451b649582SRandall Stewart LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 66461b649582SRandall Stewart if ((loopback_scope == 0) && 66471b649582SRandall Stewart SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 66481b649582SRandall Stewart continue; 66491b649582SRandall Stewart } 66501b649582SRandall Stewart LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 66511b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, sctp_ifa)) 66521b649582SRandall Stewart continue; 66535e2c2d87SRandall Stewart switch (sctp_ifa->address.sa.sa_family) { 6654ea5eba11SMichael Tuexen #ifdef INET 66555e2c2d87SRandall Stewart case AF_INET: 66565e2c2d87SRandall Stewart if (ipv4_addr_legal) { 66571b649582SRandall Stewart struct sockaddr_in *sin; 66581b649582SRandall Stewart 66591b649582SRandall Stewart sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 66601b649582SRandall Stewart if (sin->sin_addr.s_addr == 0) { 66615e2c2d87SRandall Stewart /* 66625e2c2d87SRandall Stewart * skip unspecified 66635e2c2d87SRandall Stewart * addrs 66645e2c2d87SRandall Stewart */ 66651b649582SRandall Stewart continue; 66661b649582SRandall Stewart } 66671b649582SRandall Stewart if ((ipv4_local_scope == 0) && 66681b649582SRandall Stewart (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 66691b649582SRandall Stewart continue; 66701b649582SRandall Stewart } 66711b649582SRandall Stewart /* count this one */ 66721b649582SRandall Stewart count++; 66735e2c2d87SRandall Stewart } else { 66745e2c2d87SRandall Stewart continue; 66755e2c2d87SRandall Stewart } 66765e2c2d87SRandall Stewart break; 6677ea5eba11SMichael Tuexen #endif 66785e2c2d87SRandall Stewart #ifdef INET6 66795e2c2d87SRandall Stewart case AF_INET6: 66805e2c2d87SRandall Stewart if (ipv6_addr_legal) { 66811b649582SRandall Stewart struct sockaddr_in6 *sin6; 66821b649582SRandall Stewart 66831b649582SRandall Stewart sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 66841b649582SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 66851b649582SRandall Stewart continue; 66861b649582SRandall Stewart } 66871b649582SRandall Stewart if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 66881b649582SRandall Stewart if (local_scope == 0) 66891b649582SRandall Stewart continue; 66901b649582SRandall Stewart if (sin6->sin6_scope_id == 0) { 66911b649582SRandall Stewart if (sa6_recoverscope(sin6) != 0) 66921b649582SRandall Stewart /* 66935e2c2d87SRandall Stewart * 66945e2c2d87SRandall Stewart * bad 66955e2c2d87SRandall Stewart * 66965e2c2d87SRandall Stewart * li 66975e2c2d87SRandall Stewart * nk 66985e2c2d87SRandall Stewart * 66995e2c2d87SRandall Stewart * loc 67005e2c2d87SRandall Stewart * al 67015e2c2d87SRandall Stewart * 67025e2c2d87SRandall Stewart * add 67035e2c2d87SRandall Stewart * re 67045e2c2d87SRandall Stewart * ss 67055e2c2d87SRandall Stewart * */ 67061b649582SRandall Stewart continue; 67071b649582SRandall Stewart } 67081b649582SRandall Stewart } 67091b649582SRandall Stewart if ((site_scope == 0) && 67101b649582SRandall Stewart (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 67111b649582SRandall Stewart continue; 67121b649582SRandall Stewart } 67131b649582SRandall Stewart /* count this one */ 67141b649582SRandall Stewart count++; 67151b649582SRandall Stewart } 67165e2c2d87SRandall Stewart break; 67175e2c2d87SRandall Stewart #endif 67185e2c2d87SRandall Stewart default: 67195e2c2d87SRandall Stewart /* TSNH */ 67205e2c2d87SRandall Stewart break; 67215e2c2d87SRandall Stewart } 67221b649582SRandall Stewart } 67231b649582SRandall Stewart } 67241b649582SRandall Stewart } else { 67251b649582SRandall Stewart /* 67261b649582SRandall Stewart * subset bound case 67271b649582SRandall Stewart */ 67281b649582SRandall Stewart struct sctp_laddr *laddr; 67291b649582SRandall Stewart 67301b649582SRandall Stewart LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, 67311b649582SRandall Stewart sctp_nxt_addr) { 67321b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 67331b649582SRandall Stewart continue; 67341b649582SRandall Stewart } 67351b649582SRandall Stewart /* count this one */ 67361b649582SRandall Stewart count++; 67371b649582SRandall Stewart } 67381b649582SRandall Stewart } 6739c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 67401b649582SRandall Stewart return (count); 67411b649582SRandall Stewart } 6742c4739e2fSRandall Stewart 6743c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF) 6744c4739e2fSRandall Stewart 6745c4739e2fSRandall Stewart void 6746b27a6b7dSRandall 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) 6747c4739e2fSRandall Stewart { 6748b27a6b7dSRandall Stewart uint32_t saveindex, newindex; 6749c4739e2fSRandall Stewart 6750c4739e2fSRandall Stewart do { 6751b3f1ea41SRandall Stewart saveindex = SCTP_BASE_SYSCTL(sctp_log).index; 6752c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 6753c4739e2fSRandall Stewart newindex = 1; 6754c4739e2fSRandall Stewart } else { 6755c4739e2fSRandall Stewart newindex = saveindex + 1; 6756c4739e2fSRandall Stewart } 6757b3f1ea41SRandall Stewart } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0); 6758c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 6759c4739e2fSRandall Stewart saveindex = 0; 6760c4739e2fSRandall Stewart } 6761b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; 6762b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys; 6763b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a; 6764b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b; 6765b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c; 6766b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d; 6767b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e; 6768b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f; 6769c4739e2fSRandall Stewart } 6770c4739e2fSRandall Stewart 6771c4739e2fSRandall Stewart #endif 6772ea5eba11SMichael Tuexen /* XXX: Remove the #ifdef after tunneling over IPv6 works also on FreeBSD. */ 6773ea5eba11SMichael Tuexen #ifdef INET 6774c54a18d2SRandall Stewart /* We will need to add support 6775c54a18d2SRandall Stewart * to bind the ports and such here 6776c54a18d2SRandall Stewart * so we can do UDP tunneling. In 6777c54a18d2SRandall Stewart * the mean-time, we return error 6778c54a18d2SRandall Stewart */ 6779a99b6783SRandall Stewart #include <netinet/udp.h> 6780a99b6783SRandall Stewart #include <netinet/udp_var.h> 6781a99b6783SRandall Stewart #include <sys/proc.h> 6782a1f2f7a5SRandall Stewart #ifdef INET6 6783a99b6783SRandall Stewart #include <netinet6/sctp6_var.h> 6784a1f2f7a5SRandall Stewart #endif 6785a99b6783SRandall Stewart 6786a99b6783SRandall Stewart static void 6787a99b6783SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored) 6788a99b6783SRandall Stewart { 6789a99b6783SRandall Stewart struct ip *iph; 6790a99b6783SRandall Stewart struct mbuf *sp, *last; 6791a99b6783SRandall Stewart struct udphdr *uhdr; 6792285052f0SMichael Tuexen uint16_t port; 6793a99b6783SRandall Stewart 6794a99b6783SRandall Stewart if ((m->m_flags & M_PKTHDR) == 0) { 6795a99b6783SRandall Stewart /* Can't handle one that is not a pkt hdr */ 6796a99b6783SRandall Stewart goto out; 6797a99b6783SRandall Stewart } 6798285052f0SMichael Tuexen /* Pull the src port */ 6799a99b6783SRandall Stewart iph = mtod(m, struct ip *); 6800a99b6783SRandall Stewart uhdr = (struct udphdr *)((caddr_t)iph + off); 6801a99b6783SRandall Stewart port = uhdr->uh_sport; 6802285052f0SMichael Tuexen /* 6803285052f0SMichael Tuexen * Split out the mbuf chain. Leave the IP header in m, place the 6804285052f0SMichael Tuexen * rest in the sp. 6805285052f0SMichael Tuexen */ 6806a99b6783SRandall Stewart sp = m_split(m, off, M_DONTWAIT); 6807a99b6783SRandall Stewart if (sp == NULL) { 6808a99b6783SRandall Stewart /* Gak, drop packet, we can't do a split */ 6809a99b6783SRandall Stewart goto out; 6810a99b6783SRandall Stewart } 6811285052f0SMichael Tuexen if (sp->m_pkthdr.len < sizeof(struct udphdr) + sizeof(struct sctphdr)) { 6812285052f0SMichael Tuexen /* Gak, packet can't have an SCTP header in it - too small */ 6813a99b6783SRandall Stewart m_freem(sp); 6814a99b6783SRandall Stewart goto out; 6815a99b6783SRandall Stewart } 6816285052f0SMichael Tuexen /* Now pull up the UDP header and SCTP header together */ 6817285052f0SMichael Tuexen sp = m_pullup(sp, sizeof(struct udphdr) + sizeof(struct sctphdr)); 6818a99b6783SRandall Stewart if (sp == NULL) { 6819a99b6783SRandall Stewart /* Gak pullup failed */ 6820a99b6783SRandall Stewart goto out; 6821a99b6783SRandall Stewart } 6822285052f0SMichael Tuexen /* Trim out the UDP header */ 6823a99b6783SRandall Stewart m_adj(sp, sizeof(struct udphdr)); 6824a99b6783SRandall Stewart 6825a99b6783SRandall Stewart /* Now reconstruct the mbuf chain */ 6826285052f0SMichael Tuexen for (last = m; last->m_next; last = last->m_next); 6827a99b6783SRandall Stewart last->m_next = sp; 6828a99b6783SRandall Stewart m->m_pkthdr.len += sp->m_pkthdr.len; 6829a99b6783SRandall Stewart iph = mtod(m, struct ip *); 6830a99b6783SRandall Stewart switch (iph->ip_v) { 6831e6194c2eSMichael Tuexen #ifdef INET 6832a99b6783SRandall Stewart case IPVERSION: 683309c1c856SMichael Tuexen iph->ip_len = htons(ntohs(iph->ip_len) - sizeof(struct udphdr)); 6834a99b6783SRandall Stewart sctp_input_with_port(m, off, port); 6835a99b6783SRandall Stewart break; 6836e6194c2eSMichael Tuexen #endif 6837a99b6783SRandall Stewart #ifdef INET6 6838a99b6783SRandall Stewart case IPV6_VERSION >> 4: 6839285052f0SMichael Tuexen /* Not yet supported. */ 6840a99b6783SRandall Stewart goto out; 6841a99b6783SRandall Stewart break; 6842a99b6783SRandall Stewart 6843a99b6783SRandall Stewart #endif 6844a99b6783SRandall Stewart default: 6845285052f0SMichael Tuexen goto out; 6846a99b6783SRandall Stewart break; 6847a99b6783SRandall Stewart } 6848a99b6783SRandall Stewart return; 6849a99b6783SRandall Stewart out: 6850a99b6783SRandall Stewart m_freem(m); 6851a99b6783SRandall Stewart } 6852c54a18d2SRandall Stewart 6853c54a18d2SRandall Stewart void 6854c54a18d2SRandall Stewart sctp_over_udp_stop(void) 6855c54a18d2SRandall Stewart { 6856a99b6783SRandall Stewart struct socket *sop; 6857a99b6783SRandall Stewart 6858a99b6783SRandall Stewart /* 6859a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 6860a99b6783SRandall Stewart * for writting! 6861a99b6783SRandall Stewart */ 6862a99b6783SRandall Stewart if (SCTP_BASE_INFO(udp_tun_socket) == NULL) { 6863a99b6783SRandall Stewart /* Nothing to do */ 6864c54a18d2SRandall Stewart return; 6865c54a18d2SRandall Stewart } 6866a99b6783SRandall Stewart sop = SCTP_BASE_INFO(udp_tun_socket); 6867a99b6783SRandall Stewart soclose(sop); 6868a99b6783SRandall Stewart SCTP_BASE_INFO(udp_tun_socket) = NULL; 6869a99b6783SRandall Stewart } 6870ea5eba11SMichael Tuexen 6871c54a18d2SRandall Stewart int 6872c54a18d2SRandall Stewart sctp_over_udp_start(void) 6873c54a18d2SRandall Stewart { 6874a99b6783SRandall Stewart uint16_t port; 6875a99b6783SRandall Stewart int ret; 6876a99b6783SRandall Stewart struct sockaddr_in sin; 6877a99b6783SRandall Stewart struct socket *sop = NULL; 6878a99b6783SRandall Stewart struct thread *th; 6879a99b6783SRandall Stewart struct ucred *cred; 6880a99b6783SRandall Stewart 6881a99b6783SRandall Stewart /* 6882a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 6883a99b6783SRandall Stewart * for writting! 6884a99b6783SRandall Stewart */ 6885a99b6783SRandall Stewart port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); 6886a99b6783SRandall Stewart if (port == 0) { 6887a99b6783SRandall Stewart /* Must have a port set */ 6888a99b6783SRandall Stewart return (EINVAL); 6889a99b6783SRandall Stewart } 6890a99b6783SRandall Stewart if (SCTP_BASE_INFO(udp_tun_socket) != NULL) { 6891a99b6783SRandall Stewart /* Already running -- must stop first */ 6892a99b6783SRandall Stewart return (EALREADY); 6893a99b6783SRandall Stewart } 6894a99b6783SRandall Stewart th = curthread; 6895a99b6783SRandall Stewart cred = th->td_ucred; 6896a99b6783SRandall Stewart if ((ret = socreate(PF_INET, &sop, 6897a99b6783SRandall Stewart SOCK_DGRAM, IPPROTO_UDP, cred, th))) { 6898a99b6783SRandall Stewart return (ret); 6899a99b6783SRandall Stewart } 6900a99b6783SRandall Stewart SCTP_BASE_INFO(udp_tun_socket) = sop; 6901a99b6783SRandall Stewart /* call the special UDP hook */ 6902a99b6783SRandall Stewart ret = udp_set_kernel_tunneling(sop, sctp_recv_udp_tunneled_packet); 6903a99b6783SRandall Stewart if (ret) { 6904a99b6783SRandall Stewart goto exit_stage_left; 6905a99b6783SRandall Stewart } 6906a99b6783SRandall Stewart /* Ok we have a socket, bind it to the port */ 6907a99b6783SRandall Stewart memset(&sin, 0, sizeof(sin)); 6908a99b6783SRandall Stewart sin.sin_len = sizeof(sin); 6909a99b6783SRandall Stewart sin.sin_family = AF_INET; 6910a99b6783SRandall Stewart sin.sin_port = htons(port); 6911a99b6783SRandall Stewart ret = sobind(sop, (struct sockaddr *)&sin, th); 6912a99b6783SRandall Stewart if (ret) { 6913a99b6783SRandall Stewart /* Close up we cant get the port */ 6914a99b6783SRandall Stewart exit_stage_left: 6915a99b6783SRandall Stewart sctp_over_udp_stop(); 6916a99b6783SRandall Stewart return (ret); 6917a99b6783SRandall Stewart } 6918a99b6783SRandall Stewart /* 6919a99b6783SRandall Stewart * Ok we should now get UDP packets directly to our input routine 6920a99b6783SRandall Stewart * sctp_recv_upd_tunneled_packet(). 6921a99b6783SRandall Stewart */ 6922a99b6783SRandall Stewart return (0); 6923c54a18d2SRandall Stewart } 6924ea5eba11SMichael Tuexen 6925ea5eba11SMichael Tuexen #endif 6926