1f8829a4aSRandall Stewart /*- 2830d754dSRandall Stewart * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. 35d40cf5dSRandall Stewart * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved. 45d40cf5dSRandall Stewart * Copyright (c) 2008-2011, 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 /* $KAME: sctputil.c,v 1.37 2005/03/07 23:26:09 itojun Exp $ */ 34f8829a4aSRandall Stewart 35f8829a4aSRandall Stewart #include <sys/cdefs.h> 36f8829a4aSRandall Stewart __FBSDID("$FreeBSD$"); 37f8829a4aSRandall Stewart 38f8829a4aSRandall Stewart #include <netinet/sctp_os.h> 39f8829a4aSRandall Stewart #include <netinet/sctp_pcb.h> 40f8829a4aSRandall Stewart #include <netinet/sctputil.h> 41f8829a4aSRandall Stewart #include <netinet/sctp_var.h> 4242551e99SRandall Stewart #include <netinet/sctp_sysctl.h> 43f8829a4aSRandall Stewart #ifdef INET6 44f8829a4aSRandall Stewart #endif 45f8829a4aSRandall Stewart #include <netinet/sctp_header.h> 46f8829a4aSRandall Stewart #include <netinet/sctp_output.h> 47f8829a4aSRandall Stewart #include <netinet/sctp_uio.h> 48f8829a4aSRandall Stewart #include <netinet/sctp_timer.h> 49f8829a4aSRandall Stewart #include <netinet/sctp_indata.h>/* for sctp_deliver_data() */ 50f8829a4aSRandall Stewart #include <netinet/sctp_auth.h> 51f8829a4aSRandall Stewart #include <netinet/sctp_asconf.h> 52f7517433SRandall Stewart #include <netinet/sctp_bsd_addr.h> 53f8829a4aSRandall Stewart 54f8829a4aSRandall Stewart 55b9e7085aSRandall Stewart #ifndef KTR_SCTP 56b9e7085aSRandall Stewart #define KTR_SCTP KTR_SUBSYS 5780fefe0aSRandall Stewart #endif 58f8829a4aSRandall Stewart 590e9a9c10SMichael Tuexen extern struct sctp_cc_functions sctp_cc_functions[]; 60f7a77f6fSMichael Tuexen extern struct sctp_ss_functions sctp_ss_functions[]; 610e9a9c10SMichael Tuexen 62f8829a4aSRandall Stewart void 63f8829a4aSRandall Stewart sctp_sblog(struct sockbuf *sb, 64f8829a4aSRandall Stewart struct sctp_tcb *stcb, int from, int incr) 65f8829a4aSRandall Stewart { 6680fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 67f8829a4aSRandall Stewart 6880fefe0aSRandall Stewart sctp_clog.x.sb.stcb = stcb; 6980fefe0aSRandall Stewart sctp_clog.x.sb.so_sbcc = sb->sb_cc; 70f8829a4aSRandall Stewart if (stcb) 7180fefe0aSRandall Stewart sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc; 72f8829a4aSRandall Stewart else 7380fefe0aSRandall Stewart sctp_clog.x.sb.stcb_sbcc = 0; 7480fefe0aSRandall Stewart sctp_clog.x.sb.incr = incr; 75c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 7680fefe0aSRandall Stewart SCTP_LOG_EVENT_SB, 7780fefe0aSRandall Stewart from, 7880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 7980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 8080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 8180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 82f8829a4aSRandall Stewart } 83f8829a4aSRandall Stewart 84f8829a4aSRandall Stewart void 85f8829a4aSRandall Stewart sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc) 86f8829a4aSRandall Stewart { 8780fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 88f8829a4aSRandall Stewart 8980fefe0aSRandall Stewart sctp_clog.x.close.inp = (void *)inp; 9080fefe0aSRandall Stewart sctp_clog.x.close.sctp_flags = inp->sctp_flags; 91f8829a4aSRandall Stewart if (stcb) { 9280fefe0aSRandall Stewart sctp_clog.x.close.stcb = (void *)stcb; 9380fefe0aSRandall Stewart sctp_clog.x.close.state = (uint16_t) stcb->asoc.state; 94f8829a4aSRandall Stewart } else { 9580fefe0aSRandall Stewart sctp_clog.x.close.stcb = 0; 9680fefe0aSRandall Stewart sctp_clog.x.close.state = 0; 97f8829a4aSRandall Stewart } 9880fefe0aSRandall Stewart sctp_clog.x.close.loc = loc; 99c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 10080fefe0aSRandall Stewart SCTP_LOG_EVENT_CLOSE, 10180fefe0aSRandall Stewart 0, 10280fefe0aSRandall Stewart sctp_clog.x.misc.log1, 10380fefe0aSRandall Stewart sctp_clog.x.misc.log2, 10480fefe0aSRandall Stewart sctp_clog.x.misc.log3, 10580fefe0aSRandall Stewart sctp_clog.x.misc.log4); 106f8829a4aSRandall Stewart } 107f8829a4aSRandall Stewart 108f8829a4aSRandall Stewart 109f8829a4aSRandall Stewart void 110f8829a4aSRandall Stewart rto_logging(struct sctp_nets *net, int from) 111f8829a4aSRandall Stewart { 11280fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 113f8829a4aSRandall Stewart 114bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 11580fefe0aSRandall Stewart sctp_clog.x.rto.net = (void *)net; 116be1d9176SMichael Tuexen sctp_clog.x.rto.rtt = net->rtt / 1000; 117c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 11880fefe0aSRandall Stewart SCTP_LOG_EVENT_RTT, 11980fefe0aSRandall Stewart from, 12080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 12180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 12280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 12380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 124f8829a4aSRandall Stewart } 125f8829a4aSRandall Stewart 126f8829a4aSRandall Stewart void 1276a91f103SRandall Stewart sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from) 128f8829a4aSRandall Stewart { 12980fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 130f8829a4aSRandall Stewart 13180fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = stcb; 13280fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = tsn; 13380fefe0aSRandall Stewart sctp_clog.x.strlog.n_sseq = sseq; 13480fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 13580fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 13680fefe0aSRandall Stewart sctp_clog.x.strlog.strm = stream; 137c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 13880fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 13980fefe0aSRandall Stewart from, 14080fefe0aSRandall Stewart sctp_clog.x.misc.log1, 14180fefe0aSRandall Stewart sctp_clog.x.misc.log2, 14280fefe0aSRandall Stewart sctp_clog.x.misc.log3, 14380fefe0aSRandall Stewart sctp_clog.x.misc.log4); 144f8829a4aSRandall Stewart } 145f8829a4aSRandall Stewart 146f8829a4aSRandall Stewart void 147f8829a4aSRandall Stewart sctp_log_nagle_event(struct sctp_tcb *stcb, int action) 148f8829a4aSRandall Stewart { 14980fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 150f8829a4aSRandall Stewart 15180fefe0aSRandall Stewart sctp_clog.x.nagle.stcb = (void *)stcb; 15280fefe0aSRandall Stewart sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight; 15380fefe0aSRandall Stewart sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size; 15480fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue; 15580fefe0aSRandall Stewart sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count; 156c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 15780fefe0aSRandall Stewart SCTP_LOG_EVENT_NAGLE, 15880fefe0aSRandall Stewart action, 15980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 16080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 16180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 16280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 163f8829a4aSRandall Stewart } 164f8829a4aSRandall Stewart 165f8829a4aSRandall Stewart 166f8829a4aSRandall Stewart void 167f8829a4aSRandall Stewart sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from) 168f8829a4aSRandall Stewart { 16980fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 170f8829a4aSRandall Stewart 17180fefe0aSRandall Stewart sctp_clog.x.sack.cumack = cumack; 17280fefe0aSRandall Stewart sctp_clog.x.sack.oldcumack = old_cumack; 17380fefe0aSRandall Stewart sctp_clog.x.sack.tsn = tsn; 17480fefe0aSRandall Stewart sctp_clog.x.sack.numGaps = gaps; 17580fefe0aSRandall Stewart sctp_clog.x.sack.numDups = dups; 176c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 17780fefe0aSRandall Stewart SCTP_LOG_EVENT_SACK, 17880fefe0aSRandall Stewart from, 17980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 18080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 18180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 18280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 183f8829a4aSRandall Stewart } 184f8829a4aSRandall Stewart 185f8829a4aSRandall Stewart void 186f8829a4aSRandall Stewart sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from) 187f8829a4aSRandall Stewart { 18880fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 189f8829a4aSRandall Stewart 190bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 19180fefe0aSRandall Stewart sctp_clog.x.map.base = map; 19280fefe0aSRandall Stewart sctp_clog.x.map.cum = cum; 19380fefe0aSRandall Stewart sctp_clog.x.map.high = high; 194c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 19580fefe0aSRandall Stewart SCTP_LOG_EVENT_MAP, 19680fefe0aSRandall Stewart from, 19780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 19880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 19980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 20080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 201f8829a4aSRandall Stewart } 202f8829a4aSRandall Stewart 203f8829a4aSRandall Stewart void 204f8829a4aSRandall Stewart sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, 205f8829a4aSRandall Stewart int from) 206f8829a4aSRandall Stewart { 20780fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 208f8829a4aSRandall Stewart 209bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 21080fefe0aSRandall Stewart sctp_clog.x.fr.largest_tsn = biggest_tsn; 21180fefe0aSRandall Stewart sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn; 21280fefe0aSRandall Stewart sctp_clog.x.fr.tsn = tsn; 213c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 21480fefe0aSRandall Stewart SCTP_LOG_EVENT_FR, 21580fefe0aSRandall Stewart from, 21680fefe0aSRandall Stewart sctp_clog.x.misc.log1, 21780fefe0aSRandall Stewart sctp_clog.x.misc.log2, 21880fefe0aSRandall Stewart sctp_clog.x.misc.log3, 21980fefe0aSRandall Stewart sctp_clog.x.misc.log4); 220f8829a4aSRandall Stewart } 221f8829a4aSRandall Stewart 222f8829a4aSRandall Stewart 223f8829a4aSRandall Stewart void 224f8829a4aSRandall Stewart sctp_log_mb(struct mbuf *m, int from) 225f8829a4aSRandall Stewart { 22680fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 227f8829a4aSRandall Stewart 22880fefe0aSRandall Stewart sctp_clog.x.mb.mp = m; 22980fefe0aSRandall Stewart sctp_clog.x.mb.mbuf_flags = (uint8_t) (SCTP_BUF_GET_FLAGS(m)); 23080fefe0aSRandall Stewart sctp_clog.x.mb.size = (uint16_t) (SCTP_BUF_LEN(m)); 23180fefe0aSRandall Stewart sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0); 232139bc87fSRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 23380fefe0aSRandall Stewart sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m); 23480fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = (uint8_t) (SCTP_BUF_EXTEND_REFCNT(m)); 235f8829a4aSRandall Stewart } else { 23680fefe0aSRandall Stewart sctp_clog.x.mb.ext = 0; 23780fefe0aSRandall Stewart sctp_clog.x.mb.refcnt = 0; 238f8829a4aSRandall Stewart } 239c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 24080fefe0aSRandall Stewart SCTP_LOG_EVENT_MBUF, 24180fefe0aSRandall Stewart from, 24280fefe0aSRandall Stewart sctp_clog.x.misc.log1, 24380fefe0aSRandall Stewart sctp_clog.x.misc.log2, 24480fefe0aSRandall Stewart sctp_clog.x.misc.log3, 24580fefe0aSRandall Stewart sctp_clog.x.misc.log4); 246f8829a4aSRandall Stewart } 247f8829a4aSRandall Stewart 248f8829a4aSRandall Stewart 249f8829a4aSRandall Stewart void 250f8829a4aSRandall Stewart sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, 251f8829a4aSRandall Stewart int from) 252f8829a4aSRandall Stewart { 25380fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 254f8829a4aSRandall Stewart 255f8829a4aSRandall Stewart if (control == NULL) { 256ad81507eSRandall Stewart SCTP_PRINTF("Gak log of NULL?\n"); 257f8829a4aSRandall Stewart return; 258f8829a4aSRandall Stewart } 25980fefe0aSRandall Stewart sctp_clog.x.strlog.stcb = control->stcb; 26080fefe0aSRandall Stewart sctp_clog.x.strlog.n_tsn = control->sinfo_tsn; 26180fefe0aSRandall Stewart sctp_clog.x.strlog.n_sseq = control->sinfo_ssn; 26280fefe0aSRandall Stewart sctp_clog.x.strlog.strm = control->sinfo_stream; 263f8829a4aSRandall Stewart if (poschk != NULL) { 26480fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn; 26580fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = poschk->sinfo_ssn; 266f8829a4aSRandall Stewart } else { 26780fefe0aSRandall Stewart sctp_clog.x.strlog.e_tsn = 0; 26880fefe0aSRandall Stewart sctp_clog.x.strlog.e_sseq = 0; 269f8829a4aSRandall Stewart } 270c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 27180fefe0aSRandall Stewart SCTP_LOG_EVENT_STRM, 27280fefe0aSRandall Stewart from, 27380fefe0aSRandall Stewart sctp_clog.x.misc.log1, 27480fefe0aSRandall Stewart sctp_clog.x.misc.log2, 27580fefe0aSRandall Stewart sctp_clog.x.misc.log3, 27680fefe0aSRandall Stewart sctp_clog.x.misc.log4); 277f8829a4aSRandall Stewart } 278f8829a4aSRandall Stewart 279f8829a4aSRandall Stewart void 280f8829a4aSRandall Stewart sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from) 281f8829a4aSRandall Stewart { 28280fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 283f8829a4aSRandall Stewart 28480fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 285f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 28680fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 287f8829a4aSRandall Stewart else 28880fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 289f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 29080fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 291f8829a4aSRandall Stewart else 29280fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 293f8829a4aSRandall Stewart 294f8829a4aSRandall Stewart if (net) { 29580fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = net->cwnd; 29680fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 29780fefe0aSRandall Stewart sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack; 29880fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack; 29980fefe0aSRandall Stewart sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack; 300f8829a4aSRandall Stewart } 301f8829a4aSRandall Stewart if (SCTP_CWNDLOG_PRESEND == from) { 30280fefe0aSRandall Stewart sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd; 303f8829a4aSRandall Stewart } 30480fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = augment; 305c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 30680fefe0aSRandall Stewart SCTP_LOG_EVENT_CWND, 30780fefe0aSRandall Stewart from, 30880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 30980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 31080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 31180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 312f8829a4aSRandall Stewart } 313f8829a4aSRandall Stewart 314f8829a4aSRandall Stewart void 315f8829a4aSRandall Stewart sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from) 316f8829a4aSRandall Stewart { 31780fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 318f8829a4aSRandall Stewart 319bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 32003b0b021SRandall Stewart if (inp) { 32180fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)inp->sctp_socket; 32203b0b021SRandall Stewart 32303b0b021SRandall Stewart } else { 32480fefe0aSRandall Stewart sctp_clog.x.lock.sock = (void *)NULL; 32503b0b021SRandall Stewart } 32680fefe0aSRandall Stewart sctp_clog.x.lock.inp = (void *)inp; 327f8829a4aSRandall Stewart if (stcb) { 32880fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx); 329f8829a4aSRandall Stewart } else { 33080fefe0aSRandall Stewart sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN; 331f8829a4aSRandall Stewart } 332f8829a4aSRandall Stewart if (inp) { 33380fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx); 33480fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx); 335f8829a4aSRandall Stewart } else { 33680fefe0aSRandall Stewart sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN; 33780fefe0aSRandall Stewart sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN; 338f8829a4aSRandall Stewart } 339b3f1ea41SRandall Stewart sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx)); 34052129fcdSRandall Stewart if (inp && (inp->sctp_socket)) { 34180fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 34280fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(&(inp->sctp_socket->so_rcv.sb_mtx)); 34380fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = mtx_owned(&(inp->sctp_socket->so_snd.sb_mtx)); 344f8829a4aSRandall Stewart } else { 34580fefe0aSRandall Stewart sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN; 34680fefe0aSRandall Stewart sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN; 34780fefe0aSRandall Stewart sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN; 348f8829a4aSRandall Stewart } 349c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 35080fefe0aSRandall Stewart SCTP_LOG_LOCK_EVENT, 35180fefe0aSRandall Stewart from, 35280fefe0aSRandall Stewart sctp_clog.x.misc.log1, 35380fefe0aSRandall Stewart sctp_clog.x.misc.log2, 35480fefe0aSRandall Stewart sctp_clog.x.misc.log3, 35580fefe0aSRandall Stewart sctp_clog.x.misc.log4); 356f8829a4aSRandall Stewart } 357f8829a4aSRandall Stewart 358f8829a4aSRandall Stewart void 359f8829a4aSRandall Stewart sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from) 360f8829a4aSRandall Stewart { 36180fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 362f8829a4aSRandall Stewart 363bfefd190SRandall Stewart memset(&sctp_clog, 0, sizeof(sctp_clog)); 36480fefe0aSRandall Stewart sctp_clog.x.cwnd.net = net; 36580fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_new_value = error; 36680fefe0aSRandall Stewart sctp_clog.x.cwnd.inflight = net->flight_size; 36780fefe0aSRandall Stewart sctp_clog.x.cwnd.cwnd_augment = burst; 368f8829a4aSRandall Stewart if (stcb->asoc.send_queue_cnt > 255) 36980fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = 255; 370f8829a4aSRandall Stewart else 37180fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt; 372f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt > 255) 37380fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = 255; 374f8829a4aSRandall Stewart else 37580fefe0aSRandall Stewart sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt; 376c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 37780fefe0aSRandall Stewart SCTP_LOG_EVENT_MAXBURST, 37880fefe0aSRandall Stewart from, 37980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 38080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 38180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 38280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 383f8829a4aSRandall Stewart } 384f8829a4aSRandall Stewart 385f8829a4aSRandall Stewart void 386f8829a4aSRandall Stewart sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead) 387f8829a4aSRandall Stewart { 38880fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 389f8829a4aSRandall Stewart 39080fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 39180fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = snd_size; 39280fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 39380fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = 0; 394c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 39580fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 39680fefe0aSRandall Stewart from, 39780fefe0aSRandall Stewart sctp_clog.x.misc.log1, 39880fefe0aSRandall Stewart sctp_clog.x.misc.log2, 39980fefe0aSRandall Stewart sctp_clog.x.misc.log3, 40080fefe0aSRandall Stewart sctp_clog.x.misc.log4); 401f8829a4aSRandall Stewart } 402f8829a4aSRandall Stewart 403f8829a4aSRandall Stewart void 404f8829a4aSRandall Stewart sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval) 405f8829a4aSRandall Stewart { 40680fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 407f8829a4aSRandall Stewart 40880fefe0aSRandall Stewart sctp_clog.x.rwnd.rwnd = peers_rwnd; 40980fefe0aSRandall Stewart sctp_clog.x.rwnd.send_size = flight_size; 41080fefe0aSRandall Stewart sctp_clog.x.rwnd.overhead = overhead; 41180fefe0aSRandall Stewart sctp_clog.x.rwnd.new_rwnd = a_rwndval; 412c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 41380fefe0aSRandall Stewart SCTP_LOG_EVENT_RWND, 41480fefe0aSRandall Stewart from, 41580fefe0aSRandall Stewart sctp_clog.x.misc.log1, 41680fefe0aSRandall Stewart sctp_clog.x.misc.log2, 41780fefe0aSRandall Stewart sctp_clog.x.misc.log3, 41880fefe0aSRandall Stewart sctp_clog.x.misc.log4); 419f8829a4aSRandall Stewart } 420f8829a4aSRandall Stewart 421f8829a4aSRandall Stewart void 422f8829a4aSRandall Stewart sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt) 423f8829a4aSRandall Stewart { 42480fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 425f8829a4aSRandall Stewart 42680fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_size = total_oq; 42780fefe0aSRandall Stewart sctp_clog.x.mbcnt.size_change = book; 42880fefe0aSRandall Stewart sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q; 42980fefe0aSRandall Stewart sctp_clog.x.mbcnt.mbcnt_change = mbcnt; 430c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 43180fefe0aSRandall Stewart SCTP_LOG_EVENT_MBCNT, 43280fefe0aSRandall Stewart from, 43380fefe0aSRandall Stewart sctp_clog.x.misc.log1, 43480fefe0aSRandall Stewart sctp_clog.x.misc.log2, 43580fefe0aSRandall Stewart sctp_clog.x.misc.log3, 43680fefe0aSRandall Stewart sctp_clog.x.misc.log4); 437f8829a4aSRandall Stewart } 438f8829a4aSRandall Stewart 439f8829a4aSRandall Stewart void 440f8829a4aSRandall Stewart sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d) 441f8829a4aSRandall Stewart { 442c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 44380fefe0aSRandall Stewart SCTP_LOG_MISC_EVENT, 44480fefe0aSRandall Stewart from, 44580fefe0aSRandall Stewart a, b, c, d); 446f8829a4aSRandall Stewart } 447f8829a4aSRandall Stewart 448f8829a4aSRandall Stewart void 449*7215cc1bSMichael Tuexen sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from) 450f8829a4aSRandall Stewart { 45180fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 452f8829a4aSRandall Stewart 45380fefe0aSRandall Stewart sctp_clog.x.wake.stcb = (void *)stcb; 45480fefe0aSRandall Stewart sctp_clog.x.wake.wake_cnt = wake_cnt; 45580fefe0aSRandall Stewart sctp_clog.x.wake.flight = stcb->asoc.total_flight_count; 45680fefe0aSRandall Stewart sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt; 45780fefe0aSRandall Stewart sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt; 458f8829a4aSRandall Stewart 459f8829a4aSRandall Stewart if (stcb->asoc.stream_queue_cnt < 0xff) 46080fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = (uint8_t) stcb->asoc.stream_queue_cnt; 461f8829a4aSRandall Stewart else 46280fefe0aSRandall Stewart sctp_clog.x.wake.stream_qcnt = 0xff; 463f8829a4aSRandall Stewart 464f8829a4aSRandall Stewart if (stcb->asoc.chunks_on_out_queue < 0xff) 46580fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = (uint8_t) stcb->asoc.chunks_on_out_queue; 466f8829a4aSRandall Stewart else 46780fefe0aSRandall Stewart sctp_clog.x.wake.chunks_on_oque = 0xff; 468f8829a4aSRandall Stewart 46980fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags = 0; 470f8829a4aSRandall Stewart /* set in the defered mode stuff */ 471f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) 47280fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 1; 473f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) 47480fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 2; 475f8829a4aSRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) 47680fefe0aSRandall Stewart sctp_clog.x.wake.sctpflags |= 4; 477f8829a4aSRandall Stewart /* what about the sb */ 478f8829a4aSRandall Stewart if (stcb->sctp_socket) { 479f8829a4aSRandall Stewart struct socket *so = stcb->sctp_socket; 480f8829a4aSRandall Stewart 48180fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = (uint8_t) ((so->so_snd.sb_flags & 0x00ff)); 482f8829a4aSRandall Stewart } else { 48380fefe0aSRandall Stewart sctp_clog.x.wake.sbflags = 0xff; 484f8829a4aSRandall Stewart } 485c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 48680fefe0aSRandall Stewart SCTP_LOG_EVENT_WAKE, 48780fefe0aSRandall Stewart from, 48880fefe0aSRandall Stewart sctp_clog.x.misc.log1, 48980fefe0aSRandall Stewart sctp_clog.x.misc.log2, 49080fefe0aSRandall Stewart sctp_clog.x.misc.log3, 49180fefe0aSRandall Stewart sctp_clog.x.misc.log4); 492f8829a4aSRandall Stewart } 493f8829a4aSRandall Stewart 494f8829a4aSRandall Stewart void 495*7215cc1bSMichael Tuexen sctp_log_block(uint8_t from, struct sctp_association *asoc, int sendlen) 496f8829a4aSRandall Stewart { 49780fefe0aSRandall Stewart struct sctp_cwnd_log sctp_clog; 498f8829a4aSRandall Stewart 49980fefe0aSRandall Stewart sctp_clog.x.blk.onsb = asoc->total_output_queue_size; 50080fefe0aSRandall Stewart sctp_clog.x.blk.send_sent_qcnt = (uint16_t) (asoc->send_queue_cnt + asoc->sent_queue_cnt); 50180fefe0aSRandall Stewart sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd; 50280fefe0aSRandall Stewart sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt; 50380fefe0aSRandall Stewart sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue; 50480fefe0aSRandall Stewart sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight / 1024); 50580fefe0aSRandall Stewart sctp_clog.x.blk.sndlen = sendlen; 506c4739e2fSRandall Stewart SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x", 50780fefe0aSRandall Stewart SCTP_LOG_EVENT_BLOCK, 50880fefe0aSRandall Stewart from, 50980fefe0aSRandall Stewart sctp_clog.x.misc.log1, 51080fefe0aSRandall Stewart sctp_clog.x.misc.log2, 51180fefe0aSRandall Stewart sctp_clog.x.misc.log3, 51280fefe0aSRandall Stewart sctp_clog.x.misc.log4); 513f8829a4aSRandall Stewart } 514f8829a4aSRandall Stewart 515f8829a4aSRandall Stewart int 516*7215cc1bSMichael Tuexen sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED) 517f8829a4aSRandall Stewart { 51880fefe0aSRandall Stewart /* May need to fix this if ktrdump does not work */ 519f8829a4aSRandall Stewart return (0); 520f8829a4aSRandall Stewart } 521f8829a4aSRandall Stewart 522f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 523f8829a4aSRandall Stewart uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2]; 524f8829a4aSRandall Stewart static int sctp_audit_indx = 0; 525f8829a4aSRandall Stewart 526f8829a4aSRandall Stewart static 527f8829a4aSRandall Stewart void 528f8829a4aSRandall Stewart sctp_print_audit_report(void) 529f8829a4aSRandall Stewart { 530f8829a4aSRandall Stewart int i; 531f8829a4aSRandall Stewart int cnt; 532f8829a4aSRandall Stewart 533f8829a4aSRandall Stewart cnt = 0; 534f8829a4aSRandall Stewart for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) { 535f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 536f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 537f8829a4aSRandall Stewart cnt = 0; 538ad81507eSRandall Stewart SCTP_PRINTF("\n"); 539f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 540f8829a4aSRandall Stewart cnt = 0; 541ad81507eSRandall Stewart SCTP_PRINTF("\n"); 542f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 543f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 544ad81507eSRandall Stewart SCTP_PRINTF("\n"); 545f8829a4aSRandall Stewart cnt = 0; 546f8829a4aSRandall Stewart } 547ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0], 548f8829a4aSRandall Stewart (uint32_t) sctp_audit_data[i][1]); 549f8829a4aSRandall Stewart cnt++; 550f8829a4aSRandall Stewart if ((cnt % 14) == 0) 551ad81507eSRandall Stewart SCTP_PRINTF("\n"); 552f8829a4aSRandall Stewart } 553f8829a4aSRandall Stewart for (i = 0; i < sctp_audit_indx; i++) { 554f8829a4aSRandall Stewart if ((sctp_audit_data[i][0] == 0xe0) && 555f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 556f8829a4aSRandall Stewart cnt = 0; 557ad81507eSRandall Stewart SCTP_PRINTF("\n"); 558f8829a4aSRandall Stewart } else if (sctp_audit_data[i][0] == 0xf0) { 559f8829a4aSRandall Stewart cnt = 0; 560ad81507eSRandall Stewart SCTP_PRINTF("\n"); 561f8829a4aSRandall Stewart } else if ((sctp_audit_data[i][0] == 0xc0) && 562f8829a4aSRandall Stewart (sctp_audit_data[i][1] == 0x01)) { 563ad81507eSRandall Stewart SCTP_PRINTF("\n"); 564f8829a4aSRandall Stewart cnt = 0; 565f8829a4aSRandall Stewart } 566ad81507eSRandall Stewart SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0], 567f8829a4aSRandall Stewart (uint32_t) sctp_audit_data[i][1]); 568f8829a4aSRandall Stewart cnt++; 569f8829a4aSRandall Stewart if ((cnt % 14) == 0) 570ad81507eSRandall Stewart SCTP_PRINTF("\n"); 571f8829a4aSRandall Stewart } 572ad81507eSRandall Stewart SCTP_PRINTF("\n"); 573f8829a4aSRandall Stewart } 574f8829a4aSRandall Stewart 575f8829a4aSRandall Stewart void 576f8829a4aSRandall Stewart sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 577f8829a4aSRandall Stewart struct sctp_nets *net) 578f8829a4aSRandall Stewart { 579f8829a4aSRandall Stewart int resend_cnt, tot_out, rep, tot_book_cnt; 580f8829a4aSRandall Stewart struct sctp_nets *lnet; 581f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 582f8829a4aSRandall Stewart 583f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAA; 584f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from; 585f8829a4aSRandall Stewart sctp_audit_indx++; 586f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 587f8829a4aSRandall Stewart sctp_audit_indx = 0; 588f8829a4aSRandall Stewart } 589f8829a4aSRandall Stewart if (inp == NULL) { 590f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 591f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x01; 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 if (stcb == NULL) { 599f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 600f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0x02; 601f8829a4aSRandall Stewart sctp_audit_indx++; 602f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 603f8829a4aSRandall Stewart sctp_audit_indx = 0; 604f8829a4aSRandall Stewart } 605f8829a4aSRandall Stewart return; 606f8829a4aSRandall Stewart } 607f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA1; 608f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 609f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 610f8829a4aSRandall Stewart sctp_audit_indx++; 611f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 612f8829a4aSRandall Stewart sctp_audit_indx = 0; 613f8829a4aSRandall Stewart } 614f8829a4aSRandall Stewart rep = 0; 615f8829a4aSRandall Stewart tot_book_cnt = 0; 616f8829a4aSRandall Stewart resend_cnt = tot_out = 0; 617f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 618f8829a4aSRandall Stewart if (chk->sent == SCTP_DATAGRAM_RESEND) { 619f8829a4aSRandall Stewart resend_cnt++; 620f8829a4aSRandall Stewart } else if (chk->sent < SCTP_DATAGRAM_RESEND) { 621f8829a4aSRandall Stewart tot_out += chk->book_size; 622f8829a4aSRandall Stewart tot_book_cnt++; 623f8829a4aSRandall Stewart } 624f8829a4aSRandall Stewart } 625f8829a4aSRandall Stewart if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) { 626f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 627f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA1; 628f8829a4aSRandall Stewart sctp_audit_indx++; 629f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 630f8829a4aSRandall Stewart sctp_audit_indx = 0; 631f8829a4aSRandall Stewart } 632ad81507eSRandall Stewart SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n", 633f8829a4aSRandall Stewart resend_cnt, stcb->asoc.sent_queue_retran_cnt); 634f8829a4aSRandall Stewart rep = 1; 635f8829a4aSRandall Stewart stcb->asoc.sent_queue_retran_cnt = resend_cnt; 636f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xA2; 637f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 638f8829a4aSRandall Stewart (0x000000ff & stcb->asoc.sent_queue_retran_cnt); 639f8829a4aSRandall Stewart sctp_audit_indx++; 640f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 641f8829a4aSRandall Stewart sctp_audit_indx = 0; 642f8829a4aSRandall Stewart } 643f8829a4aSRandall Stewart } 644f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 645f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 646f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA2; 647f8829a4aSRandall Stewart sctp_audit_indx++; 648f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 649f8829a4aSRandall Stewart sctp_audit_indx = 0; 650f8829a4aSRandall Stewart } 651f8829a4aSRandall Stewart rep = 1; 652ad81507eSRandall Stewart SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out, 653f8829a4aSRandall Stewart (int)stcb->asoc.total_flight); 654f8829a4aSRandall Stewart stcb->asoc.total_flight = tot_out; 655f8829a4aSRandall Stewart } 656f8829a4aSRandall Stewart if (tot_book_cnt != stcb->asoc.total_flight_count) { 657f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 658f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA5; 659f8829a4aSRandall Stewart sctp_audit_indx++; 660f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 661f8829a4aSRandall Stewart sctp_audit_indx = 0; 662f8829a4aSRandall Stewart } 663f8829a4aSRandall Stewart rep = 1; 664f31e6c7fSMichael Tuexen SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt); 665f8829a4aSRandall Stewart 666f8829a4aSRandall Stewart stcb->asoc.total_flight_count = tot_book_cnt; 667f8829a4aSRandall Stewart } 668f8829a4aSRandall Stewart tot_out = 0; 669f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 670f8829a4aSRandall Stewart tot_out += lnet->flight_size; 671f8829a4aSRandall Stewart } 672f8829a4aSRandall Stewart if (tot_out != stcb->asoc.total_flight) { 673f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = 0xAF; 674f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = 0xA3; 675f8829a4aSRandall Stewart sctp_audit_indx++; 676f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 677f8829a4aSRandall Stewart sctp_audit_indx = 0; 678f8829a4aSRandall Stewart } 679f8829a4aSRandall Stewart rep = 1; 680ad81507eSRandall Stewart SCTP_PRINTF("real flight:%d net total was %d\n", 681f8829a4aSRandall Stewart stcb->asoc.total_flight, tot_out); 682f8829a4aSRandall Stewart /* now corrective action */ 683f8829a4aSRandall Stewart TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { 684f8829a4aSRandall Stewart 685f8829a4aSRandall Stewart tot_out = 0; 686f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { 687f8829a4aSRandall Stewart if ((chk->whoTo == lnet) && 688f8829a4aSRandall Stewart (chk->sent < SCTP_DATAGRAM_RESEND)) { 689f8829a4aSRandall Stewart tot_out += chk->book_size; 690f8829a4aSRandall Stewart } 691f8829a4aSRandall Stewart } 692f8829a4aSRandall Stewart if (lnet->flight_size != tot_out) { 693f31e6c7fSMichael Tuexen SCTP_PRINTF("net:%p flight was %d corrected to %d\n", 694f31e6c7fSMichael Tuexen lnet, lnet->flight_size, 695ad81507eSRandall Stewart tot_out); 696f8829a4aSRandall Stewart lnet->flight_size = tot_out; 697f8829a4aSRandall Stewart } 698f8829a4aSRandall Stewart } 699f8829a4aSRandall Stewart } 700f8829a4aSRandall Stewart if (rep) { 701f8829a4aSRandall Stewart sctp_print_audit_report(); 702f8829a4aSRandall Stewart } 703f8829a4aSRandall Stewart } 704f8829a4aSRandall Stewart 705f8829a4aSRandall Stewart void 706f8829a4aSRandall Stewart sctp_audit_log(uint8_t ev, uint8_t fd) 707f8829a4aSRandall Stewart { 708f8829a4aSRandall Stewart 709f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][0] = ev; 710f8829a4aSRandall Stewart sctp_audit_data[sctp_audit_indx][1] = fd; 711f8829a4aSRandall Stewart sctp_audit_indx++; 712f8829a4aSRandall Stewart if (sctp_audit_indx >= SCTP_AUDIT_SIZE) { 713f8829a4aSRandall Stewart sctp_audit_indx = 0; 714f8829a4aSRandall Stewart } 715f8829a4aSRandall Stewart } 716f8829a4aSRandall Stewart 717f8829a4aSRandall Stewart #endif 718f8829a4aSRandall Stewart 719f8829a4aSRandall Stewart /* 72012af6654SMichael Tuexen * sctp_stop_timers_for_shutdown() should be called 72112af6654SMichael Tuexen * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT 72212af6654SMichael Tuexen * state to make sure that all timers are stopped. 72312af6654SMichael Tuexen */ 72412af6654SMichael Tuexen void 72512af6654SMichael Tuexen sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb) 72612af6654SMichael Tuexen { 72712af6654SMichael Tuexen struct sctp_association *asoc; 72812af6654SMichael Tuexen struct sctp_nets *net; 72912af6654SMichael Tuexen 73012af6654SMichael Tuexen asoc = &stcb->asoc; 73112af6654SMichael Tuexen 73212af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->dack_timer.timer); 73312af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->strreset_timer.timer); 73412af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->asconf_timer.timer); 73512af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->autoclose_timer.timer); 73612af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer); 73712af6654SMichael Tuexen TAILQ_FOREACH(net, &asoc->nets, sctp_next) { 73812af6654SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&net->pmtu_timer.timer); 739ca85e948SMichael Tuexen (void)SCTP_OS_TIMER_STOP(&net->hb_timer.timer); 74012af6654SMichael Tuexen } 74112af6654SMichael Tuexen } 74212af6654SMichael Tuexen 74312af6654SMichael Tuexen /* 744f8829a4aSRandall Stewart * a list of sizes based on typical mtu's, used only if next hop size not 745f8829a4aSRandall Stewart * returned. 746f8829a4aSRandall Stewart */ 747437fc91aSMichael Tuexen static uint32_t sctp_mtu_sizes[] = { 748f8829a4aSRandall Stewart 68, 749f8829a4aSRandall Stewart 296, 750f8829a4aSRandall Stewart 508, 751f8829a4aSRandall Stewart 512, 752f8829a4aSRandall Stewart 544, 753f8829a4aSRandall Stewart 576, 754f8829a4aSRandall Stewart 1006, 755f8829a4aSRandall Stewart 1492, 756f8829a4aSRandall Stewart 1500, 757f8829a4aSRandall Stewart 1536, 758f8829a4aSRandall Stewart 2002, 759f8829a4aSRandall Stewart 2048, 760f8829a4aSRandall Stewart 4352, 761f8829a4aSRandall Stewart 4464, 762f8829a4aSRandall Stewart 8166, 763f8829a4aSRandall Stewart 17914, 764f8829a4aSRandall Stewart 32000, 765f8829a4aSRandall Stewart 65535 766f8829a4aSRandall Stewart }; 767f8829a4aSRandall Stewart 768f8829a4aSRandall Stewart /* 769437fc91aSMichael Tuexen * Return the largest MTU smaller than val. If there is no 770437fc91aSMichael Tuexen * entry, just return val. 771f8829a4aSRandall Stewart */ 772437fc91aSMichael Tuexen uint32_t 773437fc91aSMichael Tuexen sctp_get_prev_mtu(uint32_t val) 774437fc91aSMichael Tuexen { 775437fc91aSMichael Tuexen uint32_t i; 776437fc91aSMichael Tuexen 777437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[0]) { 778437fc91aSMichael Tuexen return (val); 779437fc91aSMichael Tuexen } 780437fc91aSMichael Tuexen for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 781437fc91aSMichael Tuexen if (val <= sctp_mtu_sizes[i]) { 782f8829a4aSRandall Stewart break; 783f8829a4aSRandall Stewart } 784f8829a4aSRandall Stewart } 785437fc91aSMichael Tuexen return (sctp_mtu_sizes[i - 1]); 786437fc91aSMichael Tuexen } 787437fc91aSMichael Tuexen 788437fc91aSMichael Tuexen /* 789437fc91aSMichael Tuexen * Return the smallest MTU larger than val. If there is no 790437fc91aSMichael Tuexen * entry, just return val. 791437fc91aSMichael Tuexen */ 792437fc91aSMichael Tuexen uint32_t 793*7215cc1bSMichael Tuexen sctp_get_next_mtu(uint32_t val) 794437fc91aSMichael Tuexen { 795437fc91aSMichael Tuexen /* select another MTU that is just bigger than this one */ 796437fc91aSMichael Tuexen uint32_t i; 797437fc91aSMichael Tuexen 798437fc91aSMichael Tuexen for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) { 799437fc91aSMichael Tuexen if (val < sctp_mtu_sizes[i]) { 800437fc91aSMichael Tuexen return (sctp_mtu_sizes[i]); 801437fc91aSMichael Tuexen } 802437fc91aSMichael Tuexen } 803437fc91aSMichael Tuexen return (val); 804f8829a4aSRandall Stewart } 805f8829a4aSRandall Stewart 806f8829a4aSRandall Stewart void 807f8829a4aSRandall Stewart sctp_fill_random_store(struct sctp_pcb *m) 808f8829a4aSRandall Stewart { 809f8829a4aSRandall Stewart /* 810f8829a4aSRandall Stewart * Here we use the MD5/SHA-1 to hash with our good randomNumbers and 811f8829a4aSRandall Stewart * our counter. The result becomes our good random numbers and we 812f8829a4aSRandall Stewart * then setup to give these out. Note that we do no locking to 813f8829a4aSRandall Stewart * protect this. This is ok, since if competing folks call this we 81417205eccSRandall Stewart * will get more gobbled gook in the random store which is what we 815f8829a4aSRandall Stewart * want. There is a danger that two guys will use the same random 816f8829a4aSRandall Stewart * numbers, but thats ok too since that is random as well :-> 817f8829a4aSRandall Stewart */ 818f8829a4aSRandall Stewart m->store_at = 0; 819ad81507eSRandall Stewart (void)sctp_hmac(SCTP_HMAC, (uint8_t *) m->random_numbers, 820f8829a4aSRandall Stewart sizeof(m->random_numbers), (uint8_t *) & m->random_counter, 821f8829a4aSRandall Stewart sizeof(m->random_counter), (uint8_t *) m->random_store); 822f8829a4aSRandall Stewart m->random_counter++; 823f8829a4aSRandall Stewart } 824f8829a4aSRandall Stewart 825f8829a4aSRandall Stewart uint32_t 826851b7298SRandall Stewart sctp_select_initial_TSN(struct sctp_pcb *inp) 827f8829a4aSRandall Stewart { 828f8829a4aSRandall Stewart /* 829f8829a4aSRandall Stewart * A true implementation should use random selection process to get 830f8829a4aSRandall Stewart * the initial stream sequence number, using RFC1750 as a good 831f8829a4aSRandall Stewart * guideline 832f8829a4aSRandall Stewart */ 833139bc87fSRandall Stewart uint32_t x, *xp; 834f8829a4aSRandall Stewart uint8_t *p; 835851b7298SRandall Stewart int store_at, new_store; 836f8829a4aSRandall Stewart 837851b7298SRandall Stewart if (inp->initial_sequence_debug != 0) { 838f8829a4aSRandall Stewart uint32_t ret; 839f8829a4aSRandall Stewart 840851b7298SRandall Stewart ret = inp->initial_sequence_debug; 841851b7298SRandall Stewart inp->initial_sequence_debug++; 842f8829a4aSRandall Stewart return (ret); 843f8829a4aSRandall Stewart } 844851b7298SRandall Stewart retry: 845851b7298SRandall Stewart store_at = inp->store_at; 846851b7298SRandall Stewart new_store = store_at + sizeof(uint32_t); 847851b7298SRandall Stewart if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) { 848851b7298SRandall Stewart new_store = 0; 849f8829a4aSRandall Stewart } 850851b7298SRandall Stewart if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) { 851851b7298SRandall Stewart goto retry; 852851b7298SRandall Stewart } 853851b7298SRandall Stewart if (new_store == 0) { 854851b7298SRandall Stewart /* Refill the random store */ 855851b7298SRandall Stewart sctp_fill_random_store(inp); 856851b7298SRandall Stewart } 857851b7298SRandall Stewart p = &inp->random_store[store_at]; 858139bc87fSRandall Stewart xp = (uint32_t *) p; 859f8829a4aSRandall Stewart x = *xp; 860f8829a4aSRandall Stewart return (x); 861f8829a4aSRandall Stewart } 862f8829a4aSRandall Stewart 863f8829a4aSRandall Stewart uint32_t 864*7215cc1bSMichael Tuexen sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check) 865f8829a4aSRandall Stewart { 866*7215cc1bSMichael Tuexen uint32_t x; 867f8829a4aSRandall Stewart struct timeval now; 868f8829a4aSRandall Stewart 869*7215cc1bSMichael Tuexen if (check) { 8706e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 871*7215cc1bSMichael Tuexen } 872*7215cc1bSMichael Tuexen for (;;) { 873851b7298SRandall Stewart x = sctp_select_initial_TSN(&inp->sctp_ep); 874f8829a4aSRandall Stewart if (x == 0) { 875f8829a4aSRandall Stewart /* we never use 0 */ 876f8829a4aSRandall Stewart continue; 877f8829a4aSRandall Stewart } 878*7215cc1bSMichael Tuexen if (!check || sctp_is_vtag_good(x, lport, rport, &now)) { 879*7215cc1bSMichael Tuexen break; 880f8829a4aSRandall Stewart } 881f8829a4aSRandall Stewart } 882f8829a4aSRandall Stewart return (x); 883f8829a4aSRandall Stewart } 884f8829a4aSRandall Stewart 885f8829a4aSRandall Stewart int 8860696e120SRandall Stewart sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb, 887b5c16493SMichael Tuexen uint32_t override_tag, uint32_t vrf_id) 888f8829a4aSRandall Stewart { 8890696e120SRandall Stewart struct sctp_association *asoc; 8900696e120SRandall Stewart 891f8829a4aSRandall Stewart /* 892f8829a4aSRandall Stewart * Anything set to zero is taken care of by the allocation routine's 893f8829a4aSRandall Stewart * bzero 894f8829a4aSRandall Stewart */ 895f8829a4aSRandall Stewart 896f8829a4aSRandall Stewart /* 897f8829a4aSRandall Stewart * Up front select what scoping to apply on addresses I tell my peer 898f8829a4aSRandall Stewart * Not sure what to do with these right now, we will need to come up 899f8829a4aSRandall Stewart * with a way to set them. We may need to pass them through from the 900f8829a4aSRandall Stewart * caller in the sctp_aloc_assoc() function. 901f8829a4aSRandall Stewart */ 902f8829a4aSRandall Stewart int i; 903f8829a4aSRandall Stewart 9040696e120SRandall Stewart asoc = &stcb->asoc; 905f8829a4aSRandall Stewart /* init all variables to a known value. */ 906c4739e2fSRandall Stewart SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_INUSE); 907f8829a4aSRandall Stewart asoc->max_burst = m->sctp_ep.max_burst; 908899288aeSRandall Stewart asoc->fr_max_burst = m->sctp_ep.fr_max_burst; 909f8829a4aSRandall Stewart asoc->heart_beat_delay = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); 910f8829a4aSRandall Stewart asoc->cookie_life = m->sctp_ep.def_cookie_life; 91120083c2eSMichael Tuexen asoc->sctp_cmt_on_off = m->sctp_cmt_on_off; 912c446091bSMichael Tuexen asoc->ecn_allowed = m->sctp_ecn_enable; 913830d754dSRandall Stewart asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off); 914ca85e948SMichael Tuexen asoc->sctp_cmt_pf = (uint8_t) 0; 915d61a0ae0SRandall Stewart asoc->sctp_frag_point = m->sctp_frag_point; 916e2e7c62eSMichael Tuexen asoc->sctp_features = m->sctp_features; 91758bdb691SMichael Tuexen asoc->default_dscp = m->sctp_ep.default_dscp; 91842551e99SRandall Stewart #ifdef INET6 91958bdb691SMichael Tuexen if (m->sctp_ep.default_flowlabel) { 92058bdb691SMichael Tuexen asoc->default_flowlabel = m->sctp_ep.default_flowlabel; 92158bdb691SMichael Tuexen } else { 92258bdb691SMichael Tuexen if (m->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) { 92358bdb691SMichael Tuexen asoc->default_flowlabel = sctp_select_initial_TSN(&m->sctp_ep); 92458bdb691SMichael Tuexen asoc->default_flowlabel &= 0x000fffff; 92558bdb691SMichael Tuexen asoc->default_flowlabel |= 0x80000000; 92658bdb691SMichael Tuexen } else { 927f8829a4aSRandall Stewart asoc->default_flowlabel = 0; 92858bdb691SMichael Tuexen } 92958bdb691SMichael Tuexen } 930f8829a4aSRandall Stewart #endif 9319f22f500SRandall Stewart asoc->sb_send_resv = 0; 932f8829a4aSRandall Stewart if (override_tag) { 933f8829a4aSRandall Stewart asoc->my_vtag = override_tag; 934f8829a4aSRandall Stewart } else { 935830d754dSRandall Stewart asoc->my_vtag = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 1); 936f8829a4aSRandall Stewart } 937de0e935bSRandall Stewart /* Get the nonce tags */ 938830d754dSRandall Stewart asoc->my_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 939830d754dSRandall Stewart asoc->peer_vtag_nonce = sctp_select_a_tag(m, stcb->sctp_ep->sctp_lport, stcb->rport, 0); 94042551e99SRandall Stewart asoc->vrf_id = vrf_id; 941de0e935bSRandall Stewart 94218e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 94318e198d3SRandall Stewart asoc->tsn_in_at = 0; 94418e198d3SRandall Stewart asoc->tsn_out_at = 0; 94518e198d3SRandall Stewart asoc->tsn_in_wrapped = 0; 94618e198d3SRandall Stewart asoc->tsn_out_wrapped = 0; 94718e198d3SRandall Stewart asoc->cumack_log_at = 0; 948b201f536SRandall Stewart asoc->cumack_log_atsnt = 0; 94918e198d3SRandall Stewart #endif 95018e198d3SRandall Stewart #ifdef SCTP_FS_SPEC_LOG 95118e198d3SRandall Stewart asoc->fs_index = 0; 95218e198d3SRandall Stewart #endif 953f8829a4aSRandall Stewart asoc->refcnt = 0; 954f8829a4aSRandall Stewart asoc->assoc_up_sent = 0; 955f8829a4aSRandall Stewart asoc->asconf_seq_out = asoc->str_reset_seq_out = asoc->init_seq_number = asoc->sending_seq = 956f8829a4aSRandall Stewart sctp_select_initial_TSN(&m->sctp_ep); 957c54a18d2SRandall Stewart asoc->asconf_seq_out_acked = asoc->asconf_seq_out - 1; 958f8829a4aSRandall Stewart /* we are optimisitic here */ 959f8829a4aSRandall Stewart asoc->peer_supports_pktdrop = 1; 960830d754dSRandall Stewart asoc->peer_supports_nat = 0; 961f8829a4aSRandall Stewart asoc->sent_queue_retran_cnt = 0; 962f8829a4aSRandall Stewart 963f8829a4aSRandall Stewart /* for CMT */ 9648933fa13SRandall Stewart asoc->last_net_cmt_send_started = NULL; 965f8829a4aSRandall Stewart 966f8829a4aSRandall Stewart /* This will need to be adjusted */ 967f8829a4aSRandall Stewart asoc->last_acked_seq = asoc->init_seq_number - 1; 968f8829a4aSRandall Stewart asoc->advanced_peer_ack_point = asoc->last_acked_seq; 969f8829a4aSRandall Stewart asoc->asconf_seq_in = asoc->last_acked_seq; 970f8829a4aSRandall Stewart 971f8829a4aSRandall Stewart /* here we are different, we hold the next one we expect */ 972f8829a4aSRandall Stewart asoc->str_reset_seq_in = asoc->last_acked_seq + 1; 973f8829a4aSRandall Stewart 974f8829a4aSRandall Stewart asoc->initial_init_rto_max = m->sctp_ep.initial_init_rto_max; 975f8829a4aSRandall Stewart asoc->initial_rto = m->sctp_ep.initial_rto; 976f8829a4aSRandall Stewart 977f8829a4aSRandall Stewart asoc->max_init_times = m->sctp_ep.max_init_times; 978f8829a4aSRandall Stewart asoc->max_send_times = m->sctp_ep.max_send_times; 979f8829a4aSRandall Stewart asoc->def_net_failure = m->sctp_ep.def_net_failure; 980ca85e948SMichael Tuexen asoc->def_net_pf_threshold = m->sctp_ep.def_net_pf_threshold; 981f8829a4aSRandall Stewart asoc->free_chunk_cnt = 0; 982f8829a4aSRandall Stewart 983f8829a4aSRandall Stewart asoc->iam_blocking = 0; 984493d8e5aSRandall Stewart 985f8829a4aSRandall Stewart asoc->context = m->sctp_context; 986f8829a4aSRandall Stewart asoc->def_send = m->def_send; 987f8829a4aSRandall Stewart asoc->delayed_ack = TICKS_TO_MSEC(m->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); 98842551e99SRandall Stewart asoc->sack_freq = m->sctp_ep.sctp_sack_freq; 989f8829a4aSRandall Stewart asoc->pr_sctp_cnt = 0; 990f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 991f8829a4aSRandall Stewart 992f8829a4aSRandall Stewart if (m->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 993f8829a4aSRandall Stewart struct in6pcb *inp6; 994f8829a4aSRandall Stewart 995f8829a4aSRandall Stewart /* Its a V6 socket */ 996f8829a4aSRandall Stewart inp6 = (struct in6pcb *)m; 997f8829a4aSRandall Stewart asoc->ipv6_addr_legal = 1; 998f8829a4aSRandall Stewart /* Now look at the binding flag to see if V4 will be legal */ 99944b7479bSRandall Stewart if (SCTP_IPV6_V6ONLY(inp6) == 0) { 1000f8829a4aSRandall Stewart asoc->ipv4_addr_legal = 1; 1001f8829a4aSRandall Stewart } else { 1002f8829a4aSRandall Stewart /* V4 addresses are NOT legal on the association */ 1003f8829a4aSRandall Stewart asoc->ipv4_addr_legal = 0; 1004f8829a4aSRandall Stewart } 1005f8829a4aSRandall Stewart } else { 1006f8829a4aSRandall Stewart /* Its a V4 socket, no - V6 */ 1007f8829a4aSRandall Stewart asoc->ipv4_addr_legal = 1; 1008f8829a4aSRandall Stewart asoc->ipv6_addr_legal = 0; 1009f8829a4aSRandall Stewart } 1010f8829a4aSRandall Stewart 101162c1ff9cSRandall Stewart asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(m->sctp_socket), SCTP_MINIMAL_RWND); 101262c1ff9cSRandall Stewart asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(m->sctp_socket); 1013f8829a4aSRandall Stewart 1014f8829a4aSRandall Stewart asoc->smallest_mtu = m->sctp_frag_point; 1015f8829a4aSRandall Stewart asoc->minrto = m->sctp_ep.sctp_minrto; 1016f8829a4aSRandall Stewart asoc->maxrto = m->sctp_ep.sctp_maxrto; 1017f8829a4aSRandall Stewart 1018f8829a4aSRandall Stewart asoc->locked_on_sending = NULL; 1019f8829a4aSRandall Stewart asoc->stream_locked_on = 0; 1020f8829a4aSRandall Stewart asoc->ecn_echo_cnt_onq = 0; 1021f8829a4aSRandall Stewart asoc->stream_locked = 0; 1022f8829a4aSRandall Stewart 102342551e99SRandall Stewart asoc->send_sack = 1; 102442551e99SRandall Stewart 102542551e99SRandall Stewart LIST_INIT(&asoc->sctp_restricted_addrs); 102642551e99SRandall Stewart 1027f8829a4aSRandall Stewart TAILQ_INIT(&asoc->nets); 1028f8829a4aSRandall Stewart TAILQ_INIT(&asoc->pending_reply_queue); 10292afb3e84SRandall Stewart TAILQ_INIT(&asoc->asconf_ack_sent); 1030f8829a4aSRandall Stewart /* Setup to fill the hb random cache at first HB */ 1031f8829a4aSRandall Stewart asoc->hb_random_idx = 4; 1032f8829a4aSRandall Stewart 1033f8829a4aSRandall Stewart asoc->sctp_autoclose_ticks = m->sctp_ep.auto_close_time; 1034f8829a4aSRandall Stewart 10350e9a9c10SMichael Tuexen stcb->asoc.congestion_control_module = m->sctp_ep.sctp_default_cc_module; 10360e9a9c10SMichael Tuexen stcb->asoc.cc_functions = sctp_cc_functions[m->sctp_ep.sctp_default_cc_module]; 1037b54d3a6cSRandall Stewart 1038f7a77f6fSMichael Tuexen stcb->asoc.stream_scheduling_module = m->sctp_ep.sctp_default_ss_module; 1039f7a77f6fSMichael Tuexen stcb->asoc.ss_functions = sctp_ss_functions[m->sctp_ep.sctp_default_ss_module]; 1040f7a77f6fSMichael Tuexen 1041b54d3a6cSRandall Stewart /* 1042f8829a4aSRandall Stewart * Now the stream parameters, here we allocate space for all streams 1043f8829a4aSRandall Stewart * that we request by default. 1044f8829a4aSRandall Stewart */ 1045ea44232bSRandall Stewart asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams = 1046f8829a4aSRandall Stewart m->sctp_ep.pre_open_stream_count; 1047f8829a4aSRandall Stewart SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *, 1048f8829a4aSRandall Stewart asoc->streamoutcnt * sizeof(struct sctp_stream_out), 1049207304d4SRandall Stewart SCTP_M_STRMO); 1050f8829a4aSRandall Stewart if (asoc->strmout == NULL) { 1051f8829a4aSRandall Stewart /* big trouble no memory */ 1052c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1053f8829a4aSRandall Stewart return (ENOMEM); 1054f8829a4aSRandall Stewart } 1055f8829a4aSRandall Stewart for (i = 0; i < asoc->streamoutcnt; i++) { 1056f8829a4aSRandall Stewart /* 1057f8829a4aSRandall Stewart * inbound side must be set to 0xffff, also NOTE when we get 1058f8829a4aSRandall Stewart * the INIT-ACK back (for INIT sender) we MUST reduce the 1059f8829a4aSRandall Stewart * count (streamoutcnt) but first check if we sent to any of 1060f8829a4aSRandall Stewart * the upper streams that were dropped (if some were). Those 1061f8829a4aSRandall Stewart * that were dropped must be notified to the upper layer as 1062f8829a4aSRandall Stewart * failed to send. 1063f8829a4aSRandall Stewart */ 1064f8829a4aSRandall Stewart asoc->strmout[i].next_sequence_sent = 0x0; 1065f8829a4aSRandall Stewart TAILQ_INIT(&asoc->strmout[i].outqueue); 1066f8829a4aSRandall Stewart asoc->strmout[i].stream_no = i; 1067f8829a4aSRandall Stewart asoc->strmout[i].last_msg_incomplete = 0; 1068252f7f93SMichael Tuexen asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL); 1069f8829a4aSRandall Stewart } 1070f7a77f6fSMichael Tuexen asoc->ss_functions.sctp_ss_init(stcb, asoc, 0); 1071f7a77f6fSMichael Tuexen 1072f8829a4aSRandall Stewart /* Now the mapping array */ 1073f8829a4aSRandall Stewart asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY; 1074f8829a4aSRandall Stewart SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size, 1075207304d4SRandall Stewart SCTP_M_MAP); 1076f8829a4aSRandall Stewart if (asoc->mapping_array == NULL) { 1077207304d4SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1078c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1079f8829a4aSRandall Stewart return (ENOMEM); 1080f8829a4aSRandall Stewart } 1081f8829a4aSRandall Stewart memset(asoc->mapping_array, 0, asoc->mapping_array_size); 1082b5c16493SMichael Tuexen SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size, 1083830d754dSRandall Stewart SCTP_M_MAP); 1084bf1be571SRandall Stewart if (asoc->nr_mapping_array == NULL) { 1085bf1be571SRandall Stewart SCTP_FREE(asoc->strmout, SCTP_M_STRMO); 1086bf1be571SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1087bf1be571SRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 1088bf1be571SRandall Stewart return (ENOMEM); 1089bf1be571SRandall Stewart } 1090b5c16493SMichael Tuexen memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size); 1091830d754dSRandall Stewart 1092f8829a4aSRandall Stewart /* Now the init of the other outqueues */ 1093f8829a4aSRandall Stewart TAILQ_INIT(&asoc->free_chunks); 1094f8829a4aSRandall Stewart TAILQ_INIT(&asoc->control_send_queue); 1095c54a18d2SRandall Stewart TAILQ_INIT(&asoc->asconf_send_queue); 1096f8829a4aSRandall Stewart TAILQ_INIT(&asoc->send_queue); 1097f8829a4aSRandall Stewart TAILQ_INIT(&asoc->sent_queue); 1098f8829a4aSRandall Stewart TAILQ_INIT(&asoc->reasmqueue); 1099f8829a4aSRandall Stewart TAILQ_INIT(&asoc->resetHead); 1100f8829a4aSRandall Stewart asoc->max_inbound_streams = m->sctp_ep.max_open_streams_intome; 1101f8829a4aSRandall Stewart TAILQ_INIT(&asoc->asconf_queue); 1102f8829a4aSRandall Stewart /* authentication fields */ 1103f8829a4aSRandall Stewart asoc->authinfo.random = NULL; 1104830d754dSRandall Stewart asoc->authinfo.active_keyid = 0; 1105f8829a4aSRandall Stewart asoc->authinfo.assoc_key = NULL; 1106f8829a4aSRandall Stewart asoc->authinfo.assoc_keyid = 0; 1107f8829a4aSRandall Stewart asoc->authinfo.recv_key = NULL; 1108f8829a4aSRandall Stewart asoc->authinfo.recv_keyid = 0; 1109f8829a4aSRandall Stewart LIST_INIT(&asoc->shared_keys); 1110f42a358aSRandall Stewart asoc->marked_retrans = 0; 1111c9c58059SMichael Tuexen asoc->port = m->sctp_ep.port; 1112f42a358aSRandall Stewart asoc->timoinit = 0; 1113f42a358aSRandall Stewart asoc->timodata = 0; 1114f42a358aSRandall Stewart asoc->timosack = 0; 1115f42a358aSRandall Stewart asoc->timoshutdown = 0; 1116f42a358aSRandall Stewart asoc->timoheartbeat = 0; 1117f42a358aSRandall Stewart asoc->timocookie = 0; 1118f42a358aSRandall Stewart asoc->timoshutdownack = 0; 11196e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&asoc->start_time); 11206e55db54SRandall Stewart asoc->discontinuity_time = asoc->start_time; 1121eacc51c5SRandall Stewart /* 1122eacc51c5SRandall Stewart * sa_ignore MEMLEAK {memory is put in the assoc mapping array and 112377acdc25SRandall Stewart * freed later when the association is freed. 1124eacc51c5SRandall Stewart */ 1125f8829a4aSRandall Stewart return (0); 1126f8829a4aSRandall Stewart } 1127f8829a4aSRandall Stewart 11280e13104dSRandall Stewart void 11290e13104dSRandall Stewart sctp_print_mapping_array(struct sctp_association *asoc) 11300e13104dSRandall Stewart { 1131aed5947cSMichael Tuexen unsigned int i, limit; 11320e13104dSRandall Stewart 1133aed5947cSMichael Tuexen printf("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n", 11340e13104dSRandall Stewart asoc->mapping_array_size, 11350e13104dSRandall Stewart asoc->mapping_array_base_tsn, 11360e13104dSRandall Stewart asoc->cumulative_tsn, 1137aed5947cSMichael Tuexen asoc->highest_tsn_inside_map, 1138aed5947cSMichael Tuexen asoc->highest_tsn_inside_nr_map); 1139aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 1140aed5947cSMichael Tuexen if (asoc->mapping_array[limit - 1]) { 114177acdc25SRandall Stewart break; 114277acdc25SRandall Stewart } 114377acdc25SRandall Stewart } 1144aed5947cSMichael Tuexen printf("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 114577acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1146aed5947cSMichael Tuexen printf("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 114777acdc25SRandall Stewart } 1148aed5947cSMichael Tuexen if (limit % 16) 114977acdc25SRandall Stewart printf("\n"); 1150aed5947cSMichael Tuexen for (limit = asoc->mapping_array_size; limit > 1; limit--) { 1151aed5947cSMichael Tuexen if (asoc->nr_mapping_array[limit - 1]) { 115277acdc25SRandall Stewart break; 115377acdc25SRandall Stewart } 115477acdc25SRandall Stewart } 1155aed5947cSMichael Tuexen printf("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit); 115677acdc25SRandall Stewart for (i = 0; i < limit; i++) { 1157553aff12SMichael Tuexen printf("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ' : '\n'); 11580e13104dSRandall Stewart } 1159aed5947cSMichael Tuexen if (limit % 16) 11600e13104dSRandall Stewart printf("\n"); 11610e13104dSRandall Stewart } 11620e13104dSRandall Stewart 1163f8829a4aSRandall Stewart int 11640696e120SRandall Stewart sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed) 1165f8829a4aSRandall Stewart { 1166f8829a4aSRandall Stewart /* mapping array needs to grow */ 1167b5c16493SMichael Tuexen uint8_t *new_array1, *new_array2; 11680696e120SRandall Stewart uint32_t new_size; 1169f8829a4aSRandall Stewart 11700696e120SRandall Stewart new_size = asoc->mapping_array_size + ((needed + 7) / 8 + SCTP_MAPPING_ARRAY_INCR); 1171b5c16493SMichael Tuexen SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP); 1172b5c16493SMichael Tuexen SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP); 1173b5c16493SMichael Tuexen if ((new_array1 == NULL) || (new_array2 == NULL)) { 1174f8829a4aSRandall Stewart /* can't get more, forget it */ 1175b5c16493SMichael Tuexen SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size); 1176b5c16493SMichael Tuexen if (new_array1) { 1177b5c16493SMichael Tuexen SCTP_FREE(new_array1, SCTP_M_MAP); 1178b5c16493SMichael Tuexen } 1179b5c16493SMichael Tuexen if (new_array2) { 1180b5c16493SMichael Tuexen SCTP_FREE(new_array2, SCTP_M_MAP); 1181b5c16493SMichael Tuexen } 1182f8829a4aSRandall Stewart return (-1); 1183f8829a4aSRandall Stewart } 1184b5c16493SMichael Tuexen memset(new_array1, 0, new_size); 1185b5c16493SMichael Tuexen memset(new_array2, 0, new_size); 1186b5c16493SMichael Tuexen memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size); 1187b5c16493SMichael Tuexen memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size); 1188207304d4SRandall Stewart SCTP_FREE(asoc->mapping_array, SCTP_M_MAP); 1189830d754dSRandall Stewart SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP); 1190b5c16493SMichael Tuexen asoc->mapping_array = new_array1; 1191b5c16493SMichael Tuexen asoc->nr_mapping_array = new_array2; 1192b5c16493SMichael Tuexen asoc->mapping_array_size = new_size; 1193830d754dSRandall Stewart return (0); 1194830d754dSRandall Stewart } 1195830d754dSRandall Stewart 11968933fa13SRandall Stewart 119742551e99SRandall Stewart static void 119842551e99SRandall Stewart sctp_iterator_work(struct sctp_iterator *it) 119942551e99SRandall Stewart { 120042551e99SRandall Stewart int iteration_count = 0; 120142551e99SRandall Stewart int inp_skip = 0; 1202ec4c19fcSRandall Stewart int first_in = 1; 1203ec4c19fcSRandall Stewart struct sctp_inpcb *tinp; 120442551e99SRandall Stewart 1205ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 120642551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1207ad81507eSRandall Stewart if (it->inp) { 1208ec4c19fcSRandall Stewart SCTP_INP_RLOCK(it->inp); 120942551e99SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1210ad81507eSRandall Stewart } 121142551e99SRandall Stewart if (it->inp == NULL) { 121242551e99SRandall Stewart /* iterator is complete */ 121342551e99SRandall Stewart done_with_iterator: 121442551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1215ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 121642551e99SRandall Stewart if (it->function_atend != NULL) { 121742551e99SRandall Stewart (*it->function_atend) (it->pointer, it->val); 121842551e99SRandall Stewart } 1219207304d4SRandall Stewart SCTP_FREE(it, SCTP_M_ITER); 122042551e99SRandall Stewart return; 122142551e99SRandall Stewart } 122242551e99SRandall Stewart select_a_new_ep: 1223ec4c19fcSRandall Stewart if (first_in) { 1224ec4c19fcSRandall Stewart first_in = 0; 1225ec4c19fcSRandall Stewart } else { 1226f7517433SRandall Stewart SCTP_INP_RLOCK(it->inp); 1227ec4c19fcSRandall Stewart } 122842551e99SRandall Stewart while (((it->pcb_flags) && 122942551e99SRandall Stewart ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) || 123042551e99SRandall Stewart ((it->pcb_features) && 123142551e99SRandall Stewart ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) { 123242551e99SRandall Stewart /* endpoint flags or features don't match, so keep looking */ 123342551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 1234f7517433SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 123542551e99SRandall Stewart goto done_with_iterator; 123642551e99SRandall Stewart } 1237ec4c19fcSRandall Stewart tinp = it->inp; 123842551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 1239ec4c19fcSRandall Stewart SCTP_INP_RUNLOCK(tinp); 124042551e99SRandall Stewart if (it->inp == NULL) { 124142551e99SRandall Stewart goto done_with_iterator; 124242551e99SRandall Stewart } 124342551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1244f7517433SRandall Stewart } 124542551e99SRandall Stewart /* now go through each assoc which is in the desired state */ 124642551e99SRandall Stewart if (it->done_current_ep == 0) { 124742551e99SRandall Stewart if (it->function_inp != NULL) 124842551e99SRandall Stewart inp_skip = (*it->function_inp) (it->inp, it->pointer, it->val); 124942551e99SRandall Stewart it->done_current_ep = 1; 125042551e99SRandall Stewart } 125142551e99SRandall Stewart if (it->stcb == NULL) { 125242551e99SRandall Stewart /* run the per instance function */ 125342551e99SRandall Stewart it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list); 125442551e99SRandall Stewart } 125542551e99SRandall Stewart if ((inp_skip) || it->stcb == NULL) { 125642551e99SRandall Stewart if (it->function_inp_end != NULL) { 125742551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 125842551e99SRandall Stewart it->pointer, 125942551e99SRandall Stewart it->val); 126042551e99SRandall Stewart } 126142551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 126242551e99SRandall Stewart goto no_stcb; 126342551e99SRandall Stewart } 126442551e99SRandall Stewart while (it->stcb) { 126542551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 126642551e99SRandall Stewart if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) { 126742551e99SRandall Stewart /* not in the right state... keep looking */ 126842551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 126942551e99SRandall Stewart goto next_assoc; 127042551e99SRandall Stewart } 127142551e99SRandall Stewart /* see if we have limited out the iterator loop */ 127242551e99SRandall Stewart iteration_count++; 127342551e99SRandall Stewart if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) { 127442551e99SRandall Stewart /* Pause to let others grab the lock */ 127542551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, 1); 127642551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 1277c4739e2fSRandall Stewart SCTP_INP_INCR_REF(it->inp); 127842551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 127942551e99SRandall Stewart SCTP_ITERATOR_UNLOCK(); 1280ec4c19fcSRandall Stewart SCTP_INP_INFO_RUNLOCK(); 1281ec4c19fcSRandall Stewart SCTP_INP_INFO_RLOCK(); 128242551e99SRandall Stewart SCTP_ITERATOR_LOCK(); 1283f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags) { 1284f7517433SRandall Stewart /* We won't be staying here */ 1285f7517433SRandall Stewart SCTP_INP_DECR_REF(it->inp); 1286f7517433SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 1287f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1288f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_IT) { 1289f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT; 1290f7517433SRandall Stewart goto done_with_iterator; 1291f7517433SRandall Stewart } 1292f7517433SRandall Stewart if (sctp_it_ctl.iterator_flags & 1293f7517433SRandall Stewart SCTP_ITERATOR_STOP_CUR_INP) { 1294f7517433SRandall Stewart sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP; 1295f7517433SRandall Stewart goto no_stcb; 1296f7517433SRandall Stewart } 1297f7517433SRandall Stewart /* If we reach here huh? */ 1298f7517433SRandall Stewart printf("Unknown it ctl flag %x\n", 1299f7517433SRandall Stewart sctp_it_ctl.iterator_flags); 1300f7517433SRandall Stewart sctp_it_ctl.iterator_flags = 0; 1301f7517433SRandall Stewart } 130242551e99SRandall Stewart SCTP_INP_RLOCK(it->inp); 1303c4739e2fSRandall Stewart SCTP_INP_DECR_REF(it->inp); 130442551e99SRandall Stewart SCTP_TCB_LOCK(it->stcb); 130542551e99SRandall Stewart atomic_add_int(&it->stcb->asoc.refcnt, -1); 130642551e99SRandall Stewart iteration_count = 0; 130742551e99SRandall Stewart } 130842551e99SRandall Stewart /* run function on this one */ 130942551e99SRandall Stewart (*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val); 131042551e99SRandall Stewart 131142551e99SRandall Stewart /* 131242551e99SRandall Stewart * we lie here, it really needs to have its own type but 131342551e99SRandall Stewart * first I must verify that this won't effect things :-0 131442551e99SRandall Stewart */ 131542551e99SRandall Stewart if (it->no_chunk_output == 0) 1316ceaad40aSRandall Stewart sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 131742551e99SRandall Stewart 131842551e99SRandall Stewart SCTP_TCB_UNLOCK(it->stcb); 131942551e99SRandall Stewart next_assoc: 132042551e99SRandall Stewart it->stcb = LIST_NEXT(it->stcb, sctp_tcblist); 132142551e99SRandall Stewart if (it->stcb == NULL) { 132242551e99SRandall Stewart /* Run last function */ 132342551e99SRandall Stewart if (it->function_inp_end != NULL) { 132442551e99SRandall Stewart inp_skip = (*it->function_inp_end) (it->inp, 132542551e99SRandall Stewart it->pointer, 132642551e99SRandall Stewart it->val); 132742551e99SRandall Stewart } 132842551e99SRandall Stewart } 132942551e99SRandall Stewart } 133042551e99SRandall Stewart SCTP_INP_RUNLOCK(it->inp); 133142551e99SRandall Stewart no_stcb: 133242551e99SRandall Stewart /* done with all assocs on this endpoint, move on to next endpoint */ 133342551e99SRandall Stewart it->done_current_ep = 0; 133442551e99SRandall Stewart if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { 133542551e99SRandall Stewart it->inp = NULL; 133642551e99SRandall Stewart } else { 133742551e99SRandall Stewart it->inp = LIST_NEXT(it->inp, sctp_list); 133842551e99SRandall Stewart } 133942551e99SRandall Stewart if (it->inp == NULL) { 134042551e99SRandall Stewart goto done_with_iterator; 134142551e99SRandall Stewart } 134242551e99SRandall Stewart goto select_a_new_ep; 134342551e99SRandall Stewart } 134442551e99SRandall Stewart 134542551e99SRandall Stewart void 134642551e99SRandall Stewart sctp_iterator_worker(void) 134742551e99SRandall Stewart { 13484a9ef3f8SMichael Tuexen struct sctp_iterator *it, *nit; 134942551e99SRandall Stewart 135042551e99SRandall Stewart /* This function is called with the WQ lock in place */ 135142551e99SRandall Stewart 1352f7517433SRandall Stewart sctp_it_ctl.iterator_running = 1; 13534a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(it, &sctp_it_ctl.iteratorhead, sctp_nxt_itr, nit) { 13544a9ef3f8SMichael Tuexen sctp_it_ctl.cur_it = it; 135542551e99SRandall Stewart /* now lets work on this one */ 1356f7517433SRandall Stewart TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); 135742551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_UNLOCK(); 1358f7517433SRandall Stewart CURVNET_SET(it->vn); 135942551e99SRandall Stewart sctp_iterator_work(it); 1360f79aab18SRandall Stewart sctp_it_ctl.cur_it = NULL; 1361f7517433SRandall Stewart CURVNET_RESTORE(); 136242551e99SRandall Stewart SCTP_IPI_ITERATOR_WQ_LOCK(); 13633c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 136442551e99SRandall Stewart } 1365f7517433SRandall Stewart sctp_it_ctl.iterator_running = 0; 136642551e99SRandall Stewart return; 136742551e99SRandall Stewart } 136842551e99SRandall Stewart 1369f8829a4aSRandall Stewart 1370f8829a4aSRandall Stewart static void 1371f8829a4aSRandall Stewart sctp_handle_addr_wq(void) 1372f8829a4aSRandall Stewart { 1373f8829a4aSRandall Stewart /* deal with the ADDR wq from the rtsock calls */ 13744a9ef3f8SMichael Tuexen struct sctp_laddr *wi, *nwi; 137542551e99SRandall Stewart struct sctp_asconf_iterator *asc; 1376f8829a4aSRandall Stewart 137742551e99SRandall Stewart SCTP_MALLOC(asc, struct sctp_asconf_iterator *, 1378207304d4SRandall Stewart sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT); 137942551e99SRandall Stewart if (asc == NULL) { 138042551e99SRandall Stewart /* Try later, no memory */ 1381f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 1382f8829a4aSRandall Stewart (struct sctp_inpcb *)NULL, 1383f8829a4aSRandall Stewart (struct sctp_tcb *)NULL, 1384f8829a4aSRandall Stewart (struct sctp_nets *)NULL); 138542551e99SRandall Stewart return; 1386f8829a4aSRandall Stewart } 138742551e99SRandall Stewart LIST_INIT(&asc->list_of_work); 138842551e99SRandall Stewart asc->cnt = 0; 1389f7517433SRandall Stewart 1390f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 13914a9ef3f8SMichael Tuexen LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) { 139242551e99SRandall Stewart LIST_REMOVE(wi, sctp_nxt_addr); 139342551e99SRandall Stewart LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr); 139442551e99SRandall Stewart asc->cnt++; 1395f8829a4aSRandall Stewart } 1396f7517433SRandall Stewart SCTP_WQ_ADDR_UNLOCK(); 1397f7517433SRandall Stewart 139842551e99SRandall Stewart if (asc->cnt == 0) { 1399207304d4SRandall Stewart SCTP_FREE(asc, SCTP_M_ASC_IT); 140042551e99SRandall Stewart } else { 14011b649582SRandall Stewart (void)sctp_initiate_iterator(sctp_asconf_iterator_ep, 14021b649582SRandall Stewart sctp_asconf_iterator_stcb, 140342551e99SRandall Stewart NULL, /* No ep end for boundall */ 140442551e99SRandall Stewart SCTP_PCB_FLAGS_BOUNDALL, 140542551e99SRandall Stewart SCTP_PCB_ANY_FEATURES, 14061b649582SRandall Stewart SCTP_ASOC_ANY_STATE, 14071b649582SRandall Stewart (void *)asc, 0, 14081b649582SRandall Stewart sctp_asconf_iterator_end, NULL, 0); 140942551e99SRandall Stewart } 1410f8829a4aSRandall Stewart } 1411f8829a4aSRandall Stewart 1412b54d3a6cSRandall Stewart int retcode = 0; 1413b54d3a6cSRandall Stewart int cur_oerr = 0; 1414b54d3a6cSRandall Stewart 1415f8829a4aSRandall Stewart void 1416f8829a4aSRandall Stewart sctp_timeout_handler(void *t) 1417f8829a4aSRandall Stewart { 1418f8829a4aSRandall Stewart struct sctp_inpcb *inp; 1419f8829a4aSRandall Stewart struct sctp_tcb *stcb; 1420f8829a4aSRandall Stewart struct sctp_nets *net; 1421f8829a4aSRandall Stewart struct sctp_timer *tmr; 1422ceaad40aSRandall Stewart 1423ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1424ceaad40aSRandall Stewart struct socket *so; 1425ceaad40aSRandall Stewart 1426ceaad40aSRandall Stewart #endif 1427d61374e1SRandall Stewart int did_output, type; 1428f8829a4aSRandall Stewart 1429f8829a4aSRandall Stewart tmr = (struct sctp_timer *)t; 1430f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)tmr->ep; 1431f8829a4aSRandall Stewart stcb = (struct sctp_tcb *)tmr->tcb; 1432f8829a4aSRandall Stewart net = (struct sctp_nets *)tmr->net; 14338518270eSMichael Tuexen CURVNET_SET((struct vnet *)tmr->vnet); 1434f8829a4aSRandall Stewart did_output = 1; 1435f8829a4aSRandall Stewart 1436f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1437f8829a4aSRandall Stewart sctp_audit_log(0xF0, (uint8_t) tmr->type); 1438f8829a4aSRandall Stewart sctp_auditing(3, inp, stcb, net); 1439f8829a4aSRandall Stewart #endif 1440f8829a4aSRandall Stewart 1441f8829a4aSRandall Stewart /* sanity checks... */ 1442f8829a4aSRandall Stewart if (tmr->self != (void *)tmr) { 1443f8829a4aSRandall Stewart /* 1444ad81507eSRandall Stewart * SCTP_PRINTF("Stale SCTP timer fired (%p), ignoring...\n", 1445f8829a4aSRandall Stewart * tmr); 1446f8829a4aSRandall Stewart */ 14478518270eSMichael Tuexen CURVNET_RESTORE(); 1448f8829a4aSRandall Stewart return; 1449f8829a4aSRandall Stewart } 1450a5d547adSRandall Stewart tmr->stopped_from = 0xa001; 1451f8829a4aSRandall Stewart if (!SCTP_IS_TIMER_TYPE_VALID(tmr->type)) { 1452f8829a4aSRandall Stewart /* 1453ad81507eSRandall Stewart * SCTP_PRINTF("SCTP timer fired with invalid type: 0x%x\n", 1454f8829a4aSRandall Stewart * tmr->type); 1455f8829a4aSRandall Stewart */ 14568518270eSMichael Tuexen CURVNET_RESTORE(); 1457f8829a4aSRandall Stewart return; 1458f8829a4aSRandall Stewart } 1459a5d547adSRandall Stewart tmr->stopped_from = 0xa002; 1460f8829a4aSRandall Stewart if ((tmr->type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) { 14618518270eSMichael Tuexen CURVNET_RESTORE(); 1462f8829a4aSRandall Stewart return; 1463f8829a4aSRandall Stewart } 1464f8829a4aSRandall Stewart /* if this is an iterator timeout, get the struct and clear inp */ 1465a5d547adSRandall Stewart tmr->stopped_from = 0xa003; 1466d61374e1SRandall Stewart type = tmr->type; 1467f8829a4aSRandall Stewart if (inp) { 1468f8829a4aSRandall Stewart SCTP_INP_INCR_REF(inp); 1469f8829a4aSRandall Stewart if ((inp->sctp_socket == 0) && 1470f8829a4aSRandall Stewart ((tmr->type != SCTP_TIMER_TYPE_INPKILL) && 1471810ec536SMichael Tuexen (tmr->type != SCTP_TIMER_TYPE_INIT) && 1472a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SEND) && 1473a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_RECV) && 1474a1e13272SRandall Stewart (tmr->type != SCTP_TIMER_TYPE_HEARTBEAT) && 1475f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWN) && 1476f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNACK) && 1477f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_SHUTDOWNGUARD) && 1478f8829a4aSRandall Stewart (tmr->type != SCTP_TIMER_TYPE_ASOCKILL)) 1479f8829a4aSRandall Stewart ) { 1480f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 14818518270eSMichael Tuexen CURVNET_RESTORE(); 1482f8829a4aSRandall Stewart return; 1483f8829a4aSRandall Stewart } 1484f8829a4aSRandall Stewart } 1485a5d547adSRandall Stewart tmr->stopped_from = 0xa004; 1486f8829a4aSRandall Stewart if (stcb) { 1487c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1488f8829a4aSRandall Stewart if (stcb->asoc.state == 0) { 1489c105859eSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1490f8829a4aSRandall Stewart if (inp) { 1491f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1492f8829a4aSRandall Stewart } 14938518270eSMichael Tuexen CURVNET_RESTORE(); 1494f8829a4aSRandall Stewart return; 1495f8829a4aSRandall Stewart } 1496f8829a4aSRandall Stewart } 1497a5d547adSRandall Stewart tmr->stopped_from = 0xa005; 1498ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Timer type %d goes off\n", tmr->type); 1499139bc87fSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 1500f8829a4aSRandall Stewart if (inp) { 1501f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1502f8829a4aSRandall Stewart } 1503207304d4SRandall Stewart if (stcb) { 1504207304d4SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1505207304d4SRandall Stewart } 15068518270eSMichael Tuexen CURVNET_RESTORE(); 1507f8829a4aSRandall Stewart return; 1508f8829a4aSRandall Stewart } 1509a5d547adSRandall Stewart tmr->stopped_from = 0xa006; 1510a5d547adSRandall Stewart 1511f8829a4aSRandall Stewart if (stcb) { 1512f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 151350cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 1514b54d3a6cSRandall Stewart if ((tmr->type != SCTP_TIMER_TYPE_ASOCKILL) && 1515b54d3a6cSRandall Stewart ((stcb->asoc.state == 0) || 1516b54d3a6cSRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) { 1517b54d3a6cSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1518b54d3a6cSRandall Stewart if (inp) { 1519b54d3a6cSRandall Stewart SCTP_INP_DECR_REF(inp); 1520b54d3a6cSRandall Stewart } 15218518270eSMichael Tuexen CURVNET_RESTORE(); 1522b54d3a6cSRandall Stewart return; 1523b54d3a6cSRandall Stewart } 1524f8829a4aSRandall Stewart } 152544b7479bSRandall Stewart /* record in stopped what t-o occured */ 152644b7479bSRandall Stewart tmr->stopped_from = tmr->type; 152744b7479bSRandall Stewart 1528f8829a4aSRandall Stewart /* mark as being serviced now */ 152944b7479bSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 153044b7479bSRandall Stewart /* 153144b7479bSRandall Stewart * Callout has been rescheduled. 153244b7479bSRandall Stewart */ 153344b7479bSRandall Stewart goto get_out; 153444b7479bSRandall Stewart } 153544b7479bSRandall Stewart if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) { 153644b7479bSRandall Stewart /* 153744b7479bSRandall Stewart * Not active, so no action. 153844b7479bSRandall Stewart */ 153944b7479bSRandall Stewart goto get_out; 154044b7479bSRandall Stewart } 1541139bc87fSRandall Stewart SCTP_OS_TIMER_DEACTIVATE(&tmr->timer); 1542f8829a4aSRandall Stewart 1543f8829a4aSRandall Stewart /* call the handler for the appropriate timer type */ 1544f8829a4aSRandall Stewart switch (tmr->type) { 1545d61a0ae0SRandall Stewart case SCTP_TIMER_TYPE_ZERO_COPY: 1546eacc51c5SRandall Stewart if (inp == NULL) { 1547eacc51c5SRandall Stewart break; 1548eacc51c5SRandall Stewart } 1549d61a0ae0SRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 1550d61a0ae0SRandall Stewart SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); 1551d61a0ae0SRandall Stewart } 1552d61a0ae0SRandall Stewart break; 1553ad21a364SRandall Stewart case SCTP_TIMER_TYPE_ZCOPY_SENDQ: 1554eacc51c5SRandall Stewart if (inp == NULL) { 1555eacc51c5SRandall Stewart break; 1556eacc51c5SRandall Stewart } 1557ad21a364SRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 1558ad21a364SRandall Stewart SCTP_ZERO_COPY_SENDQ_EVENT(inp, inp->sctp_socket); 1559ad21a364SRandall Stewart } 1560ad21a364SRandall Stewart break; 1561f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 1562f8829a4aSRandall Stewart sctp_handle_addr_wq(); 1563f8829a4aSRandall Stewart break; 1564f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 1565ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1566ad81507eSRandall Stewart break; 1567ad81507eSRandall Stewart } 1568f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timodata); 1569f42a358aSRandall Stewart stcb->asoc.timodata++; 1570f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 1571f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 1572f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 1573f8829a4aSRandall Stewart } 1574b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1575b54d3a6cSRandall Stewart cur_oerr = stcb->asoc.overall_error_count; 1576b54d3a6cSRandall Stewart retcode = sctp_t3rxt_timer(inp, stcb, net); 1577b54d3a6cSRandall Stewart if (retcode) { 1578f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1579f8829a4aSRandall Stewart 1580f8829a4aSRandall Stewart goto out_decr; 1581f8829a4aSRandall Stewart } 1582b54d3a6cSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1583f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1584f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1585f8829a4aSRandall Stewart #endif 1586ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1587f8829a4aSRandall Stewart if ((stcb->asoc.num_send_timers_up == 0) && 15884a9ef3f8SMichael Tuexen (stcb->asoc.sent_queue_cnt > 0)) { 1589f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 1590f8829a4aSRandall Stewart 1591f8829a4aSRandall Stewart /* 1592f8829a4aSRandall Stewart * safeguard. If there on some on the sent queue 1593f8829a4aSRandall Stewart * somewhere but no timers running something is 1594f8829a4aSRandall Stewart * wrong... so we start a timer on the first chunk 1595f8829a4aSRandall Stewart * on the send queue on whatever net it is sent to. 1596f8829a4aSRandall Stewart */ 1597f8829a4aSRandall Stewart chk = TAILQ_FIRST(&stcb->asoc.sent_queue); 1598f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, 1599f8829a4aSRandall Stewart chk->whoTo); 1600f8829a4aSRandall Stewart } 1601f8829a4aSRandall Stewart break; 1602f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 1603ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1604ad81507eSRandall Stewart break; 1605ad81507eSRandall Stewart } 1606f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinit); 1607f42a358aSRandall Stewart stcb->asoc.timoinit++; 1608f8829a4aSRandall Stewart if (sctp_t1init_timer(inp, stcb, net)) { 1609f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1610f8829a4aSRandall Stewart goto out_decr; 1611f8829a4aSRandall Stewart } 1612f8829a4aSRandall Stewart /* We do output but not here */ 1613f8829a4aSRandall Stewart did_output = 0; 1614f8829a4aSRandall Stewart break; 1615f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 1616ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1617ad81507eSRandall Stewart break; 1618ca85e948SMichael Tuexen } 1619f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosack); 1620f42a358aSRandall Stewart stcb->asoc.timosack++; 1621689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED); 1622f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1623f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1624f8829a4aSRandall Stewart #endif 1625ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED); 1626f8829a4aSRandall Stewart break; 1627f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 1628ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1629ad81507eSRandall Stewart break; 1630ad81507eSRandall Stewart } 1631f8829a4aSRandall Stewart if (sctp_shutdown_timer(inp, stcb, net)) { 1632f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1633f8829a4aSRandall Stewart goto out_decr; 1634f8829a4aSRandall Stewart } 1635f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdown); 1636f42a358aSRandall Stewart stcb->asoc.timoshutdown++; 1637f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1638f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1639f8829a4aSRandall Stewart #endif 1640ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED); 1641f8829a4aSRandall Stewart break; 1642f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 1643ca85e948SMichael Tuexen if ((stcb == NULL) || (inp == NULL) || (net == NULL)) { 1644ad81507eSRandall Stewart break; 1645ad81507eSRandall Stewart } 1646f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoheartbeat); 1647f42a358aSRandall Stewart stcb->asoc.timoheartbeat++; 1648ca85e948SMichael Tuexen if (sctp_heartbeat_timer(inp, stcb, net)) { 1649f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1650f8829a4aSRandall Stewart goto out_decr; 1651f8829a4aSRandall Stewart } 1652f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1653ca85e948SMichael Tuexen sctp_auditing(4, inp, stcb, net); 1654f8829a4aSRandall Stewart #endif 1655ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_NOHB)) { 1656629749b6SMichael Tuexen sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); 1657ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED); 1658f8829a4aSRandall Stewart } 1659f8829a4aSRandall Stewart break; 1660f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 1661ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1662ad81507eSRandall Stewart break; 1663ad81507eSRandall Stewart } 1664f8829a4aSRandall Stewart if (sctp_cookie_timer(inp, stcb, net)) { 1665f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1666f8829a4aSRandall Stewart goto out_decr; 1667f8829a4aSRandall Stewart } 1668f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timocookie); 1669f42a358aSRandall Stewart stcb->asoc.timocookie++; 1670f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1671f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1672f8829a4aSRandall Stewart #endif 1673f8829a4aSRandall Stewart /* 1674f8829a4aSRandall Stewart * We consider T3 and Cookie timer pretty much the same with 1675f8829a4aSRandall Stewart * respect to where from in chunk_output. 1676f8829a4aSRandall Stewart */ 1677ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); 1678f8829a4aSRandall Stewart break; 1679f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 1680f8829a4aSRandall Stewart { 1681f8829a4aSRandall Stewart struct timeval tv; 1682f8829a4aSRandall Stewart int i, secret; 1683f8829a4aSRandall Stewart 1684ad81507eSRandall Stewart if (inp == NULL) { 1685ad81507eSRandall Stewart break; 1686ad81507eSRandall Stewart } 1687f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timosecret); 16886e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&tv); 1689f8829a4aSRandall Stewart SCTP_INP_WLOCK(inp); 1690f8829a4aSRandall Stewart inp->sctp_ep.time_of_secret_change = tv.tv_sec; 1691f8829a4aSRandall Stewart inp->sctp_ep.last_secret_number = 1692f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number; 1693f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number++; 1694f8829a4aSRandall Stewart if (inp->sctp_ep.current_secret_number >= 1695f8829a4aSRandall Stewart SCTP_HOW_MANY_SECRETS) { 1696f8829a4aSRandall Stewart inp->sctp_ep.current_secret_number = 0; 1697f8829a4aSRandall Stewart } 1698f8829a4aSRandall Stewart secret = (int)inp->sctp_ep.current_secret_number; 1699f8829a4aSRandall Stewart for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) { 1700f8829a4aSRandall Stewart inp->sctp_ep.secret_key[secret][i] = 1701f8829a4aSRandall Stewart sctp_select_initial_TSN(&inp->sctp_ep); 1702f8829a4aSRandall Stewart } 1703f8829a4aSRandall Stewart SCTP_INP_WUNLOCK(inp); 1704f8829a4aSRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, stcb, net); 1705f8829a4aSRandall Stewart } 1706f8829a4aSRandall Stewart did_output = 0; 1707f8829a4aSRandall Stewart break; 1708f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 1709ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1710ad81507eSRandall Stewart break; 1711ad81507eSRandall Stewart } 1712f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timopathmtu); 1713f8829a4aSRandall Stewart sctp_pathmtu_timer(inp, stcb, net); 1714f8829a4aSRandall Stewart did_output = 0; 1715f8829a4aSRandall Stewart break; 1716f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 1717ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1718ad81507eSRandall Stewart break; 1719ad81507eSRandall Stewart } 1720f8829a4aSRandall Stewart if (sctp_shutdownack_timer(inp, stcb, net)) { 1721f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1722f8829a4aSRandall Stewart goto out_decr; 1723f8829a4aSRandall Stewart } 1724f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownack); 1725f42a358aSRandall Stewart stcb->asoc.timoshutdownack++; 1726f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1727f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1728f8829a4aSRandall Stewart #endif 1729ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED); 1730f8829a4aSRandall Stewart break; 1731f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 1732ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1733ad81507eSRandall Stewart break; 1734ad81507eSRandall Stewart } 1735f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoshutdownguard); 1736f8829a4aSRandall Stewart sctp_abort_an_association(inp, stcb, 1737ceaad40aSRandall Stewart SCTP_SHUTDOWN_GUARD_EXPIRES, NULL, SCTP_SO_NOT_LOCKED); 1738f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1739f8829a4aSRandall Stewart goto out_decr; 1740f8829a4aSRandall Stewart 1741f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 1742ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1743ad81507eSRandall Stewart break; 1744ad81507eSRandall Stewart } 1745f8829a4aSRandall Stewart if (sctp_strreset_timer(inp, stcb, net)) { 1746f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1747f8829a4aSRandall Stewart goto out_decr; 1748f8829a4aSRandall Stewart } 1749f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timostrmrst); 1750ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED); 1751f8829a4aSRandall Stewart break; 1752f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 1753ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1754ad81507eSRandall Stewart break; 1755ad81507eSRandall Stewart } 1756f8829a4aSRandall Stewart if (sctp_asconf_timer(inp, stcb, net)) { 1757f8829a4aSRandall Stewart /* no need to unlock on tcb its gone */ 1758f8829a4aSRandall Stewart goto out_decr; 1759f8829a4aSRandall Stewart } 1760f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoasconf); 1761f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1762f8829a4aSRandall Stewart sctp_auditing(4, inp, stcb, net); 1763f8829a4aSRandall Stewart #endif 1764ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED); 1765f8829a4aSRandall Stewart break; 1766851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 1767851b7298SRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1768851b7298SRandall Stewart break; 1769851b7298SRandall Stewart } 177004ee05e8SRandall Stewart sctp_delete_prim_timer(inp, stcb, net); 1771851b7298SRandall Stewart SCTP_STAT_INCR(sctps_timodelprim); 1772851b7298SRandall Stewart break; 1773f8829a4aSRandall Stewart 1774f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 1775ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1776ad81507eSRandall Stewart break; 1777ad81507eSRandall Stewart } 1778f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoautoclose); 1779f8829a4aSRandall Stewart sctp_autoclose_timer(inp, stcb, net); 1780ceaad40aSRandall Stewart sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); 1781f8829a4aSRandall Stewart did_output = 0; 1782f8829a4aSRandall Stewart break; 1783f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 1784ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 1785ad81507eSRandall Stewart break; 1786ad81507eSRandall Stewart } 1787f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoassockill); 1788f8829a4aSRandall Stewart /* Can we free it yet? */ 1789f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1790a5d547adSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1); 1791ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1792ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 1793ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 1794ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1795ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 1796ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 1797ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 1798ceaad40aSRandall Stewart #endif 1799c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_2); 1800ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 1801ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 1802ceaad40aSRandall Stewart #endif 1803f8829a4aSRandall Stewart /* 1804f8829a4aSRandall Stewart * free asoc, always unlocks (or destroy's) so prevent 1805f8829a4aSRandall Stewart * duplicate unlock or unlock of a free mtx :-0 1806f8829a4aSRandall Stewart */ 1807f8829a4aSRandall Stewart stcb = NULL; 1808f8829a4aSRandall Stewart goto out_no_decr; 1809f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 1810f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_timoinpkill); 1811ad81507eSRandall Stewart if (inp == NULL) { 1812ad81507eSRandall Stewart break; 1813ad81507eSRandall Stewart } 1814f8829a4aSRandall Stewart /* 1815f8829a4aSRandall Stewart * special case, take away our increment since WE are the 1816f8829a4aSRandall Stewart * killer 1817f8829a4aSRandall Stewart */ 1818f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1819a5d547adSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_3); 1820b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 18210c7dc840SRandall Stewart SCTP_CALLED_FROM_INPKILL_TIMER); 1822d61374e1SRandall Stewart inp = NULL; 1823f8829a4aSRandall Stewart goto out_no_decr; 1824f8829a4aSRandall Stewart default: 1825ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "sctp_timeout_handler:unknown timer %d\n", 1826f8829a4aSRandall Stewart tmr->type); 1827f8829a4aSRandall Stewart break; 1828f8829a4aSRandall Stewart }; 1829f8829a4aSRandall Stewart #ifdef SCTP_AUDITING_ENABLED 1830f8829a4aSRandall Stewart sctp_audit_log(0xF1, (uint8_t) tmr->type); 1831f8829a4aSRandall Stewart if (inp) 1832f8829a4aSRandall Stewart sctp_auditing(5, inp, stcb, net); 1833f8829a4aSRandall Stewart #endif 1834f8829a4aSRandall Stewart if ((did_output) && stcb) { 1835f8829a4aSRandall Stewart /* 1836f8829a4aSRandall Stewart * Now we need to clean up the control chunk chain if an 1837f8829a4aSRandall Stewart * ECNE is on it. It must be marked as UNSENT again so next 1838f8829a4aSRandall Stewart * call will continue to send it until such time that we get 1839f8829a4aSRandall Stewart * a CWR, to remove it. It is, however, less likely that we 1840f8829a4aSRandall Stewart * will find a ecn echo on the chain though. 1841f8829a4aSRandall Stewart */ 1842f8829a4aSRandall Stewart sctp_fix_ecn_echo(&stcb->asoc); 1843f8829a4aSRandall Stewart } 184444b7479bSRandall Stewart get_out: 1845f8829a4aSRandall Stewart if (stcb) { 1846f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 1847f8829a4aSRandall Stewart } 1848f8829a4aSRandall Stewart out_decr: 1849f8829a4aSRandall Stewart if (inp) { 1850f8829a4aSRandall Stewart SCTP_INP_DECR_REF(inp); 1851f8829a4aSRandall Stewart } 1852f8829a4aSRandall Stewart out_no_decr: 1853ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "Timer now complete (type %d)\n", 1854d61374e1SRandall Stewart type); 18558518270eSMichael Tuexen CURVNET_RESTORE(); 1856f8829a4aSRandall Stewart } 1857f8829a4aSRandall Stewart 1858ad81507eSRandall Stewart void 1859f8829a4aSRandall Stewart sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 1860f8829a4aSRandall Stewart struct sctp_nets *net) 1861f8829a4aSRandall Stewart { 1862ca85e948SMichael Tuexen uint32_t to_ticks; 1863f8829a4aSRandall Stewart struct sctp_timer *tmr; 1864f8829a4aSRandall Stewart 1865139bc87fSRandall Stewart if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && (inp == NULL)) 1866ad81507eSRandall Stewart return; 1867f8829a4aSRandall Stewart 1868f8829a4aSRandall Stewart to_ticks = 0; 1869f8829a4aSRandall Stewart 1870f8829a4aSRandall Stewart tmr = NULL; 1871f8829a4aSRandall Stewart if (stcb) { 1872f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 1873f8829a4aSRandall Stewart } 1874f8829a4aSRandall Stewart switch (t_type) { 1875d61a0ae0SRandall Stewart case SCTP_TIMER_TYPE_ZERO_COPY: 1876d61a0ae0SRandall Stewart tmr = &inp->sctp_ep.zero_copy_timer; 1877d61a0ae0SRandall Stewart to_ticks = SCTP_ZERO_COPY_TICK_DELAY; 1878d61a0ae0SRandall Stewart break; 1879ad21a364SRandall Stewart case SCTP_TIMER_TYPE_ZCOPY_SENDQ: 1880ad21a364SRandall Stewart tmr = &inp->sctp_ep.zero_copy_sendq_timer; 1881ad21a364SRandall Stewart to_ticks = SCTP_ZERO_COPY_SENDQ_TICK_DELAY; 1882ad21a364SRandall Stewart break; 1883f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 1884f8829a4aSRandall Stewart /* Only 1 tick away :-) */ 1885b3f1ea41SRandall Stewart tmr = &SCTP_BASE_INFO(addr_wq_timer); 188642551e99SRandall Stewart to_ticks = SCTP_ADDRESS_TICK_DELAY; 1887f8829a4aSRandall Stewart break; 1888f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 1889f8829a4aSRandall Stewart /* Here we use the RTO timer */ 1890f8829a4aSRandall Stewart { 1891f8829a4aSRandall Stewart int rto_val; 1892f8829a4aSRandall Stewart 1893f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1894ad81507eSRandall Stewart return; 1895f8829a4aSRandall Stewart } 1896f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1897f8829a4aSRandall Stewart if (net->RTO == 0) { 1898f8829a4aSRandall Stewart rto_val = stcb->asoc.initial_rto; 1899f8829a4aSRandall Stewart } else { 1900f8829a4aSRandall Stewart rto_val = net->RTO; 1901f8829a4aSRandall Stewart } 1902f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(rto_val); 1903f8829a4aSRandall Stewart } 1904f8829a4aSRandall Stewart break; 1905f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 1906f8829a4aSRandall Stewart /* 1907f8829a4aSRandall Stewart * Here we use the INIT timer default usually about 1 1908f8829a4aSRandall Stewart * minute. 1909f8829a4aSRandall Stewart */ 1910f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1911ad81507eSRandall Stewart return; 1912f8829a4aSRandall Stewart } 1913f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1914f8829a4aSRandall Stewart if (net->RTO == 0) { 1915f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 1916f8829a4aSRandall Stewart } else { 1917f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 1918f8829a4aSRandall Stewart } 1919f8829a4aSRandall Stewart break; 1920f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 1921f8829a4aSRandall Stewart /* 1922f8829a4aSRandall Stewart * Here we use the Delayed-Ack timer value from the inp 1923f8829a4aSRandall Stewart * ususually about 200ms. 1924f8829a4aSRandall Stewart */ 1925f8829a4aSRandall Stewart if (stcb == NULL) { 1926ad81507eSRandall Stewart return; 1927f8829a4aSRandall Stewart } 1928f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 1929f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.delayed_ack); 1930f8829a4aSRandall Stewart break; 1931f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 1932f8829a4aSRandall Stewart /* Here we use the RTO of the destination. */ 1933f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1934ad81507eSRandall Stewart return; 1935f8829a4aSRandall Stewart } 1936f8829a4aSRandall Stewart if (net->RTO == 0) { 1937f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 1938f8829a4aSRandall Stewart } else { 1939f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 1940f8829a4aSRandall Stewart } 1941f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1942f8829a4aSRandall Stewart break; 1943f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 1944f8829a4aSRandall Stewart /* 1945f8829a4aSRandall Stewart * the net is used here so that we can add in the RTO. Even 1946f8829a4aSRandall Stewart * though we use a different timer. We also add the HB timer 1947f8829a4aSRandall Stewart * PLUS a random jitter. 1948f8829a4aSRandall Stewart */ 1949ca85e948SMichael Tuexen if ((inp == NULL) || (stcb == NULL) || (net == NULL)) { 1950ad81507eSRandall Stewart return; 1951ad81507eSRandall Stewart } else { 1952f8829a4aSRandall Stewart uint32_t rndval; 1953ca85e948SMichael Tuexen uint32_t jitter; 1954f8829a4aSRandall Stewart 1955ca85e948SMichael Tuexen if ((net->dest_state & SCTP_ADDR_NOHB) && 1956ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { 1957ad81507eSRandall Stewart return; 1958f8829a4aSRandall Stewart } 1959f8829a4aSRandall Stewart if (net->RTO == 0) { 1960ca85e948SMichael Tuexen to_ticks = stcb->asoc.initial_rto; 1961f8829a4aSRandall Stewart } else { 1962ca85e948SMichael Tuexen to_ticks = net->RTO; 1963f8829a4aSRandall Stewart } 1964ca85e948SMichael Tuexen rndval = sctp_select_initial_TSN(&inp->sctp_ep); 1965ca85e948SMichael Tuexen jitter = rndval % to_ticks; 1966ca85e948SMichael Tuexen if (jitter >= (to_ticks >> 1)) { 1967ca85e948SMichael Tuexen to_ticks = to_ticks + (jitter - (to_ticks >> 1)); 1968f8829a4aSRandall Stewart } else { 1969ca85e948SMichael Tuexen to_ticks = to_ticks - jitter; 1970f8829a4aSRandall Stewart } 1971ca85e948SMichael Tuexen if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && 1972ca85e948SMichael Tuexen !(net->dest_state & SCTP_ADDR_PF)) { 1973ca85e948SMichael Tuexen to_ticks += net->heart_beat_delay; 1974f8829a4aSRandall Stewart } 1975f8829a4aSRandall Stewart /* 1976f8829a4aSRandall Stewart * Now we must convert the to_ticks that are now in 1977f8829a4aSRandall Stewart * ms to ticks. 1978f8829a4aSRandall Stewart */ 1979f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(to_ticks); 1980ca85e948SMichael Tuexen tmr = &net->hb_timer; 1981f8829a4aSRandall Stewart } 1982f8829a4aSRandall Stewart break; 1983f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 1984f8829a4aSRandall Stewart /* 1985f8829a4aSRandall Stewart * Here we can use the RTO timer from the network since one 1986f8829a4aSRandall Stewart * RTT was compelete. If a retran happened then we will be 1987f8829a4aSRandall Stewart * using the RTO initial value. 1988f8829a4aSRandall Stewart */ 1989f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 1990ad81507eSRandall Stewart return; 1991f8829a4aSRandall Stewart } 1992f8829a4aSRandall Stewart if (net->RTO == 0) { 1993f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 1994f8829a4aSRandall Stewart } else { 1995f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 1996f8829a4aSRandall Stewart } 1997f8829a4aSRandall Stewart tmr = &net->rxt_timer; 1998f8829a4aSRandall Stewart break; 1999f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2000f8829a4aSRandall Stewart /* 2001f8829a4aSRandall Stewart * nothing needed but the endpoint here ususually about 60 2002f8829a4aSRandall Stewart * minutes. 2003f8829a4aSRandall Stewart */ 2004ad81507eSRandall Stewart if (inp == NULL) { 2005ad81507eSRandall Stewart return; 2006ad81507eSRandall Stewart } 2007f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2008f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_SIGNATURE]; 2009f8829a4aSRandall Stewart break; 2010f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 2011f8829a4aSRandall Stewart if (stcb == NULL) { 2012ad81507eSRandall Stewart return; 2013f8829a4aSRandall Stewart } 2014f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2015f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(SCTP_ASOC_KILL_TIMEOUT); 2016f8829a4aSRandall Stewart break; 2017f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 2018f8829a4aSRandall Stewart /* 2019f8829a4aSRandall Stewart * The inp is setup to die. We re-use the signature_chage 2020f8829a4aSRandall Stewart * timer since that has stopped and we are in the GONE 2021f8829a4aSRandall Stewart * state. 2022f8829a4aSRandall Stewart */ 2023ad81507eSRandall Stewart if (inp == NULL) { 2024ad81507eSRandall Stewart return; 2025ad81507eSRandall Stewart } 2026f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2027f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(SCTP_INP_KILL_TIMEOUT); 2028f8829a4aSRandall Stewart break; 2029f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2030f8829a4aSRandall Stewart /* 2031f8829a4aSRandall Stewart * Here we use the value found in the EP for PMTU ususually 2032f8829a4aSRandall Stewart * about 10 minutes. 2033f8829a4aSRandall Stewart */ 2034ad81507eSRandall Stewart if ((stcb == NULL) || (inp == NULL)) { 2035ad81507eSRandall Stewart return; 2036f8829a4aSRandall Stewart } 2037f8829a4aSRandall Stewart if (net == NULL) { 2038ad81507eSRandall Stewart return; 2039f8829a4aSRandall Stewart } 204080c79bbeSMichael Tuexen if (net->dest_state & SCTP_ADDR_NO_PMTUD) { 204180c79bbeSMichael Tuexen return; 204280c79bbeSMichael Tuexen } 2043f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_PMTU]; 2044f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2045f8829a4aSRandall Stewart break; 2046f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2047f8829a4aSRandall Stewart /* Here we use the RTO of the destination */ 2048f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2049ad81507eSRandall Stewart return; 2050f8829a4aSRandall Stewart } 2051f8829a4aSRandall Stewart if (net->RTO == 0) { 2052f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2053f8829a4aSRandall Stewart } else { 2054f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2055f8829a4aSRandall Stewart } 2056f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2057f8829a4aSRandall Stewart break; 2058f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2059f8829a4aSRandall Stewart /* 2060f8829a4aSRandall Stewart * Here we use the endpoints shutdown guard timer usually 2061f8829a4aSRandall Stewart * about 3 minutes. 2062f8829a4aSRandall Stewart */ 2063ad81507eSRandall Stewart if ((inp == NULL) || (stcb == NULL)) { 2064ad81507eSRandall Stewart return; 2065f8829a4aSRandall Stewart } 2066f8829a4aSRandall Stewart to_ticks = inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_MAXSHUTDOWN]; 2067f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2068f8829a4aSRandall Stewart break; 2069f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2070f8829a4aSRandall Stewart /* 20711b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 20721b649582SRandall Stewart * the net's RTO. 2073f8829a4aSRandall Stewart */ 2074f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2075ad81507eSRandall Stewart return; 2076f8829a4aSRandall Stewart } 2077f8829a4aSRandall Stewart if (net->RTO == 0) { 2078f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2079f8829a4aSRandall Stewart } else { 2080f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2081f8829a4aSRandall Stewart } 2082f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2083f8829a4aSRandall Stewart break; 2084f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 2085f8829a4aSRandall Stewart /* 20861b649582SRandall Stewart * Here the timer comes from the stcb but its value is from 20871b649582SRandall Stewart * the net's RTO. 2088f8829a4aSRandall Stewart */ 2089f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 2090ad81507eSRandall Stewart return; 2091f8829a4aSRandall Stewart } 2092f8829a4aSRandall Stewart if (net->RTO == 0) { 2093f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2094f8829a4aSRandall Stewart } else { 2095f8829a4aSRandall Stewart to_ticks = MSEC_TO_TICKS(net->RTO); 2096f8829a4aSRandall Stewart } 2097f8829a4aSRandall Stewart tmr = &stcb->asoc.asconf_timer; 2098f8829a4aSRandall Stewart break; 2099851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2100851b7298SRandall Stewart if ((stcb == NULL) || (net != NULL)) { 2101851b7298SRandall Stewart return; 2102851b7298SRandall Stewart } 2103851b7298SRandall Stewart to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto); 2104851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2105851b7298SRandall Stewart break; 2106f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 2107f8829a4aSRandall Stewart if (stcb == NULL) { 2108ad81507eSRandall Stewart return; 2109f8829a4aSRandall Stewart } 2110f8829a4aSRandall Stewart if (stcb->asoc.sctp_autoclose_ticks == 0) { 2111f8829a4aSRandall Stewart /* 2112f8829a4aSRandall Stewart * Really an error since stcb is NOT set to 2113f8829a4aSRandall Stewart * autoclose 2114f8829a4aSRandall Stewart */ 2115ad81507eSRandall Stewart return; 2116f8829a4aSRandall Stewart } 2117f8829a4aSRandall Stewart to_ticks = stcb->asoc.sctp_autoclose_ticks; 2118f8829a4aSRandall Stewart tmr = &stcb->asoc.autoclose_timer; 2119f8829a4aSRandall Stewart break; 2120f8829a4aSRandall Stewart default: 2121ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n", 2122ad81507eSRandall Stewart __FUNCTION__, t_type); 2123ad81507eSRandall Stewart return; 2124f8829a4aSRandall Stewart break; 2125f8829a4aSRandall Stewart }; 2126f8829a4aSRandall Stewart if ((to_ticks <= 0) || (tmr == NULL)) { 2127ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: %d:software error to_ticks:%d tmr:%p not set ??\n", 2128ad81507eSRandall Stewart __FUNCTION__, t_type, to_ticks, tmr); 2129ad81507eSRandall Stewart return; 2130f8829a4aSRandall Stewart } 2131139bc87fSRandall Stewart if (SCTP_OS_TIMER_PENDING(&tmr->timer)) { 2132f8829a4aSRandall Stewart /* 2133f8829a4aSRandall Stewart * we do NOT allow you to have it already running. if it is 2134f8829a4aSRandall Stewart * we leave the current one up unchanged 2135f8829a4aSRandall Stewart */ 2136ad81507eSRandall Stewart return; 2137f8829a4aSRandall Stewart } 2138f8829a4aSRandall Stewart /* At this point we can proceed */ 2139f8829a4aSRandall Stewart if (t_type == SCTP_TIMER_TYPE_SEND) { 2140f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up++; 2141f8829a4aSRandall Stewart } 2142a5d547adSRandall Stewart tmr->stopped_from = 0; 2143f8829a4aSRandall Stewart tmr->type = t_type; 2144f8829a4aSRandall Stewart tmr->ep = (void *)inp; 2145f8829a4aSRandall Stewart tmr->tcb = (void *)stcb; 2146f8829a4aSRandall Stewart tmr->net = (void *)net; 2147f8829a4aSRandall Stewart tmr->self = (void *)tmr; 21488518270eSMichael Tuexen tmr->vnet = (void *)curvnet; 2149c4739e2fSRandall Stewart tmr->ticks = sctp_get_tick_count(); 2150ad81507eSRandall Stewart (void)SCTP_OS_TIMER_START(&tmr->timer, to_ticks, sctp_timeout_handler, tmr); 2151ad81507eSRandall Stewart return; 2152f8829a4aSRandall Stewart } 2153f8829a4aSRandall Stewart 21546e55db54SRandall Stewart void 2155f8829a4aSRandall Stewart sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, 2156a5d547adSRandall Stewart struct sctp_nets *net, uint32_t from) 2157f8829a4aSRandall Stewart { 2158f8829a4aSRandall Stewart struct sctp_timer *tmr; 2159f8829a4aSRandall Stewart 2160f8829a4aSRandall Stewart if ((t_type != SCTP_TIMER_TYPE_ADDR_WQ) && 2161f8829a4aSRandall Stewart (inp == NULL)) 21626e55db54SRandall Stewart return; 2163f8829a4aSRandall Stewart 2164f8829a4aSRandall Stewart tmr = NULL; 2165f8829a4aSRandall Stewart if (stcb) { 2166f8829a4aSRandall Stewart SCTP_TCB_LOCK_ASSERT(stcb); 2167f8829a4aSRandall Stewart } 2168f8829a4aSRandall Stewart switch (t_type) { 2169d61a0ae0SRandall Stewart case SCTP_TIMER_TYPE_ZERO_COPY: 2170d61a0ae0SRandall Stewart tmr = &inp->sctp_ep.zero_copy_timer; 2171d61a0ae0SRandall Stewart break; 2172ad21a364SRandall Stewart case SCTP_TIMER_TYPE_ZCOPY_SENDQ: 2173ad21a364SRandall Stewart tmr = &inp->sctp_ep.zero_copy_sendq_timer; 2174ad21a364SRandall Stewart break; 2175f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ADDR_WQ: 2176b3f1ea41SRandall Stewart tmr = &SCTP_BASE_INFO(addr_wq_timer); 2177f8829a4aSRandall Stewart break; 2178f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SEND: 2179f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21806e55db54SRandall Stewart return; 2181f8829a4aSRandall Stewart } 2182f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2183f8829a4aSRandall Stewart break; 2184f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INIT: 2185f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21866e55db54SRandall Stewart return; 2187f8829a4aSRandall Stewart } 2188f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2189f8829a4aSRandall Stewart break; 2190f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_RECV: 2191f8829a4aSRandall Stewart if (stcb == NULL) { 21926e55db54SRandall Stewart return; 2193f8829a4aSRandall Stewart } 2194f8829a4aSRandall Stewart tmr = &stcb->asoc.dack_timer; 2195f8829a4aSRandall Stewart break; 2196f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWN: 2197f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 21986e55db54SRandall Stewart return; 2199f8829a4aSRandall Stewart } 2200f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2201f8829a4aSRandall Stewart break; 2202f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_HEARTBEAT: 2203ca85e948SMichael Tuexen if ((stcb == NULL) || (net == NULL)) { 22046e55db54SRandall Stewart return; 2205f8829a4aSRandall Stewart } 2206ca85e948SMichael Tuexen tmr = &net->hb_timer; 2207f8829a4aSRandall Stewart break; 2208f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_COOKIE: 2209f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22106e55db54SRandall Stewart return; 2211f8829a4aSRandall Stewart } 2212f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2213f8829a4aSRandall Stewart break; 2214f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_NEWCOOKIE: 2215f8829a4aSRandall Stewart /* nothing needed but the endpoint here */ 2216f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2217f8829a4aSRandall Stewart /* 2218f8829a4aSRandall Stewart * We re-use the newcookie timer for the INP kill timer. We 2219f8829a4aSRandall Stewart * must assure that we do not kill it by accident. 2220f8829a4aSRandall Stewart */ 2221f8829a4aSRandall Stewart break; 2222f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASOCKILL: 2223f8829a4aSRandall Stewart /* 2224f8829a4aSRandall Stewart * Stop the asoc kill timer. 2225f8829a4aSRandall Stewart */ 2226f8829a4aSRandall Stewart if (stcb == NULL) { 22276e55db54SRandall Stewart return; 2228f8829a4aSRandall Stewart } 2229f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2230f8829a4aSRandall Stewart break; 2231f8829a4aSRandall Stewart 2232f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_INPKILL: 2233f8829a4aSRandall Stewart /* 2234f8829a4aSRandall Stewart * The inp is setup to die. We re-use the signature_chage 2235f8829a4aSRandall Stewart * timer since that has stopped and we are in the GONE 2236f8829a4aSRandall Stewart * state. 2237f8829a4aSRandall Stewart */ 2238f8829a4aSRandall Stewart tmr = &inp->sctp_ep.signature_change; 2239f8829a4aSRandall Stewart break; 2240f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_PATHMTURAISE: 2241f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22426e55db54SRandall Stewart return; 2243f8829a4aSRandall Stewart } 2244f8829a4aSRandall Stewart tmr = &net->pmtu_timer; 2245f8829a4aSRandall Stewart break; 2246f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNACK: 2247f8829a4aSRandall Stewart if ((stcb == NULL) || (net == NULL)) { 22486e55db54SRandall Stewart return; 2249f8829a4aSRandall Stewart } 2250f8829a4aSRandall Stewart tmr = &net->rxt_timer; 2251f8829a4aSRandall Stewart break; 2252f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_SHUTDOWNGUARD: 2253f8829a4aSRandall Stewart if (stcb == NULL) { 22546e55db54SRandall Stewart return; 2255f8829a4aSRandall Stewart } 2256f8829a4aSRandall Stewart tmr = &stcb->asoc.shut_guard_timer; 2257f8829a4aSRandall Stewart break; 2258f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_STRRESET: 2259f8829a4aSRandall Stewart if (stcb == NULL) { 22606e55db54SRandall Stewart return; 2261f8829a4aSRandall Stewart } 2262f8829a4aSRandall Stewart tmr = &stcb->asoc.strreset_timer; 2263f8829a4aSRandall Stewart break; 2264f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_ASCONF: 2265f8829a4aSRandall Stewart if (stcb == NULL) { 22666e55db54SRandall Stewart return; 2267f8829a4aSRandall Stewart } 2268f8829a4aSRandall Stewart tmr = &stcb->asoc.asconf_timer; 2269f8829a4aSRandall Stewart break; 2270851b7298SRandall Stewart case SCTP_TIMER_TYPE_PRIM_DELETED: 2271851b7298SRandall Stewart if (stcb == NULL) { 2272851b7298SRandall Stewart return; 2273851b7298SRandall Stewart } 2274851b7298SRandall Stewart tmr = &stcb->asoc.delete_prim_timer; 2275851b7298SRandall Stewart break; 2276f8829a4aSRandall Stewart case SCTP_TIMER_TYPE_AUTOCLOSE: 2277f8829a4aSRandall Stewart if (stcb == NULL) { 22786e55db54SRandall Stewart return; 2279f8829a4aSRandall Stewart } 2280f8829a4aSRandall Stewart tmr = &stcb->asoc.autoclose_timer; 2281f8829a4aSRandall Stewart break; 2282f8829a4aSRandall Stewart default: 2283ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_TIMER1, "%s: Unknown timer type %d\n", 2284ad81507eSRandall Stewart __FUNCTION__, t_type); 2285f8829a4aSRandall Stewart break; 2286f8829a4aSRandall Stewart }; 2287f8829a4aSRandall Stewart if (tmr == NULL) { 22886e55db54SRandall Stewart return; 2289f8829a4aSRandall Stewart } 2290f8829a4aSRandall Stewart if ((tmr->type != t_type) && tmr->type) { 2291f8829a4aSRandall Stewart /* 2292f8829a4aSRandall Stewart * Ok we have a timer that is under joint use. Cookie timer 2293f8829a4aSRandall Stewart * per chance with the SEND timer. We therefore are NOT 2294f8829a4aSRandall Stewart * running the timer that the caller wants stopped. So just 2295f8829a4aSRandall Stewart * return. 2296f8829a4aSRandall Stewart */ 22976e55db54SRandall Stewart return; 2298f8829a4aSRandall Stewart } 2299ad81507eSRandall Stewart if ((t_type == SCTP_TIMER_TYPE_SEND) && (stcb != NULL)) { 2300f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up--; 2301f8829a4aSRandall Stewart if (stcb->asoc.num_send_timers_up < 0) { 2302f8829a4aSRandall Stewart stcb->asoc.num_send_timers_up = 0; 2303f8829a4aSRandall Stewart } 2304f8829a4aSRandall Stewart } 2305f8829a4aSRandall Stewart tmr->self = NULL; 2306a5d547adSRandall Stewart tmr->stopped_from = from; 23076e55db54SRandall Stewart (void)SCTP_OS_TIMER_STOP(&tmr->timer); 23086e55db54SRandall Stewart return; 2309f8829a4aSRandall Stewart } 2310f8829a4aSRandall Stewart 2311f8829a4aSRandall Stewart uint32_t 2312f8829a4aSRandall Stewart sctp_calculate_len(struct mbuf *m) 2313f8829a4aSRandall Stewart { 2314f8829a4aSRandall Stewart uint32_t tlen = 0; 2315f8829a4aSRandall Stewart struct mbuf *at; 2316f8829a4aSRandall Stewart 2317f8829a4aSRandall Stewart at = m; 2318f8829a4aSRandall Stewart while (at) { 2319139bc87fSRandall Stewart tlen += SCTP_BUF_LEN(at); 2320139bc87fSRandall Stewart at = SCTP_BUF_NEXT(at); 2321f8829a4aSRandall Stewart } 2322f8829a4aSRandall Stewart return (tlen); 2323f8829a4aSRandall Stewart } 2324f8829a4aSRandall Stewart 2325f8829a4aSRandall Stewart void 2326f8829a4aSRandall Stewart sctp_mtu_size_reset(struct sctp_inpcb *inp, 232744b7479bSRandall Stewart struct sctp_association *asoc, uint32_t mtu) 2328f8829a4aSRandall Stewart { 2329f8829a4aSRandall Stewart /* 2330f8829a4aSRandall Stewart * Reset the P-MTU size on this association, this involves changing 2331f8829a4aSRandall Stewart * the asoc MTU, going through ANY chunk+overhead larger than mtu to 2332f8829a4aSRandall Stewart * allow the DF flag to be cleared. 2333f8829a4aSRandall Stewart */ 2334f8829a4aSRandall Stewart struct sctp_tmit_chunk *chk; 2335f8829a4aSRandall Stewart unsigned int eff_mtu, ovh; 2336f8829a4aSRandall Stewart 2337f8829a4aSRandall Stewart asoc->smallest_mtu = mtu; 2338f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 2339f8829a4aSRandall Stewart ovh = SCTP_MIN_OVERHEAD; 2340f8829a4aSRandall Stewart } else { 2341f8829a4aSRandall Stewart ovh = SCTP_MIN_V4_OVERHEAD; 2342f8829a4aSRandall Stewart } 2343f8829a4aSRandall Stewart eff_mtu = mtu - ovh; 2344f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { 2345f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2346f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2347f8829a4aSRandall Stewart } 2348f8829a4aSRandall Stewart } 2349f8829a4aSRandall Stewart TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { 2350f8829a4aSRandall Stewart if (chk->send_size > eff_mtu) { 2351f8829a4aSRandall Stewart chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; 2352f8829a4aSRandall Stewart } 2353f8829a4aSRandall Stewart } 2354f8829a4aSRandall Stewart } 2355f8829a4aSRandall Stewart 2356f8829a4aSRandall Stewart 2357f8829a4aSRandall Stewart /* 2358f8829a4aSRandall Stewart * given an association and starting time of the current RTT period return 2359f42a358aSRandall Stewart * RTO in number of msecs net should point to the current network 2360f8829a4aSRandall Stewart */ 2361899288aeSRandall Stewart 2362f8829a4aSRandall Stewart uint32_t 2363f8829a4aSRandall Stewart sctp_calculate_rto(struct sctp_tcb *stcb, 2364f8829a4aSRandall Stewart struct sctp_association *asoc, 2365f8829a4aSRandall Stewart struct sctp_nets *net, 236618e198d3SRandall Stewart struct timeval *told, 2367f79aab18SRandall Stewart int safe, int rtt_from_sack) 2368f8829a4aSRandall Stewart { 236918e198d3SRandall Stewart /*- 2370f8829a4aSRandall Stewart * given an association and the starting time of the current RTT 2371f42a358aSRandall Stewart * period (in value1/value2) return RTO in number of msecs. 2372f8829a4aSRandall Stewart */ 2373be1d9176SMichael Tuexen int32_t rtt; /* RTT in ms */ 2374be1d9176SMichael Tuexen uint32_t new_rto; 2375f8829a4aSRandall Stewart int first_measure = 0; 237618e198d3SRandall Stewart struct timeval now, then, *old; 2377f8829a4aSRandall Stewart 237818e198d3SRandall Stewart /* Copy it out for sparc64 */ 237918e198d3SRandall Stewart if (safe == sctp_align_unsafe_makecopy) { 238018e198d3SRandall Stewart old = &then; 238118e198d3SRandall Stewart memcpy(&then, told, sizeof(struct timeval)); 238218e198d3SRandall Stewart } else if (safe == sctp_align_safe_nocopy) { 238318e198d3SRandall Stewart old = told; 238418e198d3SRandall Stewart } else { 238518e198d3SRandall Stewart /* error */ 238618e198d3SRandall Stewart SCTP_PRINTF("Huh, bad rto calc call\n"); 238718e198d3SRandall Stewart return (0); 238818e198d3SRandall Stewart } 2389f8829a4aSRandall Stewart /************************/ 2390f8829a4aSRandall Stewart /* 1. calculate new RTT */ 2391f8829a4aSRandall Stewart /************************/ 2392f8829a4aSRandall Stewart /* get the current time */ 2393299108c5SRandall Stewart if (stcb->asoc.use_precise_time) { 2394299108c5SRandall Stewart (void)SCTP_GETPTIME_TIMEVAL(&now); 2395299108c5SRandall Stewart } else { 23966e55db54SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&now); 2397299108c5SRandall Stewart } 2398be1d9176SMichael Tuexen timevalsub(&now, old); 2399be1d9176SMichael Tuexen /* store the current RTT in us */ 2400be1d9176SMichael Tuexen net->rtt = (uint64_t) 10000000 *(uint64_t) now.tv_sec + 2401be1d9176SMichael Tuexen (uint64_t) now.tv_usec; 2402be1d9176SMichael Tuexen 2403be1d9176SMichael Tuexen /* computer rtt in ms */ 2404be1d9176SMichael Tuexen rtt = net->rtt / 1000; 2405f79aab18SRandall Stewart if ((asoc->cc_functions.sctp_rtt_calculated) && (rtt_from_sack == SCTP_RTT_FROM_DATA)) { 2406f79aab18SRandall Stewart /* 2407f79aab18SRandall Stewart * Tell the CC module that a new update has just occurred 2408f79aab18SRandall Stewart * from a sack 2409f79aab18SRandall Stewart */ 2410f79aab18SRandall Stewart (*asoc->cc_functions.sctp_rtt_calculated) (stcb, net, &now); 2411f79aab18SRandall Stewart } 2412f79aab18SRandall Stewart /* 2413f79aab18SRandall Stewart * Do we need to determine the lan? We do this only on sacks i.e. 2414f79aab18SRandall Stewart * RTT being determined from data not non-data (HB/INIT->INITACK). 2415f79aab18SRandall Stewart */ 2416f79aab18SRandall Stewart if ((rtt_from_sack == SCTP_RTT_FROM_DATA) && 2417be1d9176SMichael Tuexen (net->lan_type == SCTP_LAN_UNKNOWN)) { 2418be1d9176SMichael Tuexen if (net->rtt > SCTP_LOCAL_LAN_RTT) { 2419899288aeSRandall Stewart net->lan_type = SCTP_LAN_INTERNET; 2420899288aeSRandall Stewart } else { 2421899288aeSRandall Stewart net->lan_type = SCTP_LAN_LOCAL; 2422899288aeSRandall Stewart } 2423899288aeSRandall Stewart } 2424f8829a4aSRandall Stewart /***************************/ 2425f8829a4aSRandall Stewart /* 2. update RTTVAR & SRTT */ 2426f8829a4aSRandall Stewart /***************************/ 2427be1d9176SMichael Tuexen /*- 2428be1d9176SMichael Tuexen * Compute the scaled average lastsa and the 2429be1d9176SMichael Tuexen * scaled variance lastsv as described in van Jacobson 2430be1d9176SMichael Tuexen * Paper "Congestion Avoidance and Control", Annex A. 2431be1d9176SMichael Tuexen * 2432be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_SHIFT) is the srtt 2433be1d9176SMichael Tuexen * (net->lastsa >> SCTP_RTT_VAR_SHIFT) is the rttvar 2434be1d9176SMichael Tuexen */ 24359a972525SRandall Stewart if (net->RTO_measured) { 2436be1d9176SMichael Tuexen rtt -= (net->lastsa >> SCTP_RTT_SHIFT); 2437be1d9176SMichael Tuexen net->lastsa += rtt; 2438be1d9176SMichael Tuexen if (rtt < 0) { 2439be1d9176SMichael Tuexen rtt = -rtt; 2440be1d9176SMichael Tuexen } 2441be1d9176SMichael Tuexen rtt -= (net->lastsv >> SCTP_RTT_VAR_SHIFT); 2442be1d9176SMichael Tuexen net->lastsv += rtt; 2443b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2444f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_RTTVAR); 244580fefe0aSRandall Stewart } 2446f8829a4aSRandall Stewart } else { 2447f8829a4aSRandall Stewart /* First RTO measurment */ 24489a972525SRandall Stewart net->RTO_measured = 1; 2449f8829a4aSRandall Stewart first_measure = 1; 2450be1d9176SMichael Tuexen net->lastsa = rtt << SCTP_RTT_SHIFT; 2451be1d9176SMichael Tuexen net->lastsv = (rtt / 2) << SCTP_RTT_VAR_SHIFT; 2452b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RTTVAR_LOGGING_ENABLE) { 2453f8829a4aSRandall Stewart rto_logging(net, SCTP_LOG_INITIAL_RTT); 245480fefe0aSRandall Stewart } 2455f8829a4aSRandall Stewart } 2456be1d9176SMichael Tuexen if (net->lastsv == 0) { 2457be1d9176SMichael Tuexen net->lastsv = SCTP_CLOCK_GRANULARITY; 2458be1d9176SMichael Tuexen } 2459108df27cSRandall Stewart new_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; 2460f8829a4aSRandall Stewart if ((new_rto > SCTP_SAT_NETWORK_MIN) && 2461f8829a4aSRandall Stewart (stcb->asoc.sat_network_lockout == 0)) { 2462f8829a4aSRandall Stewart stcb->asoc.sat_network = 1; 2463f8829a4aSRandall Stewart } else if ((!first_measure) && stcb->asoc.sat_network) { 2464f8829a4aSRandall Stewart stcb->asoc.sat_network = 0; 2465f8829a4aSRandall Stewart stcb->asoc.sat_network_lockout = 1; 2466f8829a4aSRandall Stewart } 2467f8829a4aSRandall Stewart /* bound it, per C6/C7 in Section 5.3.1 */ 2468f8829a4aSRandall Stewart if (new_rto < stcb->asoc.minrto) { 2469f8829a4aSRandall Stewart new_rto = stcb->asoc.minrto; 2470f8829a4aSRandall Stewart } 2471f8829a4aSRandall Stewart if (new_rto > stcb->asoc.maxrto) { 2472f8829a4aSRandall Stewart new_rto = stcb->asoc.maxrto; 2473f8829a4aSRandall Stewart } 24745e54f665SRandall Stewart /* we are now returning the RTO */ 24755e54f665SRandall Stewart return (new_rto); 2476f8829a4aSRandall Stewart } 2477f8829a4aSRandall Stewart 2478f8829a4aSRandall Stewart /* 2479f8829a4aSRandall Stewart * return a pointer to a contiguous piece of data from the given mbuf chain 2480f8829a4aSRandall Stewart * starting at 'off' for 'len' bytes. If the desired piece spans more than 2481f8829a4aSRandall Stewart * one mbuf, a copy is made at 'ptr'. caller must ensure that the buffer size 2482f8829a4aSRandall Stewart * is >= 'len' returns NULL if there there isn't 'len' bytes in the chain. 2483f8829a4aSRandall Stewart */ 248472fb6fdbSRandall Stewart caddr_t 2485f8829a4aSRandall Stewart sctp_m_getptr(struct mbuf *m, int off, int len, uint8_t * in_ptr) 2486f8829a4aSRandall Stewart { 2487f8829a4aSRandall Stewart uint32_t count; 2488f8829a4aSRandall Stewart uint8_t *ptr; 2489f8829a4aSRandall Stewart 2490f8829a4aSRandall Stewart ptr = in_ptr; 2491f8829a4aSRandall Stewart if ((off < 0) || (len <= 0)) 2492f8829a4aSRandall Stewart return (NULL); 2493f8829a4aSRandall Stewart 2494f8829a4aSRandall Stewart /* find the desired start location */ 2495f8829a4aSRandall Stewart while ((m != NULL) && (off > 0)) { 2496139bc87fSRandall Stewart if (off < SCTP_BUF_LEN(m)) 2497f8829a4aSRandall Stewart break; 2498139bc87fSRandall Stewart off -= SCTP_BUF_LEN(m); 2499139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2500f8829a4aSRandall Stewart } 2501f8829a4aSRandall Stewart if (m == NULL) 2502f8829a4aSRandall Stewart return (NULL); 2503f8829a4aSRandall Stewart 2504f8829a4aSRandall Stewart /* is the current mbuf large enough (eg. contiguous)? */ 2505139bc87fSRandall Stewart if ((SCTP_BUF_LEN(m) - off) >= len) { 2506f8829a4aSRandall Stewart return (mtod(m, caddr_t)+off); 2507f8829a4aSRandall Stewart } else { 2508f8829a4aSRandall Stewart /* else, it spans more than one mbuf, so save a temp copy... */ 2509f8829a4aSRandall Stewart while ((m != NULL) && (len > 0)) { 2510139bc87fSRandall Stewart count = min(SCTP_BUF_LEN(m) - off, len); 2511f8829a4aSRandall Stewart bcopy(mtod(m, caddr_t)+off, ptr, count); 2512f8829a4aSRandall Stewart len -= count; 2513f8829a4aSRandall Stewart ptr += count; 2514f8829a4aSRandall Stewart off = 0; 2515139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 2516f8829a4aSRandall Stewart } 2517f8829a4aSRandall Stewart if ((m == NULL) && (len > 0)) 2518f8829a4aSRandall Stewart return (NULL); 2519f8829a4aSRandall Stewart else 2520f8829a4aSRandall Stewart return ((caddr_t)in_ptr); 2521f8829a4aSRandall Stewart } 2522f8829a4aSRandall Stewart } 2523f8829a4aSRandall Stewart 2524f8829a4aSRandall Stewart 252544b7479bSRandall Stewart 2526f8829a4aSRandall Stewart struct sctp_paramhdr * 2527f8829a4aSRandall Stewart sctp_get_next_param(struct mbuf *m, 2528f8829a4aSRandall Stewart int offset, 2529f8829a4aSRandall Stewart struct sctp_paramhdr *pull, 2530f8829a4aSRandall Stewart int pull_limit) 2531f8829a4aSRandall Stewart { 2532f8829a4aSRandall Stewart /* This just provides a typed signature to Peter's Pull routine */ 2533f8829a4aSRandall Stewart return ((struct sctp_paramhdr *)sctp_m_getptr(m, offset, pull_limit, 2534f8829a4aSRandall Stewart (uint8_t *) pull)); 2535f8829a4aSRandall Stewart } 2536f8829a4aSRandall Stewart 2537f8829a4aSRandall Stewart 2538f8829a4aSRandall Stewart int 2539f8829a4aSRandall Stewart sctp_add_pad_tombuf(struct mbuf *m, int padlen) 2540f8829a4aSRandall Stewart { 2541f8829a4aSRandall Stewart /* 2542f8829a4aSRandall Stewart * add padlen bytes of 0 filled padding to the end of the mbuf. If 2543f8829a4aSRandall Stewart * padlen is > 3 this routine will fail. 2544f8829a4aSRandall Stewart */ 2545f8829a4aSRandall Stewart uint8_t *dp; 2546f8829a4aSRandall Stewart int i; 2547f8829a4aSRandall Stewart 2548f8829a4aSRandall Stewart if (padlen > 3) { 2549c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 2550f8829a4aSRandall Stewart return (ENOBUFS); 2551f8829a4aSRandall Stewart } 255241eee555SRandall Stewart if (padlen <= M_TRAILINGSPACE(m)) { 2553f8829a4aSRandall Stewart /* 2554f8829a4aSRandall Stewart * The easy way. We hope the majority of the time we hit 2555f8829a4aSRandall Stewart * here :) 2556f8829a4aSRandall Stewart */ 2557139bc87fSRandall Stewart dp = (uint8_t *) (mtod(m, caddr_t)+SCTP_BUF_LEN(m)); 2558139bc87fSRandall Stewart SCTP_BUF_LEN(m) += padlen; 2559f8829a4aSRandall Stewart } else { 2560f8829a4aSRandall Stewart /* Hard way we must grow the mbuf */ 2561f8829a4aSRandall Stewart struct mbuf *tmp; 2562f8829a4aSRandall Stewart 2563f8829a4aSRandall Stewart tmp = sctp_get_mbuf_for_msg(padlen, 0, M_DONTWAIT, 1, MT_DATA); 2564f8829a4aSRandall Stewart if (tmp == NULL) { 2565f8829a4aSRandall Stewart /* Out of space GAK! we are in big trouble. */ 2566c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 2567f8829a4aSRandall Stewart return (ENOSPC); 2568f8829a4aSRandall Stewart } 2569f8829a4aSRandall Stewart /* setup and insert in middle */ 2570139bc87fSRandall Stewart SCTP_BUF_LEN(tmp) = padlen; 257141eee555SRandall Stewart SCTP_BUF_NEXT(tmp) = NULL; 2572139bc87fSRandall Stewart SCTP_BUF_NEXT(m) = tmp; 2573f8829a4aSRandall Stewart dp = mtod(tmp, uint8_t *); 2574f8829a4aSRandall Stewart } 2575f8829a4aSRandall Stewart /* zero out the pad */ 2576f8829a4aSRandall Stewart for (i = 0; i < padlen; i++) { 2577f8829a4aSRandall Stewart *dp = 0; 2578f8829a4aSRandall Stewart dp++; 2579f8829a4aSRandall Stewart } 2580f8829a4aSRandall Stewart return (0); 2581f8829a4aSRandall Stewart } 2582f8829a4aSRandall Stewart 2583f8829a4aSRandall Stewart int 2584f8829a4aSRandall Stewart sctp_pad_lastmbuf(struct mbuf *m, int padval, struct mbuf *last_mbuf) 2585f8829a4aSRandall Stewart { 2586f8829a4aSRandall Stewart /* find the last mbuf in chain and pad it */ 2587f8829a4aSRandall Stewart struct mbuf *m_at; 2588f8829a4aSRandall Stewart 2589f8829a4aSRandall Stewart m_at = m; 2590f8829a4aSRandall Stewart if (last_mbuf) { 2591f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(last_mbuf, padval)); 2592f8829a4aSRandall Stewart } else { 2593f8829a4aSRandall Stewart while (m_at) { 2594139bc87fSRandall Stewart if (SCTP_BUF_NEXT(m_at) == NULL) { 2595f8829a4aSRandall Stewart return (sctp_add_pad_tombuf(m_at, padval)); 2596f8829a4aSRandall Stewart } 2597139bc87fSRandall Stewart m_at = SCTP_BUF_NEXT(m_at); 2598f8829a4aSRandall Stewart } 2599f8829a4aSRandall Stewart } 2600c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET_PKT(m, NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 2601f8829a4aSRandall Stewart return (EFAULT); 2602f8829a4aSRandall Stewart } 2603f8829a4aSRandall Stewart 2604f8829a4aSRandall Stewart static void 2605f8829a4aSRandall Stewart sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb, 2606*7215cc1bSMichael Tuexen uint32_t error, int so_locked 2607ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2608ceaad40aSRandall Stewart SCTP_UNUSED 2609ceaad40aSRandall Stewart #endif 2610ceaad40aSRandall Stewart ) 2611f8829a4aSRandall Stewart { 2612f8829a4aSRandall Stewart struct mbuf *m_notify; 2613f8829a4aSRandall Stewart struct sctp_assoc_change *sac; 2614f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2615f8829a4aSRandall Stewart 2616ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2617ceaad40aSRandall Stewart struct socket *so; 2618ceaad40aSRandall Stewart 2619ceaad40aSRandall Stewart #endif 2620ceaad40aSRandall Stewart 2621f8829a4aSRandall Stewart /* 2622f8829a4aSRandall Stewart * For TCP model AND UDP connected sockets we will send an error up 2623f8829a4aSRandall Stewart * when an ABORT comes in. 2624f8829a4aSRandall Stewart */ 2625f8829a4aSRandall Stewart if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 2626f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && 26273c503c28SRandall Stewart ((event == SCTP_COMM_LOST) || (event == SCTP_CANT_STR_ASSOC))) { 2628c4739e2fSRandall Stewart if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) { 2629c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNREFUSED); 263044b7479bSRandall Stewart stcb->sctp_socket->so_error = ECONNREFUSED; 2631c4739e2fSRandall Stewart } else { 2632c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 2633f8829a4aSRandall Stewart stcb->sctp_socket->so_error = ECONNRESET; 2634c4739e2fSRandall Stewart } 2635f8829a4aSRandall Stewart /* Wake ANY sleepers */ 2636ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2637ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 2638ceaad40aSRandall Stewart if (!so_locked) { 2639ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 2640ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 2641ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 2642ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 2643ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 2644ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 2645ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2646ceaad40aSRandall Stewart return; 2647ceaad40aSRandall Stewart } 2648ceaad40aSRandall Stewart } 2649ceaad40aSRandall Stewart #endif 26508b4da1c3SMichael Tuexen socantrcvmore(stcb->sctp_socket); 2651f8829a4aSRandall Stewart sorwakeup(stcb->sctp_socket); 2652f8829a4aSRandall Stewart sowwakeup(stcb->sctp_socket); 2653ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2654ceaad40aSRandall Stewart if (!so_locked) { 2655ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2656ceaad40aSRandall Stewart } 2657ceaad40aSRandall Stewart #endif 2658f8829a4aSRandall Stewart } 2659e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) { 2660f8829a4aSRandall Stewart /* event not enabled */ 2661f8829a4aSRandall Stewart return; 2662f8829a4aSRandall Stewart } 2663139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_assoc_change), 0, M_DONTWAIT, 1, MT_DATA); 2664f8829a4aSRandall Stewart if (m_notify == NULL) 2665f8829a4aSRandall Stewart /* no space left */ 2666f8829a4aSRandall Stewart return; 2667139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2668f8829a4aSRandall Stewart 2669f8829a4aSRandall Stewart sac = mtod(m_notify, struct sctp_assoc_change *); 2670f8829a4aSRandall Stewart sac->sac_type = SCTP_ASSOC_CHANGE; 2671f8829a4aSRandall Stewart sac->sac_flags = 0; 2672f8829a4aSRandall Stewart sac->sac_length = sizeof(struct sctp_assoc_change); 2673f8829a4aSRandall Stewart sac->sac_state = event; 2674f8829a4aSRandall Stewart sac->sac_error = error; 2675f8829a4aSRandall Stewart /* XXX verify these stream counts */ 2676f8829a4aSRandall Stewart sac->sac_outbound_streams = stcb->asoc.streamoutcnt; 2677f8829a4aSRandall Stewart sac->sac_inbound_streams = stcb->asoc.streamincnt; 2678f8829a4aSRandall Stewart sac->sac_assoc_id = sctp_get_associd(stcb); 2679139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_assoc_change); 2680139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 2681f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 2682*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2683f8829a4aSRandall Stewart m_notify); 2684f8829a4aSRandall Stewart if (control == NULL) { 2685f8829a4aSRandall Stewart /* no memory */ 2686f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2687f8829a4aSRandall Stewart return; 2688f8829a4aSRandall Stewart } 2689139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 2690f8829a4aSRandall Stewart /* not that we need this */ 2691f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2692139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2693f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2694f8829a4aSRandall Stewart control, 2695cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, 2696cfde3ff7SRandall Stewart so_locked); 2697f8829a4aSRandall Stewart if (event == SCTP_COMM_LOST) { 2698f8829a4aSRandall Stewart /* Wake up any sleeper */ 2699ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2700ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 2701ceaad40aSRandall Stewart if (!so_locked) { 2702ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 2703ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 2704ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 2705ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 2706ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 2707ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 2708ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2709ceaad40aSRandall Stewart return; 2710ceaad40aSRandall Stewart } 2711ceaad40aSRandall Stewart } 2712ceaad40aSRandall Stewart #endif 2713f8829a4aSRandall Stewart sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 2714ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 2715ceaad40aSRandall Stewart if (!so_locked) { 2716ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 2717ceaad40aSRandall Stewart } 2718ceaad40aSRandall Stewart #endif 2719f8829a4aSRandall Stewart } 2720f8829a4aSRandall Stewart } 2721f8829a4aSRandall Stewart 2722f8829a4aSRandall Stewart static void 2723f8829a4aSRandall Stewart sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state, 2724f8829a4aSRandall Stewart struct sockaddr *sa, uint32_t error) 2725f8829a4aSRandall Stewart { 2726f8829a4aSRandall Stewart struct mbuf *m_notify; 2727f8829a4aSRandall Stewart struct sctp_paddr_change *spc; 2728f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2729f8829a4aSRandall Stewart 2730e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) { 2731f8829a4aSRandall Stewart /* event not enabled */ 2732f8829a4aSRandall Stewart return; 2733830d754dSRandall Stewart } 2734139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_paddr_change), 0, M_DONTWAIT, 1, MT_DATA); 2735f8829a4aSRandall Stewart if (m_notify == NULL) 2736f8829a4aSRandall Stewart return; 2737139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2738f8829a4aSRandall Stewart spc = mtod(m_notify, struct sctp_paddr_change *); 2739f8829a4aSRandall Stewart spc->spc_type = SCTP_PEER_ADDR_CHANGE; 2740f8829a4aSRandall Stewart spc->spc_flags = 0; 2741f8829a4aSRandall Stewart spc->spc_length = sizeof(struct sctp_paddr_change); 27425e2c2d87SRandall Stewart switch (sa->sa_family) { 2743ea5eba11SMichael Tuexen #ifdef INET 27445e2c2d87SRandall Stewart case AF_INET: 2745f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in)); 27465e2c2d87SRandall Stewart break; 2747ea5eba11SMichael Tuexen #endif 27485e2c2d87SRandall Stewart #ifdef INET6 27495e2c2d87SRandall Stewart case AF_INET6: 27505e2c2d87SRandall Stewart { 2751f42a358aSRandall Stewart struct sockaddr_in6 *sin6; 2752f42a358aSRandall Stewart 2753f8829a4aSRandall Stewart memcpy(&spc->spc_aaddr, sa, sizeof(struct sockaddr_in6)); 2754f42a358aSRandall Stewart 2755f42a358aSRandall Stewart sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr; 2756f42a358aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) { 275742551e99SRandall Stewart if (sin6->sin6_scope_id == 0) { 275842551e99SRandall Stewart /* recover scope_id for user */ 2759f42a358aSRandall Stewart (void)sa6_recoverscope(sin6); 276042551e99SRandall Stewart } else { 276142551e99SRandall Stewart /* clear embedded scope_id for user */ 276242551e99SRandall Stewart in6_clearscope(&sin6->sin6_addr); 276342551e99SRandall Stewart } 2764f42a358aSRandall Stewart } 27655e2c2d87SRandall Stewart break; 27665e2c2d87SRandall Stewart } 27675e2c2d87SRandall Stewart #endif 27685e2c2d87SRandall Stewart default: 27695e2c2d87SRandall Stewart /* TSNH */ 27705e2c2d87SRandall Stewart break; 2771f8829a4aSRandall Stewart } 2772f8829a4aSRandall Stewart spc->spc_state = state; 2773f8829a4aSRandall Stewart spc->spc_error = error; 2774f8829a4aSRandall Stewart spc->spc_assoc_id = sctp_get_associd(stcb); 2775f8829a4aSRandall Stewart 2776139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_paddr_change); 2777139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 2778f8829a4aSRandall Stewart 2779f8829a4aSRandall Stewart /* append to socket */ 2780f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 2781*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2782f8829a4aSRandall Stewart m_notify); 2783f8829a4aSRandall Stewart if (control == NULL) { 2784f8829a4aSRandall Stewart /* no memory */ 2785f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2786f8829a4aSRandall Stewart return; 2787f8829a4aSRandall Stewart } 2788139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 2789139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2790f8829a4aSRandall Stewart /* not that we need this */ 2791f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2792f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2793f8829a4aSRandall Stewart control, 2794cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 2795cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 2796cfde3ff7SRandall Stewart SCTP_SO_NOT_LOCKED); 2797f8829a4aSRandall Stewart } 2798f8829a4aSRandall Stewart 2799f8829a4aSRandall Stewart 2800f8829a4aSRandall Stewart static void 2801f8829a4aSRandall Stewart sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error, 2802ceaad40aSRandall Stewart struct sctp_tmit_chunk *chk, int so_locked 2803ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2804ceaad40aSRandall Stewart SCTP_UNUSED 2805ceaad40aSRandall Stewart #endif 2806ceaad40aSRandall Stewart ) 2807f8829a4aSRandall Stewart { 2808830d754dSRandall Stewart struct mbuf *m_notify; 2809f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 2810f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2811f8829a4aSRandall Stewart int length; 2812f8829a4aSRandall Stewart 2813e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) { 2814f8829a4aSRandall Stewart /* event not enabled */ 2815f8829a4aSRandall Stewart return; 2816830d754dSRandall Stewart } 2817139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA); 2818f8829a4aSRandall Stewart if (m_notify == NULL) 2819f8829a4aSRandall Stewart /* no space left */ 2820f8829a4aSRandall Stewart return; 2821fc14de76SRandall Stewart length = sizeof(struct sctp_send_failed) + chk->send_size; 2822fc14de76SRandall Stewart length -= sizeof(struct sctp_data_chunk); 2823139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2824f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 2825f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 2826f8829a4aSRandall Stewart if (error == SCTP_NOTIFY_DATAGRAM_UNSENT) 2827f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_UNSENT; 2828f8829a4aSRandall Stewart else 2829f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_SENT; 2830f8829a4aSRandall Stewart ssf->ssf_length = length; 2831f8829a4aSRandall Stewart ssf->ssf_error = error; 2832f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 2833d00aff5dSRandall Stewart bzero(&ssf->ssf_info, sizeof(ssf->ssf_info)); 2834f8829a4aSRandall Stewart ssf->ssf_info.sinfo_stream = chk->rec.data.stream_number; 2835f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ssn = chk->rec.data.stream_seq; 2836f8829a4aSRandall Stewart ssf->ssf_info.sinfo_flags = chk->rec.data.rcv_flags; 2837f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = chk->rec.data.payloadtype; 2838f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = chk->rec.data.context; 2839f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 2840f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 2841fc14de76SRandall Stewart 2842830d754dSRandall Stewart if (chk->data) { 2843830d754dSRandall Stewart /* 2844830d754dSRandall Stewart * trim off the sctp chunk header(it should be there) 2845830d754dSRandall Stewart */ 2846830d754dSRandall Stewart if (chk->send_size >= sizeof(struct sctp_data_chunk)) { 2847830d754dSRandall Stewart m_adj(chk->data, sizeof(struct sctp_data_chunk)); 2848830d754dSRandall Stewart sctp_mbuf_crush(chk->data); 2849830d754dSRandall Stewart chk->send_size -= sizeof(struct sctp_data_chunk); 2850830d754dSRandall Stewart } 2851830d754dSRandall Stewart } 2852810ec536SMichael Tuexen SCTP_BUF_NEXT(m_notify) = chk->data; 2853810ec536SMichael Tuexen SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); 2854f8829a4aSRandall Stewart /* Steal off the mbuf */ 2855f8829a4aSRandall Stewart chk->data = NULL; 2856f8829a4aSRandall Stewart /* 2857f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 2858f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 2859f8829a4aSRandall Stewart * non-reader 2860f8829a4aSRandall Stewart */ 2861139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 2862f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2863f8829a4aSRandall Stewart return; 2864f8829a4aSRandall Stewart } 2865f8829a4aSRandall Stewart /* append to socket */ 2866f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 2867*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2868f8829a4aSRandall Stewart m_notify); 2869f8829a4aSRandall Stewart if (control == NULL) { 2870f8829a4aSRandall Stewart /* no memory */ 2871f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2872f8829a4aSRandall Stewart return; 2873f8829a4aSRandall Stewart } 2874139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2875f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2876f8829a4aSRandall Stewart control, 2877cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, 2878cfde3ff7SRandall Stewart SCTP_READ_LOCK_NOT_HELD, 2879cfde3ff7SRandall Stewart so_locked); 2880f8829a4aSRandall Stewart } 2881f8829a4aSRandall Stewart 2882f8829a4aSRandall Stewart 2883f8829a4aSRandall Stewart static void 2884f8829a4aSRandall Stewart sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error, 2885ceaad40aSRandall Stewart struct sctp_stream_queue_pending *sp, int so_locked 2886ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 2887ceaad40aSRandall Stewart SCTP_UNUSED 2888ceaad40aSRandall Stewart #endif 2889ceaad40aSRandall Stewart ) 2890f8829a4aSRandall Stewart { 2891f8829a4aSRandall Stewart struct mbuf *m_notify; 2892f8829a4aSRandall Stewart struct sctp_send_failed *ssf; 2893f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2894f8829a4aSRandall Stewart int length; 2895f8829a4aSRandall Stewart 2896e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) { 2897f8829a4aSRandall Stewart /* event not enabled */ 2898f8829a4aSRandall Stewart return; 2899830d754dSRandall Stewart } 2900f8829a4aSRandall Stewart length = sizeof(struct sctp_send_failed) + sp->length; 2901d00aff5dSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_send_failed), 0, M_DONTWAIT, 1, MT_DATA); 2902f8829a4aSRandall Stewart if (m_notify == NULL) 2903f8829a4aSRandall Stewart /* no space left */ 2904f8829a4aSRandall Stewart return; 2905139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2906f8829a4aSRandall Stewart ssf = mtod(m_notify, struct sctp_send_failed *); 2907f8829a4aSRandall Stewart ssf->ssf_type = SCTP_SEND_FAILED; 2908f8829a4aSRandall Stewart if (error == SCTP_NOTIFY_DATAGRAM_UNSENT) 2909f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_UNSENT; 2910f8829a4aSRandall Stewart else 2911f8829a4aSRandall Stewart ssf->ssf_flags = SCTP_DATA_SENT; 2912f8829a4aSRandall Stewart ssf->ssf_length = length; 2913f8829a4aSRandall Stewart ssf->ssf_error = error; 2914f8829a4aSRandall Stewart /* not exactly what the user sent in, but should be close :) */ 2915d00aff5dSRandall Stewart bzero(&ssf->ssf_info, sizeof(ssf->ssf_info)); 2916f8829a4aSRandall Stewart ssf->ssf_info.sinfo_stream = sp->stream; 2917f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ssn = sp->strseq; 2918fc14de76SRandall Stewart if (sp->some_taken) { 2919fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_LAST_FRAG; 2920fc14de76SRandall Stewart } else { 2921fc14de76SRandall Stewart ssf->ssf_info.sinfo_flags = SCTP_DATA_NOT_FRAG; 2922fc14de76SRandall Stewart } 2923f8829a4aSRandall Stewart ssf->ssf_info.sinfo_ppid = sp->ppid; 2924f8829a4aSRandall Stewart ssf->ssf_info.sinfo_context = sp->context; 2925f8829a4aSRandall Stewart ssf->ssf_info.sinfo_assoc_id = sctp_get_associd(stcb); 2926f8829a4aSRandall Stewart ssf->ssf_assoc_id = sctp_get_associd(stcb); 2927139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = sp->data; 2928139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_send_failed); 2929f8829a4aSRandall Stewart 2930f8829a4aSRandall Stewart /* Steal off the mbuf */ 2931f8829a4aSRandall Stewart sp->data = NULL; 2932f8829a4aSRandall Stewart /* 2933f8829a4aSRandall Stewart * For this case, we check the actual socket buffer, since the assoc 2934f8829a4aSRandall Stewart * is going away we don't want to overfill the socket buffer for a 2935f8829a4aSRandall Stewart * non-reader 2936f8829a4aSRandall Stewart */ 2937139bc87fSRandall Stewart if (sctp_sbspace_failedmsgs(&stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 2938f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2939f8829a4aSRandall Stewart return; 2940f8829a4aSRandall Stewart } 2941f8829a4aSRandall Stewart /* append to socket */ 2942f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 2943*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2944f8829a4aSRandall Stewart m_notify); 2945f8829a4aSRandall Stewart if (control == NULL) { 2946f8829a4aSRandall Stewart /* no memory */ 2947f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2948f8829a4aSRandall Stewart return; 2949f8829a4aSRandall Stewart } 2950139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2951f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2952f8829a4aSRandall Stewart control, 2953cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 2954f8829a4aSRandall Stewart } 2955f8829a4aSRandall Stewart 2956f8829a4aSRandall Stewart 2957f8829a4aSRandall Stewart 2958f8829a4aSRandall Stewart static void 2959*7215cc1bSMichael Tuexen sctp_notify_adaptation_layer(struct sctp_tcb *stcb) 2960f8829a4aSRandall Stewart { 2961f8829a4aSRandall Stewart struct mbuf *m_notify; 2962f8829a4aSRandall Stewart struct sctp_adaptation_event *sai; 2963f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 2964f8829a4aSRandall Stewart 2965e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) { 2966f8829a4aSRandall Stewart /* event not enabled */ 2967f8829a4aSRandall Stewart return; 2968830d754dSRandall Stewart } 2969139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_adaption_event), 0, M_DONTWAIT, 1, MT_DATA); 2970f8829a4aSRandall Stewart if (m_notify == NULL) 2971f8829a4aSRandall Stewart /* no space left */ 2972f8829a4aSRandall Stewart return; 2973139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 2974f8829a4aSRandall Stewart sai = mtod(m_notify, struct sctp_adaptation_event *); 2975f8829a4aSRandall Stewart sai->sai_type = SCTP_ADAPTATION_INDICATION; 2976f8829a4aSRandall Stewart sai->sai_flags = 0; 2977f8829a4aSRandall Stewart sai->sai_length = sizeof(struct sctp_adaptation_event); 29782afb3e84SRandall Stewart sai->sai_adaptation_ind = stcb->asoc.peers_adaptation; 2979f8829a4aSRandall Stewart sai->sai_assoc_id = sctp_get_associd(stcb); 2980f8829a4aSRandall Stewart 2981139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_adaptation_event); 2982139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 2983f8829a4aSRandall Stewart 2984f8829a4aSRandall Stewart /* append to socket */ 2985f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 2986*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 2987f8829a4aSRandall Stewart m_notify); 2988f8829a4aSRandall Stewart if (control == NULL) { 2989f8829a4aSRandall Stewart /* no memory */ 2990f8829a4aSRandall Stewart sctp_m_freem(m_notify); 2991f8829a4aSRandall Stewart return; 2992f8829a4aSRandall Stewart } 2993139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 2994139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 2995f8829a4aSRandall Stewart /* not that we need this */ 2996f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 2997f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 2998f8829a4aSRandall Stewart control, 2999cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3000f8829a4aSRandall Stewart } 3001f8829a4aSRandall Stewart 300203b0b021SRandall Stewart /* This always must be called with the read-queue LOCKED in the INP */ 3003810ec536SMichael Tuexen static void 30042dad8a55SRandall Stewart sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error, 3005810ec536SMichael Tuexen uint32_t val, int so_locked 3006810ec536SMichael Tuexen #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3007810ec536SMichael Tuexen SCTP_UNUSED 3008810ec536SMichael Tuexen #endif 3009810ec536SMichael Tuexen ) 3010f8829a4aSRandall Stewart { 3011f8829a4aSRandall Stewart struct mbuf *m_notify; 3012f8829a4aSRandall Stewart struct sctp_pdapi_event *pdapi; 3013f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 301403b0b021SRandall Stewart struct sockbuf *sb; 3015f8829a4aSRandall Stewart 3016e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) { 3017f8829a4aSRandall Stewart /* event not enabled */ 3018f8829a4aSRandall Stewart return; 3019830d754dSRandall Stewart } 3020cd1386abSMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 3021cd1386abSMichael Tuexen return; 3022cd1386abSMichael Tuexen } 3023139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_pdapi_event), 0, M_DONTWAIT, 1, MT_DATA); 3024f8829a4aSRandall Stewart if (m_notify == NULL) 3025f8829a4aSRandall Stewart /* no space left */ 3026f8829a4aSRandall Stewart return; 3027139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3028f8829a4aSRandall Stewart pdapi = mtod(m_notify, struct sctp_pdapi_event *); 3029f8829a4aSRandall Stewart pdapi->pdapi_type = SCTP_PARTIAL_DELIVERY_EVENT; 3030f8829a4aSRandall Stewart pdapi->pdapi_flags = 0; 3031f8829a4aSRandall Stewart pdapi->pdapi_length = sizeof(struct sctp_pdapi_event); 3032f8829a4aSRandall Stewart pdapi->pdapi_indication = error; 30339a6142d8SRandall Stewart pdapi->pdapi_stream = (val >> 16); 30349a6142d8SRandall Stewart pdapi->pdapi_seq = (val & 0x0000ffff); 3035f8829a4aSRandall Stewart pdapi->pdapi_assoc_id = sctp_get_associd(stcb); 3036f8829a4aSRandall Stewart 3037139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_pdapi_event); 3038139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3039f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3040*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3041f8829a4aSRandall Stewart m_notify); 3042f8829a4aSRandall Stewart if (control == NULL) { 3043f8829a4aSRandall Stewart /* no memory */ 3044f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3045f8829a4aSRandall Stewart return; 3046f8829a4aSRandall Stewart } 3047139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3048139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3049f8829a4aSRandall Stewart /* not that we need this */ 3050f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 305103b0b021SRandall Stewart control->held_length = 0; 305203b0b021SRandall Stewart control->length = 0; 305303b0b021SRandall Stewart sb = &stcb->sctp_socket->so_rcv; 3054b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 3055139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m_notify)); 305680fefe0aSRandall Stewart } 305703b0b021SRandall Stewart sctp_sballoc(stcb, sb, m_notify); 3058b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 305903b0b021SRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 306080fefe0aSRandall Stewart } 3061139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m_notify)); 306203b0b021SRandall Stewart control->end_added = 1; 306303b0b021SRandall Stewart if (stcb->asoc.control_pdapi) 306403b0b021SRandall Stewart TAILQ_INSERT_AFTER(&stcb->sctp_ep->read_queue, stcb->asoc.control_pdapi, control, next); 306503b0b021SRandall Stewart else { 306603b0b021SRandall Stewart /* we really should not see this case */ 306703b0b021SRandall Stewart TAILQ_INSERT_TAIL(&stcb->sctp_ep->read_queue, control, next); 306803b0b021SRandall Stewart } 306903b0b021SRandall Stewart if (stcb->sctp_ep && stcb->sctp_socket) { 307003b0b021SRandall Stewart /* This should always be the case */ 3071810ec536SMichael Tuexen #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3072810ec536SMichael Tuexen struct socket *so; 3073810ec536SMichael Tuexen 3074810ec536SMichael Tuexen so = SCTP_INP_SO(stcb->sctp_ep); 3075810ec536SMichael Tuexen if (!so_locked) { 3076810ec536SMichael Tuexen atomic_add_int(&stcb->asoc.refcnt, 1); 3077810ec536SMichael Tuexen SCTP_TCB_UNLOCK(stcb); 3078810ec536SMichael Tuexen SCTP_SOCKET_LOCK(so, 1); 3079810ec536SMichael Tuexen SCTP_TCB_LOCK(stcb); 3080810ec536SMichael Tuexen atomic_subtract_int(&stcb->asoc.refcnt, 1); 3081810ec536SMichael Tuexen if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3082810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3083810ec536SMichael Tuexen return; 3084810ec536SMichael Tuexen } 3085810ec536SMichael Tuexen } 3086810ec536SMichael Tuexen #endif 308703b0b021SRandall Stewart sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket); 3088810ec536SMichael Tuexen #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3089810ec536SMichael Tuexen if (!so_locked) { 3090810ec536SMichael Tuexen SCTP_SOCKET_UNLOCK(so, 1); 3091810ec536SMichael Tuexen } 3092810ec536SMichael Tuexen #endif 3093f8829a4aSRandall Stewart } 3094f8829a4aSRandall Stewart } 3095f8829a4aSRandall Stewart 3096f8829a4aSRandall Stewart static void 3097f8829a4aSRandall Stewart sctp_notify_shutdown_event(struct sctp_tcb *stcb) 3098f8829a4aSRandall Stewart { 3099f8829a4aSRandall Stewart struct mbuf *m_notify; 3100f8829a4aSRandall Stewart struct sctp_shutdown_event *sse; 3101f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3102f8829a4aSRandall Stewart 3103f8829a4aSRandall Stewart /* 3104f8829a4aSRandall Stewart * For TCP model AND UDP connected sockets we will send an error up 3105f8829a4aSRandall Stewart * when an SHUTDOWN completes 3106f8829a4aSRandall Stewart */ 3107f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 3108f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 3109f8829a4aSRandall Stewart /* mark socket closed for read/write and wakeup! */ 3110ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3111ceaad40aSRandall Stewart struct socket *so; 3112ceaad40aSRandall Stewart 3113ceaad40aSRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 3114ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3115ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3116ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3117ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3118ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3119ceaad40aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 3120ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3121ceaad40aSRandall Stewart return; 3122ceaad40aSRandall Stewart } 3123ceaad40aSRandall Stewart #endif 3124f8829a4aSRandall Stewart socantsendmore(stcb->sctp_socket); 3125ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3126ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3127ceaad40aSRandall Stewart #endif 3128f8829a4aSRandall Stewart } 3129e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) { 3130f8829a4aSRandall Stewart /* event not enabled */ 3131f8829a4aSRandall Stewart return; 3132830d754dSRandall Stewart } 3133139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_shutdown_event), 0, M_DONTWAIT, 1, MT_DATA); 3134f8829a4aSRandall Stewart if (m_notify == NULL) 3135f8829a4aSRandall Stewart /* no space left */ 3136f8829a4aSRandall Stewart return; 3137f8829a4aSRandall Stewart sse = mtod(m_notify, struct sctp_shutdown_event *); 3138f8829a4aSRandall Stewart sse->sse_type = SCTP_SHUTDOWN_EVENT; 3139f8829a4aSRandall Stewart sse->sse_flags = 0; 3140f8829a4aSRandall Stewart sse->sse_length = sizeof(struct sctp_shutdown_event); 3141f8829a4aSRandall Stewart sse->sse_assoc_id = sctp_get_associd(stcb); 3142f8829a4aSRandall Stewart 3143139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_shutdown_event); 3144139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3145f8829a4aSRandall Stewart 3146f8829a4aSRandall Stewart /* append to socket */ 3147f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3148*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3149f8829a4aSRandall Stewart m_notify); 3150f8829a4aSRandall Stewart if (control == NULL) { 3151f8829a4aSRandall Stewart /* no memory */ 3152f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3153f8829a4aSRandall Stewart return; 3154f8829a4aSRandall Stewart } 3155139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3156139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3157f8829a4aSRandall Stewart /* not that we need this */ 3158f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3159f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3160f8829a4aSRandall Stewart control, 3161cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3162f8829a4aSRandall Stewart } 3163f8829a4aSRandall Stewart 3164f8829a4aSRandall Stewart static void 3165830d754dSRandall Stewart sctp_notify_sender_dry_event(struct sctp_tcb *stcb, 3166830d754dSRandall Stewart int so_locked 3167830d754dSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3168830d754dSRandall Stewart SCTP_UNUSED 3169830d754dSRandall Stewart #endif 3170830d754dSRandall Stewart ) 3171830d754dSRandall Stewart { 3172830d754dSRandall Stewart struct mbuf *m_notify; 3173830d754dSRandall Stewart struct sctp_sender_dry_event *event; 3174830d754dSRandall Stewart struct sctp_queued_to_read *control; 3175830d754dSRandall Stewart 3176e2e7c62eSMichael Tuexen if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) { 3177830d754dSRandall Stewart /* event not enabled */ 3178830d754dSRandall Stewart return; 3179830d754dSRandall Stewart } 3180830d754dSRandall Stewart m_notify = sctp_get_mbuf_for_msg(sizeof(struct sctp_sender_dry_event), 0, M_DONTWAIT, 1, MT_DATA); 3181830d754dSRandall Stewart if (m_notify == NULL) { 3182830d754dSRandall Stewart /* no space left */ 3183830d754dSRandall Stewart return; 3184830d754dSRandall Stewart } 3185830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3186830d754dSRandall Stewart event = mtod(m_notify, struct sctp_sender_dry_event *); 3187830d754dSRandall Stewart event->sender_dry_type = SCTP_SENDER_DRY_EVENT; 3188830d754dSRandall Stewart event->sender_dry_flags = 0; 3189830d754dSRandall Stewart event->sender_dry_length = sizeof(struct sctp_sender_dry_event); 3190830d754dSRandall Stewart event->sender_dry_assoc_id = sctp_get_associd(stcb); 3191830d754dSRandall Stewart 3192830d754dSRandall Stewart SCTP_BUF_LEN(m_notify) = sizeof(struct sctp_sender_dry_event); 3193830d754dSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3194830d754dSRandall Stewart 3195830d754dSRandall Stewart /* append to socket */ 3196830d754dSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3197*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3198*7215cc1bSMichael Tuexen m_notify); 3199830d754dSRandall Stewart if (control == NULL) { 3200830d754dSRandall Stewart /* no memory */ 3201830d754dSRandall Stewart sctp_m_freem(m_notify); 3202830d754dSRandall Stewart return; 3203830d754dSRandall Stewart } 3204830d754dSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3205830d754dSRandall Stewart control->spec_flags = M_NOTIFICATION; 3206830d754dSRandall Stewart /* not that we need this */ 3207830d754dSRandall Stewart control->tail_mbuf = m_notify; 3208830d754dSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, control, 3209cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, so_locked); 3210830d754dSRandall Stewart } 3211830d754dSRandall Stewart 3212ea44232bSRandall Stewart 3213ea44232bSRandall Stewart static void 3214ea44232bSRandall Stewart sctp_notify_stream_reset_add(struct sctp_tcb *stcb, int number_entries, int flag) 3215ea44232bSRandall Stewart { 3216ea44232bSRandall Stewart struct mbuf *m_notify; 3217ea44232bSRandall Stewart struct sctp_queued_to_read *control; 3218ea44232bSRandall Stewart struct sctp_stream_reset_event *strreset; 3219ea44232bSRandall Stewart int len; 3220ea44232bSRandall Stewart 3221ea44232bSRandall Stewart if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) { 3222ea44232bSRandall Stewart /* event not enabled */ 3223ea44232bSRandall Stewart return; 3224ea44232bSRandall Stewart } 3225ea44232bSRandall Stewart m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA); 3226ea44232bSRandall Stewart if (m_notify == NULL) 3227ea44232bSRandall Stewart /* no space left */ 3228ea44232bSRandall Stewart return; 3229ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3230ea44232bSRandall Stewart len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); 3231ea44232bSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3232ea44232bSRandall Stewart /* never enough room */ 3233ea44232bSRandall Stewart sctp_m_freem(m_notify); 3234ea44232bSRandall Stewart return; 3235ea44232bSRandall Stewart } 3236ea44232bSRandall Stewart strreset = mtod(m_notify, struct sctp_stream_reset_event *); 3237ea44232bSRandall Stewart strreset->strreset_type = SCTP_STREAM_RESET_EVENT; 3238ea44232bSRandall Stewart strreset->strreset_flags = SCTP_STRRESET_ADD_STREAM | flag; 3239ea44232bSRandall Stewart strreset->strreset_length = len; 3240ea44232bSRandall Stewart strreset->strreset_assoc_id = sctp_get_associd(stcb); 3241ea44232bSRandall Stewart strreset->strreset_list[0] = number_entries; 3242ea44232bSRandall Stewart 3243ea44232bSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3244ea44232bSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3245ea44232bSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3246ea44232bSRandall Stewart /* no space */ 3247ea44232bSRandall Stewart sctp_m_freem(m_notify); 3248ea44232bSRandall Stewart return; 3249ea44232bSRandall Stewart } 3250ea44232bSRandall Stewart /* append to socket */ 3251ea44232bSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3252*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3253ea44232bSRandall Stewart m_notify); 3254ea44232bSRandall Stewart if (control == NULL) { 3255ea44232bSRandall Stewart /* no memory */ 3256ea44232bSRandall Stewart sctp_m_freem(m_notify); 3257ea44232bSRandall Stewart return; 3258ea44232bSRandall Stewart } 3259ea44232bSRandall Stewart control->spec_flags = M_NOTIFICATION; 3260ea44232bSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3261ea44232bSRandall Stewart /* not that we need this */ 3262ea44232bSRandall Stewart control->tail_mbuf = m_notify; 3263ea44232bSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3264ea44232bSRandall Stewart control, 3265cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3266ea44232bSRandall Stewart } 3267ea44232bSRandall Stewart 3268ea44232bSRandall Stewart 3269830d754dSRandall Stewart static void 3270f8829a4aSRandall Stewart sctp_notify_stream_reset(struct sctp_tcb *stcb, 3271f8829a4aSRandall Stewart int number_entries, uint16_t * list, int flag) 3272f8829a4aSRandall Stewart { 3273f8829a4aSRandall Stewart struct mbuf *m_notify; 3274f8829a4aSRandall Stewart struct sctp_queued_to_read *control; 3275f8829a4aSRandall Stewart struct sctp_stream_reset_event *strreset; 3276f8829a4aSRandall Stewart int len; 3277f8829a4aSRandall Stewart 3278830d754dSRandall Stewart if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) { 3279f8829a4aSRandall Stewart /* event not enabled */ 3280f8829a4aSRandall Stewart return; 3281830d754dSRandall Stewart } 3282139bc87fSRandall Stewart m_notify = sctp_get_mbuf_for_msg(MCLBYTES, 0, M_DONTWAIT, 1, MT_DATA); 3283f8829a4aSRandall Stewart if (m_notify == NULL) 3284f8829a4aSRandall Stewart /* no space left */ 3285f8829a4aSRandall Stewart return; 3286139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = 0; 3287f8829a4aSRandall Stewart len = sizeof(struct sctp_stream_reset_event) + (number_entries * sizeof(uint16_t)); 3288f8829a4aSRandall Stewart if (len > M_TRAILINGSPACE(m_notify)) { 3289f8829a4aSRandall Stewart /* never enough room */ 3290f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3291f8829a4aSRandall Stewart return; 3292f8829a4aSRandall Stewart } 3293f8829a4aSRandall Stewart strreset = mtod(m_notify, struct sctp_stream_reset_event *); 3294f8829a4aSRandall Stewart strreset->strreset_type = SCTP_STREAM_RESET_EVENT; 3295f8829a4aSRandall Stewart if (number_entries == 0) { 3296f8829a4aSRandall Stewart strreset->strreset_flags = flag | SCTP_STRRESET_ALL_STREAMS; 3297f8829a4aSRandall Stewart } else { 3298f8829a4aSRandall Stewart strreset->strreset_flags = flag | SCTP_STRRESET_STREAM_LIST; 3299f8829a4aSRandall Stewart } 3300f8829a4aSRandall Stewart strreset->strreset_length = len; 3301f8829a4aSRandall Stewart strreset->strreset_assoc_id = sctp_get_associd(stcb); 3302f8829a4aSRandall Stewart if (number_entries) { 3303f8829a4aSRandall Stewart int i; 3304f8829a4aSRandall Stewart 3305f8829a4aSRandall Stewart for (i = 0; i < number_entries; i++) { 3306f8829a4aSRandall Stewart strreset->strreset_list[i] = ntohs(list[i]); 3307f8829a4aSRandall Stewart } 3308f8829a4aSRandall Stewart } 3309139bc87fSRandall Stewart SCTP_BUF_LEN(m_notify) = len; 3310139bc87fSRandall Stewart SCTP_BUF_NEXT(m_notify) = NULL; 3311139bc87fSRandall Stewart if (sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv) < SCTP_BUF_LEN(m_notify)) { 3312f8829a4aSRandall Stewart /* no space */ 3313f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3314f8829a4aSRandall Stewart return; 3315f8829a4aSRandall Stewart } 3316f8829a4aSRandall Stewart /* append to socket */ 3317f8829a4aSRandall Stewart control = sctp_build_readq_entry(stcb, stcb->asoc.primary_destination, 3318*7215cc1bSMichael Tuexen 0, 0, stcb->asoc.context, 0, 0, 0, 3319f8829a4aSRandall Stewart m_notify); 3320f8829a4aSRandall Stewart if (control == NULL) { 3321f8829a4aSRandall Stewart /* no memory */ 3322f8829a4aSRandall Stewart sctp_m_freem(m_notify); 3323f8829a4aSRandall Stewart return; 3324f8829a4aSRandall Stewart } 3325139bc87fSRandall Stewart control->spec_flags = M_NOTIFICATION; 3326139bc87fSRandall Stewart control->length = SCTP_BUF_LEN(m_notify); 3327f8829a4aSRandall Stewart /* not that we need this */ 3328f8829a4aSRandall Stewart control->tail_mbuf = m_notify; 3329f8829a4aSRandall Stewart sctp_add_to_readq(stcb->sctp_ep, stcb, 3330f8829a4aSRandall Stewart control, 3331cfde3ff7SRandall Stewart &stcb->sctp_socket->so_rcv, 1, SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED); 3332f8829a4aSRandall Stewart } 3333f8829a4aSRandall Stewart 3334f8829a4aSRandall Stewart 3335f8829a4aSRandall Stewart void 3336f8829a4aSRandall Stewart sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb, 3337ceaad40aSRandall Stewart uint32_t error, void *data, int so_locked 3338ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3339ceaad40aSRandall Stewart SCTP_UNUSED 3340ceaad40aSRandall Stewart #endif 3341ceaad40aSRandall Stewart ) 3342f8829a4aSRandall Stewart { 3343830d754dSRandall Stewart if ((stcb == NULL) || 3344830d754dSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3345f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3346830d754dSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 3347830d754dSRandall Stewart /* If the socket is gone we are out of here */ 3348f8829a4aSRandall Stewart return; 3349f8829a4aSRandall Stewart } 3350a99b6783SRandall Stewart if (stcb->sctp_socket->so_rcv.sb_state & SBS_CANTRCVMORE) { 3351a99b6783SRandall Stewart return; 3352a99b6783SRandall Stewart } 335317205eccSRandall Stewart if (stcb && ((stcb->asoc.state & SCTP_STATE_COOKIE_WAIT) || 335417205eccSRandall Stewart (stcb->asoc.state & SCTP_STATE_COOKIE_ECHOED))) { 335517205eccSRandall Stewart if ((notification == SCTP_NOTIFY_INTERFACE_DOWN) || 335617205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_UP) || 335717205eccSRandall Stewart (notification == SCTP_NOTIFY_INTERFACE_CONFIRMED)) { 335817205eccSRandall Stewart /* Don't report these in front states */ 335917205eccSRandall Stewart return; 336017205eccSRandall Stewart } 336117205eccSRandall Stewart } 3362f8829a4aSRandall Stewart switch (notification) { 3363f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_UP: 3364f8829a4aSRandall Stewart if (stcb->asoc.assoc_up_sent == 0) { 3365*7215cc1bSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, so_locked); 3366f8829a4aSRandall Stewart stcb->asoc.assoc_up_sent = 1; 3367f8829a4aSRandall Stewart } 33682afb3e84SRandall Stewart if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) { 3369*7215cc1bSMichael Tuexen sctp_notify_adaptation_layer(stcb); 33702afb3e84SRandall Stewart } 3371830d754dSRandall Stewart if (stcb->asoc.peer_supports_auth == 0) { 3372830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 3373830d754dSRandall Stewart NULL, so_locked); 3374830d754dSRandall Stewart } 3375f8829a4aSRandall Stewart break; 3376f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_DOWN: 3377*7215cc1bSMichael Tuexen sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, so_locked); 3378f8829a4aSRandall Stewart break; 3379f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_DOWN: 3380f8829a4aSRandall Stewart { 3381f8829a4aSRandall Stewart struct sctp_nets *net; 3382f8829a4aSRandall Stewart 3383f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3384f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_UNREACHABLE, 3385f8829a4aSRandall Stewart (struct sockaddr *)&net->ro._l_addr, error); 3386f8829a4aSRandall Stewart break; 3387f8829a4aSRandall Stewart } 3388f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_UP: 3389f8829a4aSRandall Stewart { 3390f8829a4aSRandall Stewart struct sctp_nets *net; 3391f8829a4aSRandall Stewart 3392f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3393f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_AVAILABLE, 3394f8829a4aSRandall Stewart (struct sockaddr *)&net->ro._l_addr, error); 3395f8829a4aSRandall Stewart break; 3396f8829a4aSRandall Stewart } 3397f8829a4aSRandall Stewart case SCTP_NOTIFY_INTERFACE_CONFIRMED: 3398f8829a4aSRandall Stewart { 3399f8829a4aSRandall Stewart struct sctp_nets *net; 3400f8829a4aSRandall Stewart 3401f8829a4aSRandall Stewart net = (struct sctp_nets *)data; 3402f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_CONFIRMED, 3403f8829a4aSRandall Stewart (struct sockaddr *)&net->ro._l_addr, error); 3404f8829a4aSRandall Stewart break; 3405f8829a4aSRandall Stewart } 3406f8829a4aSRandall Stewart case SCTP_NOTIFY_SPECIAL_SP_FAIL: 3407f8829a4aSRandall Stewart sctp_notify_send_failed2(stcb, error, 3408ceaad40aSRandall Stewart (struct sctp_stream_queue_pending *)data, so_locked); 3409f8829a4aSRandall Stewart break; 3410f8829a4aSRandall Stewart case SCTP_NOTIFY_DG_FAIL: 3411f8829a4aSRandall Stewart sctp_notify_send_failed(stcb, error, 3412ceaad40aSRandall Stewart (struct sctp_tmit_chunk *)data, so_locked); 3413f8829a4aSRandall Stewart break; 3414f8829a4aSRandall Stewart case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION: 34159a6142d8SRandall Stewart { 34169a6142d8SRandall Stewart uint32_t val; 34179a6142d8SRandall Stewart 34189a6142d8SRandall Stewart val = *((uint32_t *) data); 34199a6142d8SRandall Stewart 3420810ec536SMichael Tuexen sctp_notify_partial_delivery_indication(stcb, error, val, so_locked); 3421f8829a4aSRandall Stewart break; 3422810ec536SMichael Tuexen } 3423f8829a4aSRandall Stewart case SCTP_NOTIFY_STRDATA_ERR: 3424f8829a4aSRandall Stewart break; 3425f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_ABORTED: 3426c105859eSRandall Stewart if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) || 3427c105859eSRandall Stewart ((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) { 3428*7215cc1bSMichael Tuexen sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, so_locked); 3429c105859eSRandall Stewart } else { 3430*7215cc1bSMichael Tuexen sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, so_locked); 3431c105859eSRandall Stewart } 3432f8829a4aSRandall Stewart break; 3433f8829a4aSRandall Stewart case SCTP_NOTIFY_PEER_OPENED_STREAM: 3434f8829a4aSRandall Stewart break; 3435f8829a4aSRandall Stewart case SCTP_NOTIFY_STREAM_OPENED_OK: 3436f8829a4aSRandall Stewart break; 3437f8829a4aSRandall Stewart case SCTP_NOTIFY_ASSOC_RESTART: 3438*7215cc1bSMichael Tuexen sctp_notify_assoc_change(SCTP_RESTART, stcb, error, so_locked); 3439830d754dSRandall Stewart if (stcb->asoc.peer_supports_auth == 0) { 3440830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_NO_PEER_AUTH, stcb, 0, 3441830d754dSRandall Stewart NULL, so_locked); 3442830d754dSRandall Stewart } 3443f8829a4aSRandall Stewart break; 3444f8829a4aSRandall Stewart case SCTP_NOTIFY_HB_RESP: 3445f8829a4aSRandall Stewart break; 3446ea44232bSRandall Stewart case SCTP_NOTIFY_STR_RESET_INSTREAM_ADD_OK: 3447ea44232bSRandall Stewart sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_INBOUND_STR); 3448ea44232bSRandall Stewart break; 3449ea44232bSRandall Stewart case SCTP_NOTIFY_STR_RESET_ADD_OK: 3450ea44232bSRandall Stewart sctp_notify_stream_reset_add(stcb, error, SCTP_STRRESET_OUTBOUND_STR); 3451ea44232bSRandall Stewart break; 3452ea44232bSRandall Stewart case SCTP_NOTIFY_STR_RESET_ADD_FAIL: 3453ea44232bSRandall Stewart sctp_notify_stream_reset_add(stcb, error, (SCTP_STRRESET_FAILED | SCTP_STRRESET_OUTBOUND_STR)); 3454ea44232bSRandall Stewart break; 3455ea44232bSRandall Stewart 3456f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_SEND: 3457f8829a4aSRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_OUTBOUND_STR); 3458f8829a4aSRandall Stewart break; 3459f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_RECV: 3460f8829a4aSRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), SCTP_STRRESET_INBOUND_STR); 3461f8829a4aSRandall Stewart break; 3462f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_OUT: 3463671d309cSRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_OUTBOUND_STR | SCTP_STRRESET_FAILED)); 3464f8829a4aSRandall Stewart break; 3465f8829a4aSRandall Stewart case SCTP_NOTIFY_STR_RESET_FAILED_IN: 3466671d309cSRandall Stewart sctp_notify_stream_reset(stcb, error, ((uint16_t *) data), (SCTP_STRRESET_INBOUND_STR | SCTP_STRRESET_FAILED)); 3467f8829a4aSRandall Stewart break; 3468f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_ADD_IP: 3469f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_ADDED, data, 3470f8829a4aSRandall Stewart error); 3471f8829a4aSRandall Stewart break; 3472f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_DELETE_IP: 3473f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_REMOVED, data, 3474f8829a4aSRandall Stewart error); 3475f8829a4aSRandall Stewart break; 3476f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_SET_PRIMARY: 3477f8829a4aSRandall Stewart sctp_notify_peer_addr_change(stcb, SCTP_ADDR_MADE_PRIM, data, 3478f8829a4aSRandall Stewart error); 3479f8829a4aSRandall Stewart break; 3480f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_SUCCESS: 3481f8829a4aSRandall Stewart break; 3482f8829a4aSRandall Stewart case SCTP_NOTIFY_ASCONF_FAILED: 3483f8829a4aSRandall Stewart break; 3484f8829a4aSRandall Stewart case SCTP_NOTIFY_PEER_SHUTDOWN: 3485f8829a4aSRandall Stewart sctp_notify_shutdown_event(stcb); 3486f8829a4aSRandall Stewart break; 3487f8829a4aSRandall Stewart case SCTP_NOTIFY_AUTH_NEW_KEY: 3488f8829a4aSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_NEWKEY, error, 3489830d754dSRandall Stewart (uint16_t) (uintptr_t) data, 3490830d754dSRandall Stewart so_locked); 3491f8829a4aSRandall Stewart break; 3492830d754dSRandall Stewart case SCTP_NOTIFY_AUTH_FREE_KEY: 3493830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_FREE_KEY, error, 3494830d754dSRandall Stewart (uint16_t) (uintptr_t) data, 3495830d754dSRandall Stewart so_locked); 3496f8829a4aSRandall Stewart break; 3497830d754dSRandall Stewart case SCTP_NOTIFY_NO_PEER_AUTH: 3498830d754dSRandall Stewart sctp_notify_authentication(stcb, SCTP_AUTH_NO_AUTH, error, 3499830d754dSRandall Stewart (uint16_t) (uintptr_t) data, 3500830d754dSRandall Stewart so_locked); 3501830d754dSRandall Stewart break; 3502830d754dSRandall Stewart case SCTP_NOTIFY_SENDER_DRY: 3503830d754dSRandall Stewart sctp_notify_sender_dry_event(stcb, so_locked); 3504830d754dSRandall Stewart break; 3505f8829a4aSRandall Stewart default: 3506ad81507eSRandall Stewart SCTPDBG(SCTP_DEBUG_UTIL1, "%s: unknown notification %xh (%u)\n", 3507ad81507eSRandall Stewart __FUNCTION__, notification, notification); 3508f8829a4aSRandall Stewart break; 3509f8829a4aSRandall Stewart } /* end switch */ 3510f8829a4aSRandall Stewart } 3511f8829a4aSRandall Stewart 3512f8829a4aSRandall Stewart void 3513ceaad40aSRandall Stewart sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked 3514ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3515ceaad40aSRandall Stewart SCTP_UNUSED 3516ceaad40aSRandall Stewart #endif 3517ceaad40aSRandall Stewart ) 3518f8829a4aSRandall Stewart { 3519f8829a4aSRandall Stewart struct sctp_association *asoc; 3520f8829a4aSRandall Stewart struct sctp_stream_out *outs; 35214a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk, *nchk; 35224a9ef3f8SMichael Tuexen struct sctp_stream_queue_pending *sp, *nsp; 35237f34832bSRandall Stewart int i; 3524f8829a4aSRandall Stewart 3525ad81507eSRandall Stewart if (stcb == NULL) { 3526ad81507eSRandall Stewart return; 3527ad81507eSRandall Stewart } 35284a9ef3f8SMichael Tuexen asoc = &stcb->asoc; 35294a9ef3f8SMichael Tuexen if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) { 3530478fbccbSRandall Stewart /* already being freed */ 3531478fbccbSRandall Stewart return; 3532478fbccbSRandall Stewart } 3533f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3534f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 35354a9ef3f8SMichael Tuexen (asoc->state & SCTP_STATE_CLOSED_SOCKET)) { 3536f8829a4aSRandall Stewart return; 3537f8829a4aSRandall Stewart } 3538f8829a4aSRandall Stewart /* now through all the gunk freeing chunks */ 3539ad81507eSRandall Stewart if (holds_lock == 0) { 35407f34832bSRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 3541ad81507eSRandall Stewart } 3542d00aff5dSRandall Stewart /* sent queue SHOULD be empty */ 35434a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { 3544d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); 3545d00aff5dSRandall Stewart asoc->sent_queue_cnt--; 35460c0982b8SRandall Stewart if (chk->data != NULL) { 3547d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 3548d00aff5dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, 3549ceaad40aSRandall Stewart SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked); 3550810ec536SMichael Tuexen if (chk->data) { 3551d00aff5dSRandall Stewart sctp_m_freem(chk->data); 3552d00aff5dSRandall Stewart chk->data = NULL; 3553d00aff5dSRandall Stewart } 3554810ec536SMichael Tuexen } 3555689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 3556d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 3557d00aff5dSRandall Stewart } 3558d00aff5dSRandall Stewart /* pending send queue SHOULD be empty */ 35594a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) { 3560d00aff5dSRandall Stewart TAILQ_REMOVE(&asoc->send_queue, chk, sctp_next); 3561d00aff5dSRandall Stewart asoc->send_queue_cnt--; 35620c0982b8SRandall Stewart if (chk->data != NULL) { 3563d00aff5dSRandall Stewart sctp_free_bufspace(stcb, asoc, chk, 1); 35640c0982b8SRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, 35650c0982b8SRandall Stewart SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked); 3566810ec536SMichael Tuexen if (chk->data) { 3567d00aff5dSRandall Stewart sctp_m_freem(chk->data); 3568d00aff5dSRandall Stewart chk->data = NULL; 3569d00aff5dSRandall Stewart } 3570810ec536SMichael Tuexen } 3571689e6a5fSMichael Tuexen sctp_free_a_chunk(stcb, chk, so_locked); 3572d00aff5dSRandall Stewart /* sa_ignore FREED_MEMORY */ 3573d00aff5dSRandall Stewart } 35744a9ef3f8SMichael Tuexen for (i = 0; i < asoc->streamoutcnt; i++) { 35757f34832bSRandall Stewart /* For each stream */ 35764a9ef3f8SMichael Tuexen outs = &asoc->strmout[i]; 35777f34832bSRandall Stewart /* clean up any sends there */ 35784a9ef3f8SMichael Tuexen asoc->locked_on_sending = NULL; 35794a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(sp, &outs->outqueue, next, nsp) { 35804a9ef3f8SMichael Tuexen asoc->stream_queue_cnt--; 3581f8829a4aSRandall Stewart TAILQ_REMOVE(&outs->outqueue, sp, next); 3582f8829a4aSRandall Stewart sctp_free_spbufspace(stcb, asoc, sp); 3583478fbccbSRandall Stewart if (sp->data) { 3584f8829a4aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb, 3585ceaad40aSRandall Stewart SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp, so_locked); 3586f8829a4aSRandall Stewart if (sp->data) { 3587f8829a4aSRandall Stewart sctp_m_freem(sp->data); 3588f8829a4aSRandall Stewart sp->data = NULL; 3589f8829a4aSRandall Stewart } 3590478fbccbSRandall Stewart } 35919eea4a2dSMichael Tuexen if (sp->net) { 3592f8829a4aSRandall Stewart sctp_free_remote_addr(sp->net); 3593f8829a4aSRandall Stewart sp->net = NULL; 35949eea4a2dSMichael Tuexen } 3595f8829a4aSRandall Stewart /* Free the chunk */ 3596689e6a5fSMichael Tuexen sctp_free_a_strmoq(stcb, sp, so_locked); 35973c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 3598f8829a4aSRandall Stewart } 3599f8829a4aSRandall Stewart } 3600f8829a4aSRandall Stewart 3601ad81507eSRandall Stewart if (holds_lock == 0) { 36027f34832bSRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 3603f8829a4aSRandall Stewart } 3604ad81507eSRandall Stewart } 3605f8829a4aSRandall Stewart 3606f8829a4aSRandall Stewart void 3607ceaad40aSRandall Stewart sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked 3608ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3609ceaad40aSRandall Stewart SCTP_UNUSED 3610ceaad40aSRandall Stewart #endif 3611ceaad40aSRandall Stewart ) 3612f8829a4aSRandall Stewart { 3613ad81507eSRandall Stewart if (stcb == NULL) { 3614ad81507eSRandall Stewart return; 3615ad81507eSRandall Stewart } 3616c55b70ceSMichael Tuexen if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || 3617c55b70ceSMichael Tuexen ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && 3618c55b70ceSMichael Tuexen (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) { 3619c55b70ceSMichael Tuexen stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED; 3620c55b70ceSMichael Tuexen } 3621f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 3622f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || 3623f8829a4aSRandall Stewart (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) { 3624f8829a4aSRandall Stewart return; 3625f8829a4aSRandall Stewart } 3626f8829a4aSRandall Stewart /* Tell them we lost the asoc */ 3627ceaad40aSRandall Stewart sctp_report_all_outbound(stcb, 1, so_locked); 3628ceaad40aSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL, so_locked); 3629f8829a4aSRandall Stewart } 3630f8829a4aSRandall Stewart 3631f8829a4aSRandall Stewart void 3632f8829a4aSRandall Stewart sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 363317205eccSRandall Stewart struct mbuf *m, int iphlen, struct sctphdr *sh, struct mbuf *op_err, 3634c54a18d2SRandall Stewart uint32_t vrf_id, uint16_t port) 3635f8829a4aSRandall Stewart { 3636f8829a4aSRandall Stewart uint32_t vtag; 3637f8829a4aSRandall Stewart 3638ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3639ceaad40aSRandall Stewart struct socket *so; 3640ceaad40aSRandall Stewart 3641ceaad40aSRandall Stewart #endif 3642ceaad40aSRandall Stewart 3643f8829a4aSRandall Stewart vtag = 0; 3644f8829a4aSRandall Stewart if (stcb != NULL) { 3645f8829a4aSRandall Stewart /* We have a TCB to abort, send notification too */ 3646f8829a4aSRandall Stewart vtag = stcb->asoc.peer_vtag; 3647ceaad40aSRandall Stewart sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED); 364817205eccSRandall Stewart /* get the assoc vrf id and table id */ 364917205eccSRandall Stewart vrf_id = stcb->asoc.vrf_id; 365063981c2bSRandall Stewart stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; 3651f8829a4aSRandall Stewart } 3652c54a18d2SRandall Stewart sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id, port); 3653f8829a4aSRandall Stewart if (stcb != NULL) { 3654f8829a4aSRandall Stewart /* Ok, now lets free it */ 3655ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3656ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 3657ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3658ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3659ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3660ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3661ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3662ceaad40aSRandall Stewart #endif 36630271d0cdSMichael Tuexen SCTP_STAT_INCR_COUNTER32(sctps_aborted); 36640271d0cdSMichael Tuexen if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 36650271d0cdSMichael Tuexen (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 36660271d0cdSMichael Tuexen SCTP_STAT_DECR_GAUGE32(sctps_currestab); 36670271d0cdSMichael Tuexen } 3668c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_4); 3669ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3670ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3671ceaad40aSRandall Stewart #endif 3672f8829a4aSRandall Stewart } 3673f8829a4aSRandall Stewart } 3674f8829a4aSRandall Stewart 3675f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 3676f1f73e57SRandall Stewart void 3677f1f73e57SRandall Stewart sctp_print_out_track_log(struct sctp_tcb *stcb) 3678f1f73e57SRandall Stewart { 367918e198d3SRandall Stewart #ifdef NOSIY_PRINTS 3680f1f73e57SRandall Stewart int i; 3681f1f73e57SRandall Stewart 3682ad81507eSRandall Stewart SCTP_PRINTF("Last ep reason:%x\n", stcb->sctp_ep->last_abort_code); 3683ad81507eSRandall Stewart SCTP_PRINTF("IN bound TSN log-aaa\n"); 3684f1f73e57SRandall Stewart if ((stcb->asoc.tsn_in_at == 0) && (stcb->asoc.tsn_in_wrapped == 0)) { 3685ad81507eSRandall Stewart SCTP_PRINTF("None rcvd\n"); 3686f1f73e57SRandall Stewart goto none_in; 3687f1f73e57SRandall Stewart } 3688f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_wrapped) { 3689f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_in_at; i < SCTP_TSN_LOG_SIZE; i++) { 3690ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3691f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 3692f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 3693f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 3694f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 3695f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 3696f1f73e57SRandall Stewart } 3697f1f73e57SRandall Stewart } 3698f1f73e57SRandall Stewart if (stcb->asoc.tsn_in_at) { 3699f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_in_at; i++) { 3700ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3701f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].tsn, 3702f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].strm, 3703f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].seq, 3704f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].flgs, 3705f1f73e57SRandall Stewart stcb->asoc.in_tsnlog[i].sz); 3706f1f73e57SRandall Stewart } 3707f1f73e57SRandall Stewart } 3708f1f73e57SRandall Stewart none_in: 3709ad81507eSRandall Stewart SCTP_PRINTF("OUT bound TSN log-aaa\n"); 3710ad81507eSRandall Stewart if ((stcb->asoc.tsn_out_at == 0) && 3711ad81507eSRandall Stewart (stcb->asoc.tsn_out_wrapped == 0)) { 3712ad81507eSRandall Stewart SCTP_PRINTF("None sent\n"); 3713f1f73e57SRandall Stewart } 3714f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_wrapped) { 3715f1f73e57SRandall Stewart for (i = stcb->asoc.tsn_out_at; i < SCTP_TSN_LOG_SIZE; i++) { 3716ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3717f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 3718f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 3719f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 3720f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 3721f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 3722f1f73e57SRandall Stewart } 3723f1f73e57SRandall Stewart } 3724f1f73e57SRandall Stewart if (stcb->asoc.tsn_out_at) { 3725f1f73e57SRandall Stewart for (i = 0; i < stcb->asoc.tsn_out_at; i++) { 3726ad81507eSRandall Stewart SCTP_PRINTF("TSN:%x strm:%d seq:%d flags:%x sz:%d\n", 3727f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].tsn, 3728f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].strm, 3729f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].seq, 3730f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].flgs, 3731f1f73e57SRandall Stewart stcb->asoc.out_tsnlog[i].sz); 3732f1f73e57SRandall Stewart } 3733f1f73e57SRandall Stewart } 373418e198d3SRandall Stewart #endif 3735f1f73e57SRandall Stewart } 3736f1f73e57SRandall Stewart 3737f1f73e57SRandall Stewart #endif 3738f1f73e57SRandall Stewart 3739f8829a4aSRandall Stewart void 3740f8829a4aSRandall Stewart sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb, 3741ceaad40aSRandall Stewart int error, struct mbuf *op_err, 3742ceaad40aSRandall Stewart int so_locked 3743ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 3744ceaad40aSRandall Stewart SCTP_UNUSED 3745ceaad40aSRandall Stewart #endif 3746ceaad40aSRandall Stewart ) 3747f8829a4aSRandall Stewart { 3748ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3749ceaad40aSRandall Stewart struct socket *so; 3750ceaad40aSRandall Stewart 3751ceaad40aSRandall Stewart #endif 3752ceaad40aSRandall Stewart 3753ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3754ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 3755ceaad40aSRandall Stewart #endif 3756f8829a4aSRandall Stewart if (stcb == NULL) { 3757f8829a4aSRandall Stewart /* Got to have a TCB */ 3758f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 3759f8829a4aSRandall Stewart if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) { 3760b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 3761b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 3762f8829a4aSRandall Stewart } 3763f8829a4aSRandall Stewart } 3764f8829a4aSRandall Stewart return; 376563981c2bSRandall Stewart } else { 376663981c2bSRandall Stewart stcb->asoc.state |= SCTP_STATE_WAS_ABORTED; 3767f8829a4aSRandall Stewart } 3768f8829a4aSRandall Stewart /* notify the ulp */ 3769f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) 3770ceaad40aSRandall Stewart sctp_abort_notification(stcb, error, so_locked); 3771f8829a4aSRandall Stewart /* notify the peer */ 3772b201f536SRandall Stewart #if defined(SCTP_PANIC_ON_ABORT) 3773b201f536SRandall Stewart panic("aborting an association"); 3774b201f536SRandall Stewart #endif 3775ceaad40aSRandall Stewart sctp_send_abort_tcb(stcb, op_err, so_locked); 3776f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_aborted); 3777f8829a4aSRandall Stewart if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || 3778f8829a4aSRandall Stewart (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { 3779f8829a4aSRandall Stewart SCTP_STAT_DECR_GAUGE32(sctps_currestab); 3780f8829a4aSRandall Stewart } 3781f8829a4aSRandall Stewart /* now free the asoc */ 3782f1f73e57SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 3783f1f73e57SRandall Stewart sctp_print_out_track_log(stcb); 3784f1f73e57SRandall Stewart #endif 3785ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3786ceaad40aSRandall Stewart if (!so_locked) { 3787ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 3788ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 3789ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 3790ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 3791ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 3792ceaad40aSRandall Stewart } 3793ceaad40aSRandall Stewart #endif 3794c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTPUTIL + SCTP_LOC_5); 3795ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 3796ceaad40aSRandall Stewart if (!so_locked) { 3797ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 3798ceaad40aSRandall Stewart } 3799ceaad40aSRandall Stewart #endif 3800f8829a4aSRandall Stewart } 3801f8829a4aSRandall Stewart 3802f8829a4aSRandall Stewart void 3803f8829a4aSRandall Stewart sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh, 3804c54a18d2SRandall Stewart struct sctp_inpcb *inp, struct mbuf *op_err, uint32_t vrf_id, uint16_t port) 3805f8829a4aSRandall Stewart { 3806f8829a4aSRandall Stewart struct sctp_chunkhdr *ch, chunk_buf; 3807f8829a4aSRandall Stewart unsigned int chk_length; 3808f8829a4aSRandall Stewart 3809f8829a4aSRandall Stewart SCTP_STAT_INCR_COUNTER32(sctps_outoftheblue); 3810f8829a4aSRandall Stewart /* Generate a TO address for future reference */ 3811f8829a4aSRandall Stewart if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { 3812f8829a4aSRandall Stewart if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) { 3813b0552ae2SRandall Stewart sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, 3814b0552ae2SRandall Stewart SCTP_CALLED_DIRECTLY_NOCMPSET); 3815f8829a4aSRandall Stewart } 3816f8829a4aSRandall Stewart } 3817f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 3818f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *) & chunk_buf); 3819f8829a4aSRandall Stewart while (ch != NULL) { 3820f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 3821f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 3822f8829a4aSRandall Stewart /* break to abort land */ 3823f8829a4aSRandall Stewart break; 3824f8829a4aSRandall Stewart } 3825f8829a4aSRandall Stewart switch (ch->chunk_type) { 3826d55b0b1bSRandall Stewart case SCTP_COOKIE_ECHO: 3827d55b0b1bSRandall Stewart /* We hit here only if the assoc is being freed */ 3828d55b0b1bSRandall Stewart return; 3829f8829a4aSRandall Stewart case SCTP_PACKET_DROPPED: 3830f8829a4aSRandall Stewart /* we don't respond to pkt-dropped */ 3831f8829a4aSRandall Stewart return; 3832f8829a4aSRandall Stewart case SCTP_ABORT_ASSOCIATION: 3833f8829a4aSRandall Stewart /* we don't respond with an ABORT to an ABORT */ 3834f8829a4aSRandall Stewart return; 3835f8829a4aSRandall Stewart case SCTP_SHUTDOWN_COMPLETE: 3836f8829a4aSRandall Stewart /* 3837f8829a4aSRandall Stewart * we ignore it since we are not waiting for it and 3838f8829a4aSRandall Stewart * peer is gone 3839f8829a4aSRandall Stewart */ 3840f8829a4aSRandall Stewart return; 3841f8829a4aSRandall Stewart case SCTP_SHUTDOWN_ACK: 3842*7215cc1bSMichael Tuexen sctp_send_shutdown_complete2(m, sh, vrf_id, port); 3843f8829a4aSRandall Stewart return; 3844f8829a4aSRandall Stewart default: 3845f8829a4aSRandall Stewart break; 3846f8829a4aSRandall Stewart } 3847f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 3848f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 3849f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *) & chunk_buf); 3850f8829a4aSRandall Stewart } 3851c54a18d2SRandall Stewart sctp_send_abort(m, iphlen, sh, 0, op_err, vrf_id, port); 3852f8829a4aSRandall Stewart } 3853f8829a4aSRandall Stewart 3854f8829a4aSRandall Stewart /* 3855f8829a4aSRandall Stewart * check the inbound datagram to make sure there is not an abort inside it, 3856f8829a4aSRandall Stewart * if there is return 1, else return 0. 3857f8829a4aSRandall Stewart */ 3858f8829a4aSRandall Stewart int 3859f8829a4aSRandall Stewart sctp_is_there_an_abort_here(struct mbuf *m, int iphlen, uint32_t * vtagfill) 3860f8829a4aSRandall Stewart { 3861f8829a4aSRandall Stewart struct sctp_chunkhdr *ch; 3862f8829a4aSRandall Stewart struct sctp_init_chunk *init_chk, chunk_buf; 3863f8829a4aSRandall Stewart int offset; 3864f8829a4aSRandall Stewart unsigned int chk_length; 3865f8829a4aSRandall Stewart 3866f8829a4aSRandall Stewart offset = iphlen + sizeof(struct sctphdr); 3867f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, sizeof(*ch), 3868f8829a4aSRandall Stewart (uint8_t *) & chunk_buf); 3869f8829a4aSRandall Stewart while (ch != NULL) { 3870f8829a4aSRandall Stewart chk_length = ntohs(ch->chunk_length); 3871f8829a4aSRandall Stewart if (chk_length < sizeof(*ch)) { 3872f8829a4aSRandall Stewart /* packet is probably corrupt */ 3873f8829a4aSRandall Stewart break; 3874f8829a4aSRandall Stewart } 3875f8829a4aSRandall Stewart /* we seem to be ok, is it an abort? */ 3876f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_ABORT_ASSOCIATION) { 3877f8829a4aSRandall Stewart /* yep, tell them */ 3878f8829a4aSRandall Stewart return (1); 3879f8829a4aSRandall Stewart } 3880f8829a4aSRandall Stewart if (ch->chunk_type == SCTP_INITIATION) { 3881f8829a4aSRandall Stewart /* need to update the Vtag */ 3882f8829a4aSRandall Stewart init_chk = (struct sctp_init_chunk *)sctp_m_getptr(m, 3883f8829a4aSRandall Stewart offset, sizeof(*init_chk), (uint8_t *) & chunk_buf); 3884f8829a4aSRandall Stewart if (init_chk != NULL) { 3885f8829a4aSRandall Stewart *vtagfill = ntohl(init_chk->init.initiate_tag); 3886f8829a4aSRandall Stewart } 3887f8829a4aSRandall Stewart } 3888f8829a4aSRandall Stewart /* Nope, move to the next chunk */ 3889f8829a4aSRandall Stewart offset += SCTP_SIZE32(chk_length); 3890f8829a4aSRandall Stewart ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, offset, 3891f8829a4aSRandall Stewart sizeof(*ch), (uint8_t *) & chunk_buf); 3892f8829a4aSRandall Stewart } 3893f8829a4aSRandall Stewart return (0); 3894f8829a4aSRandall Stewart } 3895f8829a4aSRandall Stewart 3896f8829a4aSRandall Stewart /* 3897f8829a4aSRandall Stewart * currently (2/02), ifa_addr embeds scope_id's and don't have sin6_scope_id 3898f8829a4aSRandall Stewart * set (i.e. it's 0) so, create this function to compare link local scopes 3899f8829a4aSRandall Stewart */ 39005e2c2d87SRandall Stewart #ifdef INET6 3901f8829a4aSRandall Stewart uint32_t 3902f8829a4aSRandall Stewart sctp_is_same_scope(struct sockaddr_in6 *addr1, struct sockaddr_in6 *addr2) 3903f8829a4aSRandall Stewart { 3904f8829a4aSRandall Stewart struct sockaddr_in6 a, b; 3905f8829a4aSRandall Stewart 3906f8829a4aSRandall Stewart /* save copies */ 3907f8829a4aSRandall Stewart a = *addr1; 3908f8829a4aSRandall Stewart b = *addr2; 3909f8829a4aSRandall Stewart 3910f8829a4aSRandall Stewart if (a.sin6_scope_id == 0) 3911f8829a4aSRandall Stewart if (sa6_recoverscope(&a)) { 3912f8829a4aSRandall Stewart /* can't get scope, so can't match */ 3913f8829a4aSRandall Stewart return (0); 3914f8829a4aSRandall Stewart } 3915f8829a4aSRandall Stewart if (b.sin6_scope_id == 0) 3916f8829a4aSRandall Stewart if (sa6_recoverscope(&b)) { 3917f8829a4aSRandall Stewart /* can't get scope, so can't match */ 3918f8829a4aSRandall Stewart return (0); 3919f8829a4aSRandall Stewart } 3920f8829a4aSRandall Stewart if (a.sin6_scope_id != b.sin6_scope_id) 3921f8829a4aSRandall Stewart return (0); 3922f8829a4aSRandall Stewart 3923f8829a4aSRandall Stewart return (1); 3924f8829a4aSRandall Stewart } 3925f8829a4aSRandall Stewart 3926f8829a4aSRandall Stewart /* 3927f8829a4aSRandall Stewart * returns a sockaddr_in6 with embedded scope recovered and removed 3928f8829a4aSRandall Stewart */ 3929f8829a4aSRandall Stewart struct sockaddr_in6 * 3930f8829a4aSRandall Stewart sctp_recover_scope(struct sockaddr_in6 *addr, struct sockaddr_in6 *store) 3931f8829a4aSRandall Stewart { 3932f8829a4aSRandall Stewart /* check and strip embedded scope junk */ 3933f8829a4aSRandall Stewart if (addr->sin6_family == AF_INET6) { 3934f8829a4aSRandall Stewart if (IN6_IS_SCOPE_LINKLOCAL(&addr->sin6_addr)) { 3935f8829a4aSRandall Stewart if (addr->sin6_scope_id == 0) { 3936f8829a4aSRandall Stewart *store = *addr; 3937f8829a4aSRandall Stewart if (!sa6_recoverscope(store)) { 3938f8829a4aSRandall Stewart /* use the recovered scope */ 3939f8829a4aSRandall Stewart addr = store; 3940f8829a4aSRandall Stewart } 3941f42a358aSRandall Stewart } else { 3942f8829a4aSRandall Stewart /* else, return the original "to" addr */ 3943f42a358aSRandall Stewart in6_clearscope(&addr->sin6_addr); 3944f8829a4aSRandall Stewart } 3945f8829a4aSRandall Stewart } 3946f8829a4aSRandall Stewart } 3947f8829a4aSRandall Stewart return (addr); 3948f8829a4aSRandall Stewart } 3949f8829a4aSRandall Stewart 39505e2c2d87SRandall Stewart #endif 39515e2c2d87SRandall Stewart 3952f8829a4aSRandall Stewart /* 3953f8829a4aSRandall Stewart * are the two addresses the same? currently a "scopeless" check returns: 1 3954f8829a4aSRandall Stewart * if same, 0 if not 3955f8829a4aSRandall Stewart */ 395672fb6fdbSRandall Stewart int 3957f8829a4aSRandall Stewart sctp_cmpaddr(struct sockaddr *sa1, struct sockaddr *sa2) 3958f8829a4aSRandall Stewart { 3959f8829a4aSRandall Stewart 3960f8829a4aSRandall Stewart /* must be valid */ 3961f8829a4aSRandall Stewart if (sa1 == NULL || sa2 == NULL) 3962f8829a4aSRandall Stewart return (0); 3963f8829a4aSRandall Stewart 3964f8829a4aSRandall Stewart /* must be the same family */ 3965f8829a4aSRandall Stewart if (sa1->sa_family != sa2->sa_family) 3966f8829a4aSRandall Stewart return (0); 3967f8829a4aSRandall Stewart 39685e2c2d87SRandall Stewart switch (sa1->sa_family) { 39695e2c2d87SRandall Stewart #ifdef INET6 39705e2c2d87SRandall Stewart case AF_INET6: 39715e2c2d87SRandall Stewart { 3972f8829a4aSRandall Stewart /* IPv6 addresses */ 3973f8829a4aSRandall Stewart struct sockaddr_in6 *sin6_1, *sin6_2; 3974f8829a4aSRandall Stewart 3975f8829a4aSRandall Stewart sin6_1 = (struct sockaddr_in6 *)sa1; 3976f8829a4aSRandall Stewart sin6_2 = (struct sockaddr_in6 *)sa2; 3977c54a18d2SRandall Stewart return (SCTP6_ARE_ADDR_EQUAL(sin6_1, 3978c54a18d2SRandall Stewart sin6_2)); 39795e2c2d87SRandall Stewart } 39805e2c2d87SRandall Stewart #endif 3981ea5eba11SMichael Tuexen #ifdef INET 39825e2c2d87SRandall Stewart case AF_INET: 39835e2c2d87SRandall Stewart { 3984f8829a4aSRandall Stewart /* IPv4 addresses */ 3985f8829a4aSRandall Stewart struct sockaddr_in *sin_1, *sin_2; 3986f8829a4aSRandall Stewart 3987f8829a4aSRandall Stewart sin_1 = (struct sockaddr_in *)sa1; 3988f8829a4aSRandall Stewart sin_2 = (struct sockaddr_in *)sa2; 3989f8829a4aSRandall Stewart return (sin_1->sin_addr.s_addr == sin_2->sin_addr.s_addr); 39905e2c2d87SRandall Stewart } 3991ea5eba11SMichael Tuexen #endif 39925e2c2d87SRandall Stewart default: 3993f8829a4aSRandall Stewart /* we don't do these... */ 3994f8829a4aSRandall Stewart return (0); 3995f8829a4aSRandall Stewart } 3996f8829a4aSRandall Stewart } 3997f8829a4aSRandall Stewart 3998f8829a4aSRandall Stewart void 3999f8829a4aSRandall Stewart sctp_print_address(struct sockaddr *sa) 4000f8829a4aSRandall Stewart { 40015e2c2d87SRandall Stewart #ifdef INET6 40027d32aa0cSBjoern A. Zeeb char ip6buf[INET6_ADDRSTRLEN]; 4003f8829a4aSRandall Stewart 4004ad81507eSRandall Stewart ip6buf[0] = 0; 40055e2c2d87SRandall Stewart #endif 40065e2c2d87SRandall Stewart 40075e2c2d87SRandall Stewart switch (sa->sa_family) { 40085e2c2d87SRandall Stewart #ifdef INET6 40095e2c2d87SRandall Stewart case AF_INET6: 40105e2c2d87SRandall Stewart { 4011ad81507eSRandall Stewart struct sockaddr_in6 *sin6; 4012ad81507eSRandall Stewart 4013f8829a4aSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 4014ad81507eSRandall Stewart SCTP_PRINTF("IPv6 address: %s:port:%d scope:%u\n", 40157d32aa0cSBjoern A. Zeeb ip6_sprintf(ip6buf, &sin6->sin6_addr), 40167d32aa0cSBjoern A. Zeeb ntohs(sin6->sin6_port), 4017f8829a4aSRandall Stewart sin6->sin6_scope_id); 40185e2c2d87SRandall Stewart break; 40195e2c2d87SRandall Stewart } 40205e2c2d87SRandall Stewart #endif 4021ea5eba11SMichael Tuexen #ifdef INET 40225e2c2d87SRandall Stewart case AF_INET: 40235e2c2d87SRandall Stewart { 4024f8829a4aSRandall Stewart struct sockaddr_in *sin; 4025f8829a4aSRandall Stewart unsigned char *p; 4026f8829a4aSRandall Stewart 4027f8829a4aSRandall Stewart sin = (struct sockaddr_in *)sa; 4028f8829a4aSRandall Stewart p = (unsigned char *)&sin->sin_addr; 4029ad81507eSRandall Stewart SCTP_PRINTF("IPv4 address: %u.%u.%u.%u:%d\n", 4030f8829a4aSRandall Stewart p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); 40315e2c2d87SRandall Stewart break; 40325e2c2d87SRandall Stewart } 4033ea5eba11SMichael Tuexen #endif 40345e2c2d87SRandall Stewart default: 4035ad81507eSRandall Stewart SCTP_PRINTF("?\n"); 40365e2c2d87SRandall Stewart break; 4037f8829a4aSRandall Stewart } 4038f8829a4aSRandall Stewart } 4039f8829a4aSRandall Stewart 4040f8829a4aSRandall Stewart void 4041f8829a4aSRandall Stewart sctp_print_address_pkt(struct ip *iph, struct sctphdr *sh) 4042f8829a4aSRandall Stewart { 40435e2c2d87SRandall Stewart switch (iph->ip_v) { 4044ea5eba11SMichael Tuexen #ifdef INET 40455e2c2d87SRandall Stewart case IPVERSION: 40465e2c2d87SRandall Stewart { 4047f8829a4aSRandall Stewart struct sockaddr_in lsa, fsa; 4048f8829a4aSRandall Stewart 4049f8829a4aSRandall Stewart bzero(&lsa, sizeof(lsa)); 4050f8829a4aSRandall Stewart lsa.sin_len = sizeof(lsa); 4051f8829a4aSRandall Stewart lsa.sin_family = AF_INET; 4052f8829a4aSRandall Stewart lsa.sin_addr = iph->ip_src; 4053f8829a4aSRandall Stewart lsa.sin_port = sh->src_port; 4054f8829a4aSRandall Stewart bzero(&fsa, sizeof(fsa)); 4055f8829a4aSRandall Stewart fsa.sin_len = sizeof(fsa); 4056f8829a4aSRandall Stewart fsa.sin_family = AF_INET; 4057f8829a4aSRandall Stewart fsa.sin_addr = iph->ip_dst; 4058f8829a4aSRandall Stewart fsa.sin_port = sh->dest_port; 4059ad81507eSRandall Stewart SCTP_PRINTF("src: "); 4060f8829a4aSRandall Stewart sctp_print_address((struct sockaddr *)&lsa); 4061ad81507eSRandall Stewart SCTP_PRINTF("dest: "); 4062f8829a4aSRandall Stewart sctp_print_address((struct sockaddr *)&fsa); 40635e2c2d87SRandall Stewart break; 40645e2c2d87SRandall Stewart } 4065ea5eba11SMichael Tuexen #endif 40665e2c2d87SRandall Stewart #ifdef INET6 40675e2c2d87SRandall Stewart case IPV6_VERSION >> 4: 40685e2c2d87SRandall Stewart { 4069f8829a4aSRandall Stewart struct ip6_hdr *ip6; 4070f8829a4aSRandall Stewart struct sockaddr_in6 lsa6, fsa6; 4071f8829a4aSRandall Stewart 4072f8829a4aSRandall Stewart ip6 = (struct ip6_hdr *)iph; 4073f8829a4aSRandall Stewart bzero(&lsa6, sizeof(lsa6)); 4074f8829a4aSRandall Stewart lsa6.sin6_len = sizeof(lsa6); 4075f8829a4aSRandall Stewart lsa6.sin6_family = AF_INET6; 4076f8829a4aSRandall Stewart lsa6.sin6_addr = ip6->ip6_src; 4077f8829a4aSRandall Stewart lsa6.sin6_port = sh->src_port; 4078f8829a4aSRandall Stewart bzero(&fsa6, sizeof(fsa6)); 4079f8829a4aSRandall Stewart fsa6.sin6_len = sizeof(fsa6); 4080f8829a4aSRandall Stewart fsa6.sin6_family = AF_INET6; 4081f8829a4aSRandall Stewart fsa6.sin6_addr = ip6->ip6_dst; 4082f8829a4aSRandall Stewart fsa6.sin6_port = sh->dest_port; 4083ad81507eSRandall Stewart SCTP_PRINTF("src: "); 4084f8829a4aSRandall Stewart sctp_print_address((struct sockaddr *)&lsa6); 4085ad81507eSRandall Stewart SCTP_PRINTF("dest: "); 4086f8829a4aSRandall Stewart sctp_print_address((struct sockaddr *)&fsa6); 40875e2c2d87SRandall Stewart break; 40885e2c2d87SRandall Stewart } 40895e2c2d87SRandall Stewart #endif 40905e2c2d87SRandall Stewart default: 40915e2c2d87SRandall Stewart /* TSNH */ 40925e2c2d87SRandall Stewart break; 4093f8829a4aSRandall Stewart } 4094f8829a4aSRandall Stewart } 4095f8829a4aSRandall Stewart 4096f8829a4aSRandall Stewart void 4097f8829a4aSRandall Stewart sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp, 4098f8829a4aSRandall Stewart struct sctp_inpcb *new_inp, 4099d06c82f1SRandall Stewart struct sctp_tcb *stcb, 4100d06c82f1SRandall Stewart int waitflags) 4101f8829a4aSRandall Stewart { 4102f8829a4aSRandall Stewart /* 4103f8829a4aSRandall Stewart * go through our old INP and pull off any control structures that 4104f8829a4aSRandall Stewart * belong to stcb and move then to the new inp. 4105f8829a4aSRandall Stewart */ 4106f8829a4aSRandall Stewart struct socket *old_so, *new_so; 4107f8829a4aSRandall Stewart struct sctp_queued_to_read *control, *nctl; 4108f8829a4aSRandall Stewart struct sctp_readhead tmp_queue; 4109f8829a4aSRandall Stewart struct mbuf *m; 4110bff64a4dSRandall Stewart int error = 0; 4111f8829a4aSRandall Stewart 4112f8829a4aSRandall Stewart old_so = old_inp->sctp_socket; 4113f8829a4aSRandall Stewart new_so = new_inp->sctp_socket; 4114f8829a4aSRandall Stewart TAILQ_INIT(&tmp_queue); 4115d06c82f1SRandall Stewart error = sblock(&old_so->so_rcv, waitflags); 4116f8829a4aSRandall Stewart if (error) { 4117f8829a4aSRandall Stewart /* 4118f8829a4aSRandall Stewart * Gak, can't get sblock, we have a problem. data will be 4119f8829a4aSRandall Stewart * left stranded.. and we don't dare look at it since the 4120f8829a4aSRandall Stewart * other thread may be reading something. Oh well, its a 4121f8829a4aSRandall Stewart * screwed up app that does a peeloff OR a accept while 4122f8829a4aSRandall Stewart * reading from the main socket... actually its only the 4123f8829a4aSRandall Stewart * peeloff() case, since I think read will fail on a 4124f8829a4aSRandall Stewart * listening socket.. 4125f8829a4aSRandall Stewart */ 4126f8829a4aSRandall Stewart return; 4127f8829a4aSRandall Stewart } 4128f8829a4aSRandall Stewart /* lock the socket buffers */ 4129f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(old_inp); 41304a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &old_inp->read_queue, next, nctl) { 4131f8829a4aSRandall Stewart /* Pull off all for out target stcb */ 4132f8829a4aSRandall Stewart if (control->stcb == stcb) { 4133f8829a4aSRandall Stewart /* remove it we want it */ 4134f8829a4aSRandall Stewart TAILQ_REMOVE(&old_inp->read_queue, control, next); 4135f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&tmp_queue, control, next); 4136f8829a4aSRandall Stewart m = control->data; 4137f8829a4aSRandall Stewart while (m) { 4138b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4139139bc87fSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 414080fefe0aSRandall Stewart } 4141f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &old_so->so_rcv, m); 4142b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4143f8829a4aSRandall Stewart sctp_sblog(&old_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 414480fefe0aSRandall Stewart } 4145139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4146f8829a4aSRandall Stewart } 4147f8829a4aSRandall Stewart } 4148f8829a4aSRandall Stewart } 4149f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(old_inp); 4150f8829a4aSRandall Stewart /* Remove the sb-lock on the old socket */ 4151f8829a4aSRandall Stewart 4152f8829a4aSRandall Stewart sbunlock(&old_so->so_rcv); 4153f8829a4aSRandall Stewart /* Now we move them over to the new socket buffer */ 4154f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(new_inp); 41554a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(control, &tmp_queue, next, nctl) { 4156f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&new_inp->read_queue, control, next); 4157f8829a4aSRandall Stewart m = control->data; 4158f8829a4aSRandall Stewart while (m) { 4159b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4160139bc87fSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 416180fefe0aSRandall Stewart } 4162f8829a4aSRandall Stewart sctp_sballoc(stcb, &new_so->so_rcv, m); 4163b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4164f8829a4aSRandall Stewart sctp_sblog(&new_so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 416580fefe0aSRandall Stewart } 4166139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4167f8829a4aSRandall Stewart } 4168f8829a4aSRandall Stewart } 4169f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(new_inp); 4170f8829a4aSRandall Stewart } 4171f8829a4aSRandall Stewart 4172f8829a4aSRandall Stewart void 4173f8829a4aSRandall Stewart sctp_add_to_readq(struct sctp_inpcb *inp, 4174f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4175f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4176f8829a4aSRandall Stewart struct sockbuf *sb, 4177ceaad40aSRandall Stewart int end, 4178cfde3ff7SRandall Stewart int inp_read_lock_held, 4179ceaad40aSRandall Stewart int so_locked 4180ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4181ceaad40aSRandall Stewart SCTP_UNUSED 4182ceaad40aSRandall Stewart #endif 4183ceaad40aSRandall Stewart ) 4184f8829a4aSRandall Stewart { 4185f8829a4aSRandall Stewart /* 4186f8829a4aSRandall Stewart * Here we must place the control on the end of the socket read 4187f8829a4aSRandall Stewart * queue AND increment sb_cc so that select will work properly on 4188f8829a4aSRandall Stewart * read. 4189f8829a4aSRandall Stewart */ 4190f8829a4aSRandall Stewart struct mbuf *m, *prev = NULL; 4191f8829a4aSRandall Stewart 419203b0b021SRandall Stewart if (inp == NULL) { 419303b0b021SRandall Stewart /* Gak, TSNH!! */ 4194a5d547adSRandall Stewart #ifdef INVARIANTS 419503b0b021SRandall Stewart panic("Gak, inp NULL on add_to_readq"); 419603b0b021SRandall Stewart #endif 419703b0b021SRandall Stewart return; 419803b0b021SRandall Stewart } 4199cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4200f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4201cd1386abSMichael Tuexen if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ) { 4202cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4203cd1386abSMichael Tuexen if (control->data) { 4204cd1386abSMichael Tuexen sctp_m_freem(control->data); 4205cd1386abSMichael Tuexen control->data = NULL; 4206cd1386abSMichael Tuexen } 4207cd1386abSMichael Tuexen SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control); 4208cd1386abSMichael Tuexen if (inp_read_lock_held == 0) 4209cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4210cd1386abSMichael Tuexen return; 4211cd1386abSMichael Tuexen } 421242551e99SRandall Stewart if (!(control->spec_flags & M_NOTIFICATION)) { 4213a5d547adSRandall Stewart atomic_add_int(&inp->total_recvs, 1); 421442551e99SRandall Stewart if (!control->do_not_ref_stcb) { 4215a5d547adSRandall Stewart atomic_add_int(&stcb->total_recvs, 1); 421642551e99SRandall Stewart } 421742551e99SRandall Stewart } 4218f8829a4aSRandall Stewart m = control->data; 4219f8829a4aSRandall Stewart control->held_length = 0; 4220f8829a4aSRandall Stewart control->length = 0; 4221f8829a4aSRandall Stewart while (m) { 4222139bc87fSRandall Stewart if (SCTP_BUF_LEN(m) == 0) { 4223f8829a4aSRandall Stewart /* Skip mbufs with NO length */ 4224f8829a4aSRandall Stewart if (prev == NULL) { 4225f8829a4aSRandall Stewart /* First one */ 4226f8829a4aSRandall Stewart control->data = sctp_m_free(m); 4227f8829a4aSRandall Stewart m = control->data; 4228f8829a4aSRandall Stewart } else { 4229139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(m); 4230139bc87fSRandall Stewart m = SCTP_BUF_NEXT(prev); 4231f8829a4aSRandall Stewart } 4232f8829a4aSRandall Stewart if (m == NULL) { 4233c2ede4b3SMartin Blapp control->tail_mbuf = prev; 4234f8829a4aSRandall Stewart } 4235f8829a4aSRandall Stewart continue; 4236f8829a4aSRandall Stewart } 4237f8829a4aSRandall Stewart prev = m; 4238b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4239139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(m)); 424080fefe0aSRandall Stewart } 4241f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, m); 4242b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4243f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 424480fefe0aSRandall Stewart } 4245139bc87fSRandall Stewart atomic_add_int(&control->length, SCTP_BUF_LEN(m)); 4246139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 4247f8829a4aSRandall Stewart } 4248f8829a4aSRandall Stewart if (prev != NULL) { 4249f8829a4aSRandall Stewart control->tail_mbuf = prev; 4250f8829a4aSRandall Stewart } else { 4251139bc87fSRandall Stewart /* Everything got collapsed out?? */ 4252cd1386abSMichael Tuexen sctp_free_remote_addr(control->whoFrom); 4253cd1386abSMichael Tuexen SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_readq), control); 4254cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 425547a490cbSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4256f8829a4aSRandall Stewart return; 4257f8829a4aSRandall Stewart } 4258f8829a4aSRandall Stewart if (end) { 4259f8829a4aSRandall Stewart control->end_added = 1; 4260f8829a4aSRandall Stewart } 4261f8829a4aSRandall Stewart TAILQ_INSERT_TAIL(&inp->read_queue, control, next); 4262cfde3ff7SRandall Stewart if (inp_read_lock_held == 0) 4263f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4264f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 426517205eccSRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 426617205eccSRandall Stewart SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); 4267ceaad40aSRandall Stewart } else { 4268ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4269ceaad40aSRandall Stewart struct socket *so; 4270ceaad40aSRandall Stewart 4271ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4272ceaad40aSRandall Stewart if (!so_locked) { 4273ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4274ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4275ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4276ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4277ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4278ceaad40aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4279ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4280ceaad40aSRandall Stewart return; 4281ceaad40aSRandall Stewart } 4282ceaad40aSRandall Stewart } 4283ceaad40aSRandall Stewart #endif 4284f8829a4aSRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 4285ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4286ceaad40aSRandall Stewart if (!so_locked) { 4287ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4288ceaad40aSRandall Stewart } 4289ceaad40aSRandall Stewart #endif 4290ceaad40aSRandall Stewart } 4291f8829a4aSRandall Stewart } 4292f8829a4aSRandall Stewart } 4293f8829a4aSRandall Stewart 4294f8829a4aSRandall Stewart 4295f8829a4aSRandall Stewart int 4296f8829a4aSRandall Stewart sctp_append_to_readq(struct sctp_inpcb *inp, 4297f8829a4aSRandall Stewart struct sctp_tcb *stcb, 4298f8829a4aSRandall Stewart struct sctp_queued_to_read *control, 4299f8829a4aSRandall Stewart struct mbuf *m, 4300f8829a4aSRandall Stewart int end, 4301f8829a4aSRandall Stewart int ctls_cumack, 4302f8829a4aSRandall Stewart struct sockbuf *sb) 4303f8829a4aSRandall Stewart { 4304f8829a4aSRandall Stewart /* 4305f8829a4aSRandall Stewart * A partial delivery API event is underway. OR we are appending on 4306f8829a4aSRandall Stewart * the reassembly queue. 4307f8829a4aSRandall Stewart * 4308f8829a4aSRandall Stewart * If PDAPI this means we need to add m to the end of the data. 4309f8829a4aSRandall Stewart * Increase the length in the control AND increment the sb_cc. 4310f8829a4aSRandall Stewart * Otherwise sb is NULL and all we need to do is put it at the end 4311f8829a4aSRandall Stewart * of the mbuf chain. 4312f8829a4aSRandall Stewart */ 4313f8829a4aSRandall Stewart int len = 0; 4314f8829a4aSRandall Stewart struct mbuf *mm, *tail = NULL, *prev = NULL; 4315f8829a4aSRandall Stewart 4316f8829a4aSRandall Stewart if (inp) { 4317f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 4318f8829a4aSRandall Stewart } 4319f8829a4aSRandall Stewart if (control == NULL) { 4320f8829a4aSRandall Stewart get_out: 4321f8829a4aSRandall Stewart if (inp) { 4322f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4323f8829a4aSRandall Stewart } 4324f8829a4aSRandall Stewart return (-1); 4325f8829a4aSRandall Stewart } 4326cd1386abSMichael Tuexen if (inp && (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_CANT_READ)) { 4327cd1386abSMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 4328cd1386abSMichael Tuexen return 0; 4329cd1386abSMichael Tuexen } 4330139bc87fSRandall Stewart if (control->end_added) { 4331f8829a4aSRandall Stewart /* huh this one is complete? */ 4332f8829a4aSRandall Stewart goto get_out; 4333f8829a4aSRandall Stewart } 4334f8829a4aSRandall Stewart mm = m; 4335f8829a4aSRandall Stewart if (mm == NULL) { 4336f8829a4aSRandall Stewart goto get_out; 4337f8829a4aSRandall Stewart } 4338f8829a4aSRandall Stewart while (mm) { 4339139bc87fSRandall Stewart if (SCTP_BUF_LEN(mm) == 0) { 4340f8829a4aSRandall Stewart /* Skip mbufs with NO lenght */ 4341f8829a4aSRandall Stewart if (prev == NULL) { 4342f8829a4aSRandall Stewart /* First one */ 4343f8829a4aSRandall Stewart m = sctp_m_free(mm); 4344f8829a4aSRandall Stewart mm = m; 4345f8829a4aSRandall Stewart } else { 4346139bc87fSRandall Stewart SCTP_BUF_NEXT(prev) = sctp_m_free(mm); 4347139bc87fSRandall Stewart mm = SCTP_BUF_NEXT(prev); 4348f8829a4aSRandall Stewart } 4349f8829a4aSRandall Stewart continue; 4350f8829a4aSRandall Stewart } 4351f8829a4aSRandall Stewart prev = mm; 4352139bc87fSRandall Stewart len += SCTP_BUF_LEN(mm); 4353f8829a4aSRandall Stewart if (sb) { 4354b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4355139bc87fSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBALLOC, SCTP_BUF_LEN(mm)); 435680fefe0aSRandall Stewart } 4357f8829a4aSRandall Stewart sctp_sballoc(stcb, sb, mm); 4358b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 4359f8829a4aSRandall Stewart sctp_sblog(sb, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 436080fefe0aSRandall Stewart } 4361f8829a4aSRandall Stewart } 4362139bc87fSRandall Stewart mm = SCTP_BUF_NEXT(mm); 4363f8829a4aSRandall Stewart } 4364f8829a4aSRandall Stewart if (prev) { 4365f8829a4aSRandall Stewart tail = prev; 4366f8829a4aSRandall Stewart } else { 4367f8829a4aSRandall Stewart /* Really there should always be a prev */ 4368f8829a4aSRandall Stewart if (m == NULL) { 4369f8829a4aSRandall Stewart /* Huh nothing left? */ 4370a5d547adSRandall Stewart #ifdef INVARIANTS 4371f8829a4aSRandall Stewart panic("Nothing left to add?"); 4372f8829a4aSRandall Stewart #else 4373f8829a4aSRandall Stewart goto get_out; 4374f8829a4aSRandall Stewart #endif 4375f8829a4aSRandall Stewart } 4376f8829a4aSRandall Stewart tail = m; 4377f8829a4aSRandall Stewart } 4378f8829a4aSRandall Stewart if (control->tail_mbuf) { 4379f8829a4aSRandall Stewart /* append */ 4380139bc87fSRandall Stewart SCTP_BUF_NEXT(control->tail_mbuf) = m; 4381f8829a4aSRandall Stewart control->tail_mbuf = tail; 4382f8829a4aSRandall Stewart } else { 4383f8829a4aSRandall Stewart /* nothing there */ 4384a5d547adSRandall Stewart #ifdef INVARIANTS 4385f8829a4aSRandall Stewart if (control->data != NULL) { 4386f8829a4aSRandall Stewart panic("This should NOT happen"); 4387f8829a4aSRandall Stewart } 4388f8829a4aSRandall Stewart #endif 4389f8829a4aSRandall Stewart control->data = m; 4390f8829a4aSRandall Stewart control->tail_mbuf = tail; 4391f8829a4aSRandall Stewart } 439218e198d3SRandall Stewart atomic_add_int(&control->length, len); 439318e198d3SRandall Stewart if (end) { 439418e198d3SRandall Stewart /* message is complete */ 439518e198d3SRandall Stewart if (stcb && (control == stcb->asoc.control_pdapi)) { 439618e198d3SRandall Stewart stcb->asoc.control_pdapi = NULL; 439718e198d3SRandall Stewart } 439818e198d3SRandall Stewart control->held_length = 0; 439918e198d3SRandall Stewart control->end_added = 1; 440018e198d3SRandall Stewart } 4401ad81507eSRandall Stewart if (stcb == NULL) { 4402ad81507eSRandall Stewart control->do_not_ref_stcb = 1; 4403ad81507eSRandall Stewart } 4404f8829a4aSRandall Stewart /* 4405f8829a4aSRandall Stewart * When we are appending in partial delivery, the cum-ack is used 4406f8829a4aSRandall Stewart * for the actual pd-api highest tsn on this mbuf. The true cum-ack 4407f8829a4aSRandall Stewart * is populated in the outbound sinfo structure from the true cumack 4408f8829a4aSRandall Stewart * if the association exists... 4409f8829a4aSRandall Stewart */ 4410f8829a4aSRandall Stewart control->sinfo_tsn = control->sinfo_cumtsn = ctls_cumack; 4411f8829a4aSRandall Stewart if (inp) { 4412f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 4413f8829a4aSRandall Stewart } 4414f8829a4aSRandall Stewart if (inp && inp->sctp_socket) { 441517205eccSRandall Stewart if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) { 441617205eccSRandall Stewart SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket); 4417ceaad40aSRandall Stewart } else { 4418ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4419ceaad40aSRandall Stewart struct socket *so; 4420ceaad40aSRandall Stewart 4421ceaad40aSRandall Stewart so = SCTP_INP_SO(inp); 4422ceaad40aSRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4423ceaad40aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4424ceaad40aSRandall Stewart SCTP_SOCKET_LOCK(so, 1); 4425ceaad40aSRandall Stewart SCTP_TCB_LOCK(stcb); 4426ceaad40aSRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 4427ceaad40aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 4428ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4429ceaad40aSRandall Stewart return (0); 4430ceaad40aSRandall Stewart } 4431ceaad40aSRandall Stewart #endif 4432f8829a4aSRandall Stewart sctp_sorwakeup(inp, inp->sctp_socket); 4433ceaad40aSRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 4434ceaad40aSRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 4435ceaad40aSRandall Stewart #endif 4436ceaad40aSRandall Stewart } 4437f8829a4aSRandall Stewart } 4438f8829a4aSRandall Stewart return (0); 4439f8829a4aSRandall Stewart } 4440f8829a4aSRandall Stewart 4441f8829a4aSRandall Stewart 4442f8829a4aSRandall Stewart 4443f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR PATCH FILE OF 4444f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4445f8829a4aSRandall Stewart */ 4446f8829a4aSRandall Stewart 4447f8829a4aSRandall Stewart /*************HOLD THIS COMMENT FOR END OF PATCH FILE OF 4448f8829a4aSRandall Stewart *************ALTERNATE ROUTING CODE 4449f8829a4aSRandall Stewart */ 4450f8829a4aSRandall Stewart 4451f8829a4aSRandall Stewart struct mbuf * 4452f8829a4aSRandall Stewart sctp_generate_invmanparam(int err) 4453f8829a4aSRandall Stewart { 4454f8829a4aSRandall Stewart /* Return a MBUF with a invalid mandatory parameter */ 4455f8829a4aSRandall Stewart struct mbuf *m; 4456f8829a4aSRandall Stewart 4457f8829a4aSRandall Stewart m = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_DONTWAIT, 1, MT_DATA); 4458f8829a4aSRandall Stewart if (m) { 4459f8829a4aSRandall Stewart struct sctp_paramhdr *ph; 4460f8829a4aSRandall Stewart 4461139bc87fSRandall Stewart SCTP_BUF_LEN(m) = sizeof(struct sctp_paramhdr); 4462f8829a4aSRandall Stewart ph = mtod(m, struct sctp_paramhdr *); 4463f8829a4aSRandall Stewart ph->param_length = htons(sizeof(struct sctp_paramhdr)); 4464f8829a4aSRandall Stewart ph->param_type = htons(err); 4465f8829a4aSRandall Stewart } 4466f8829a4aSRandall Stewart return (m); 4467f8829a4aSRandall Stewart } 4468f8829a4aSRandall Stewart 4469f8829a4aSRandall Stewart #ifdef SCTP_MBCNT_LOGGING 4470f8829a4aSRandall Stewart void 4471f8829a4aSRandall Stewart sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc, 4472f8829a4aSRandall Stewart struct sctp_tmit_chunk *tp1, int chk_cnt) 4473f8829a4aSRandall Stewart { 4474f8829a4aSRandall Stewart if (tp1->data == NULL) { 4475f8829a4aSRandall Stewart return; 4476f8829a4aSRandall Stewart } 4477f8829a4aSRandall Stewart asoc->chunks_on_out_queue -= chk_cnt; 4478b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBCNT_LOGGING_ENABLE) { 4479f8829a4aSRandall Stewart sctp_log_mbcnt(SCTP_LOG_MBCNT_DECREASE, 4480f8829a4aSRandall Stewart asoc->total_output_queue_size, 4481f8829a4aSRandall Stewart tp1->book_size, 4482f8829a4aSRandall Stewart 0, 4483f8829a4aSRandall Stewart tp1->mbcnt); 448480fefe0aSRandall Stewart } 4485f8829a4aSRandall Stewart if (asoc->total_output_queue_size >= tp1->book_size) { 448644b7479bSRandall Stewart atomic_add_int(&asoc->total_output_queue_size, -tp1->book_size); 4487f8829a4aSRandall Stewart } else { 4488f8829a4aSRandall Stewart asoc->total_output_queue_size = 0; 4489f8829a4aSRandall Stewart } 4490f8829a4aSRandall Stewart 4491f8829a4aSRandall Stewart if (stcb->sctp_socket && (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) || 4492f8829a4aSRandall Stewart ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE)))) { 4493f8829a4aSRandall Stewart if (stcb->sctp_socket->so_snd.sb_cc >= tp1->book_size) { 4494f8829a4aSRandall Stewart stcb->sctp_socket->so_snd.sb_cc -= tp1->book_size; 4495f8829a4aSRandall Stewart } else { 4496f8829a4aSRandall Stewart stcb->sctp_socket->so_snd.sb_cc = 0; 4497f8829a4aSRandall Stewart 4498f8829a4aSRandall Stewart } 4499f8829a4aSRandall Stewart } 4500f8829a4aSRandall Stewart } 4501f8829a4aSRandall Stewart 4502f8829a4aSRandall Stewart #endif 4503f8829a4aSRandall Stewart 4504f8829a4aSRandall Stewart int 4505f8829a4aSRandall Stewart sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1, 45060c0982b8SRandall Stewart int reason, int so_locked 4507ceaad40aSRandall Stewart #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) 4508ceaad40aSRandall Stewart SCTP_UNUSED 4509ceaad40aSRandall Stewart #endif 4510ceaad40aSRandall Stewart ) 4511f8829a4aSRandall Stewart { 45120c0982b8SRandall Stewart struct sctp_stream_out *strq; 45134a9ef3f8SMichael Tuexen struct sctp_tmit_chunk *chk = NULL, *tp2; 45140c0982b8SRandall Stewart struct sctp_stream_queue_pending *sp; 45150c0982b8SRandall Stewart uint16_t stream = 0, seq = 0; 45160c0982b8SRandall Stewart uint8_t foundeom = 0; 4517f8829a4aSRandall Stewart int ret_sz = 0; 4518f8829a4aSRandall Stewart int notdone; 45190c0982b8SRandall Stewart int do_wakeup_routine = 0; 4520f8829a4aSRandall Stewart 45210c0982b8SRandall Stewart stream = tp1->rec.data.stream_number; 45220c0982b8SRandall Stewart seq = tp1->rec.data.stream_seq; 4523f8829a4aSRandall Stewart do { 4524f8829a4aSRandall Stewart ret_sz += tp1->book_size; 45250c0982b8SRandall Stewart if (tp1->data != NULL) { 45268933fa13SRandall Stewart if (tp1->sent < SCTP_DATAGRAM_RESEND) { 4527830d754dSRandall Stewart sctp_flight_size_decrease(tp1); 4528830d754dSRandall Stewart sctp_total_flight_decrease(stcb, tp1); 45298933fa13SRandall Stewart } 45308933fa13SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 45310c0982b8SRandall Stewart stcb->asoc.peers_rwnd += tp1->send_size; 45320c0982b8SRandall Stewart stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); 4533830d754dSRandall Stewart sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked); 45342f99457bSMichael Tuexen if (tp1->data) { 4535f8829a4aSRandall Stewart sctp_m_freem(tp1->data); 4536f8829a4aSRandall Stewart tp1->data = NULL; 45372f99457bSMichael Tuexen } 45380c0982b8SRandall Stewart do_wakeup_routine = 1; 4539f8829a4aSRandall Stewart if (PR_SCTP_BUF_ENABLED(tp1->flags)) { 4540f8829a4aSRandall Stewart stcb->asoc.sent_queue_cnt_removeable--; 4541f8829a4aSRandall Stewart } 4542f8829a4aSRandall Stewart } 45438933fa13SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 4544f8829a4aSRandall Stewart if ((tp1->rec.data.rcv_flags & SCTP_DATA_NOT_FRAG) == 4545f8829a4aSRandall Stewart SCTP_DATA_NOT_FRAG) { 4546f8829a4aSRandall Stewart /* not frag'ed we ae done */ 4547f8829a4aSRandall Stewart notdone = 0; 4548f8829a4aSRandall Stewart foundeom = 1; 4549f8829a4aSRandall Stewart } else if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 4550f8829a4aSRandall Stewart /* end of frag, we are done */ 4551f8829a4aSRandall Stewart notdone = 0; 4552f8829a4aSRandall Stewart foundeom = 1; 4553f8829a4aSRandall Stewart } else { 4554f8829a4aSRandall Stewart /* 4555f8829a4aSRandall Stewart * Its a begin or middle piece, we must mark all of 4556f8829a4aSRandall Stewart * it 4557f8829a4aSRandall Stewart */ 4558f8829a4aSRandall Stewart notdone = 1; 4559f8829a4aSRandall Stewart tp1 = TAILQ_NEXT(tp1, sctp_next); 4560f8829a4aSRandall Stewart } 4561f8829a4aSRandall Stewart } while (tp1 && notdone); 45620c0982b8SRandall Stewart if (foundeom == 0) { 4563f8829a4aSRandall Stewart /* 4564f8829a4aSRandall Stewart * The multi-part message was scattered across the send and 4565f8829a4aSRandall Stewart * sent queue. 4566f8829a4aSRandall Stewart */ 45674a9ef3f8SMichael Tuexen TAILQ_FOREACH_SAFE(tp1, &stcb->asoc.send_queue, sctp_next, tp2) { 45684a9ef3f8SMichael Tuexen if ((tp1->rec.data.stream_number != stream) || 45694a9ef3f8SMichael Tuexen (tp1->rec.data.stream_seq != seq)) { 45704a9ef3f8SMichael Tuexen break; 45714a9ef3f8SMichael Tuexen } 45720c0982b8SRandall Stewart /* 45730c0982b8SRandall Stewart * save to chk in case we have some on stream out 45740c0982b8SRandall Stewart * queue. If so and we have an un-transmitted one we 45750c0982b8SRandall Stewart * don't have to fudge the TSN. 45760c0982b8SRandall Stewart */ 45770c0982b8SRandall Stewart chk = tp1; 45780c0982b8SRandall Stewart ret_sz += tp1->book_size; 45790c0982b8SRandall Stewart sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1); 45802f99457bSMichael Tuexen sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, so_locked); 45812f99457bSMichael Tuexen if (tp1->data) { 45820c0982b8SRandall Stewart sctp_m_freem(tp1->data); 45832f99457bSMichael Tuexen tp1->data = NULL; 45842f99457bSMichael Tuexen } 45858933fa13SRandall Stewart /* No flight involved here book the size to 0 */ 45868933fa13SRandall Stewart tp1->book_size = 0; 45870c0982b8SRandall Stewart if (tp1->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG) { 45880c0982b8SRandall Stewart foundeom = 1; 4589f8829a4aSRandall Stewart } 45900c0982b8SRandall Stewart do_wakeup_routine = 1; 45910c0982b8SRandall Stewart tp1->sent = SCTP_FORWARD_TSN_SKIP; 45920c0982b8SRandall Stewart TAILQ_REMOVE(&stcb->asoc.send_queue, tp1, sctp_next); 45930c0982b8SRandall Stewart /* 45940c0982b8SRandall Stewart * on to the sent queue so we can wait for it to be 45950c0982b8SRandall Stewart * passed by. 45960c0982b8SRandall Stewart */ 45970c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, tp1, 45980c0982b8SRandall Stewart sctp_next); 45990c0982b8SRandall Stewart stcb->asoc.send_queue_cnt--; 46000c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 46010c0982b8SRandall Stewart } 46020c0982b8SRandall Stewart } 46030c0982b8SRandall Stewart if (foundeom == 0) { 46040c0982b8SRandall Stewart /* 46050c0982b8SRandall Stewart * Still no eom found. That means there is stuff left on the 46060c0982b8SRandall Stewart * stream out queue.. yuck. 46070c0982b8SRandall Stewart */ 46080c0982b8SRandall Stewart strq = &stcb->asoc.strmout[stream]; 46090c0982b8SRandall Stewart SCTP_TCB_SEND_LOCK(stcb); 46104a9ef3f8SMichael Tuexen TAILQ_FOREACH(sp, &strq->outqueue, next) { 46114a9ef3f8SMichael Tuexen /* FIXME: Shouldn't this be a serial number check? */ 46124a9ef3f8SMichael Tuexen if (sp->strseq > seq) { 46134a9ef3f8SMichael Tuexen break; 46144a9ef3f8SMichael Tuexen } 46150c0982b8SRandall Stewart /* Check if its our SEQ */ 46160c0982b8SRandall Stewart if (sp->strseq == seq) { 46170c0982b8SRandall Stewart sp->discard_rest = 1; 46180c0982b8SRandall Stewart /* 46190c0982b8SRandall Stewart * We may need to put a chunk on the queue 46200c0982b8SRandall Stewart * that holds the TSN that would have been 46210c0982b8SRandall Stewart * sent with the LAST bit. 46220c0982b8SRandall Stewart */ 46230c0982b8SRandall Stewart if (chk == NULL) { 46240c0982b8SRandall Stewart /* Yep, we have to */ 46250c0982b8SRandall Stewart sctp_alloc_a_chunk(stcb, chk); 46260c0982b8SRandall Stewart if (chk == NULL) { 46270c0982b8SRandall Stewart /* 46280c0982b8SRandall Stewart * we are hosed. All we can 46290c0982b8SRandall Stewart * do is nothing.. which 46300c0982b8SRandall Stewart * will cause an abort if 46310c0982b8SRandall Stewart * the peer is paying 46320c0982b8SRandall Stewart * attention. 46330c0982b8SRandall Stewart */ 46340c0982b8SRandall Stewart goto oh_well; 46350c0982b8SRandall Stewart } 46360c0982b8SRandall Stewart memset(chk, 0, sizeof(*chk)); 46370c0982b8SRandall Stewart chk->rec.data.rcv_flags = SCTP_DATA_LAST_FRAG; 46380c0982b8SRandall Stewart chk->sent = SCTP_FORWARD_TSN_SKIP; 46390c0982b8SRandall Stewart chk->asoc = &stcb->asoc; 46400c0982b8SRandall Stewart chk->rec.data.stream_seq = sp->strseq; 46410c0982b8SRandall Stewart chk->rec.data.stream_number = sp->stream; 46420c0982b8SRandall Stewart chk->rec.data.payloadtype = sp->ppid; 46430c0982b8SRandall Stewart chk->rec.data.context = sp->context; 46440c0982b8SRandall Stewart chk->flags = sp->act_flags; 46459eea4a2dSMichael Tuexen if (sp->net) 46460c0982b8SRandall Stewart chk->whoTo = sp->net; 46479eea4a2dSMichael Tuexen else 46489eea4a2dSMichael Tuexen chk->whoTo = stcb->asoc.primary_destination; 46490c0982b8SRandall Stewart atomic_add_int(&chk->whoTo->ref_count, 1); 46500c0982b8SRandall Stewart chk->rec.data.TSN_seq = atomic_fetchadd_int(&stcb->asoc.sending_seq, 1); 46510c0982b8SRandall Stewart stcb->asoc.pr_sctp_cnt++; 46520c0982b8SRandall Stewart chk->pr_sctp_on = 1; 46530c0982b8SRandall Stewart TAILQ_INSERT_TAIL(&stcb->asoc.sent_queue, chk, sctp_next); 46540c0982b8SRandall Stewart stcb->asoc.sent_queue_cnt++; 46558933fa13SRandall Stewart stcb->asoc.pr_sctp_cnt++; 46560c0982b8SRandall Stewart } else { 46570c0982b8SRandall Stewart chk->rec.data.rcv_flags |= SCTP_DATA_LAST_FRAG; 46580c0982b8SRandall Stewart } 46590c0982b8SRandall Stewart oh_well: 46600c0982b8SRandall Stewart if (sp->data) { 46610c0982b8SRandall Stewart /* 46620c0982b8SRandall Stewart * Pull any data to free up the SB 46630c0982b8SRandall Stewart * and allow sender to "add more" 46640c0982b8SRandall Stewart * whilc we will throw away :-) 46650c0982b8SRandall Stewart */ 46660c0982b8SRandall Stewart sctp_free_spbufspace(stcb, &stcb->asoc, 46670c0982b8SRandall Stewart sp); 46680c0982b8SRandall Stewart ret_sz += sp->length; 46690c0982b8SRandall Stewart do_wakeup_routine = 1; 46700c0982b8SRandall Stewart sp->some_taken = 1; 46710c0982b8SRandall Stewart sctp_m_freem(sp->data); 46720c0982b8SRandall Stewart sp->length = 0; 46730c0982b8SRandall Stewart sp->data = NULL; 46740c0982b8SRandall Stewart sp->tail_mbuf = NULL; 46750c0982b8SRandall Stewart } 46760c0982b8SRandall Stewart break; 46770c0982b8SRandall Stewart } 46784a9ef3f8SMichael Tuexen } /* End tailq_foreach */ 46790c0982b8SRandall Stewart SCTP_TCB_SEND_UNLOCK(stcb); 46800c0982b8SRandall Stewart } 46810c0982b8SRandall Stewart if (do_wakeup_routine) { 46820c0982b8SRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 46838933fa13SRandall Stewart struct socket *so; 46848933fa13SRandall Stewart 46850c0982b8SRandall Stewart so = SCTP_INP_SO(stcb->sctp_ep); 46860c0982b8SRandall Stewart if (!so_locked) { 46870c0982b8SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 46880c0982b8SRandall Stewart SCTP_TCB_UNLOCK(stcb); 46890c0982b8SRandall Stewart SCTP_SOCKET_LOCK(so, 1); 46900c0982b8SRandall Stewart SCTP_TCB_LOCK(stcb); 46910c0982b8SRandall Stewart atomic_subtract_int(&stcb->asoc.refcnt, 1); 46920c0982b8SRandall Stewart if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) { 46930c0982b8SRandall Stewart /* assoc was freed while we were unlocked */ 46940c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 46950c0982b8SRandall Stewart return (ret_sz); 46960c0982b8SRandall Stewart } 46970c0982b8SRandall Stewart } 46980c0982b8SRandall Stewart #endif 46990c0982b8SRandall Stewart sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket); 47000c0982b8SRandall Stewart #if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING) 47010c0982b8SRandall Stewart if (!so_locked) { 47020c0982b8SRandall Stewart SCTP_SOCKET_UNLOCK(so, 1); 47030c0982b8SRandall Stewart } 47040c0982b8SRandall Stewart #endif 4705f8829a4aSRandall Stewart } 4706f8829a4aSRandall Stewart return (ret_sz); 4707f8829a4aSRandall Stewart } 4708f8829a4aSRandall Stewart 4709f8829a4aSRandall Stewart /* 4710f8829a4aSRandall Stewart * checks to see if the given address, sa, is one that is currently known by 4711f8829a4aSRandall Stewart * the kernel note: can't distinguish the same address on multiple interfaces 4712f8829a4aSRandall Stewart * and doesn't handle multiple addresses with different zone/scope id's note: 4713f8829a4aSRandall Stewart * ifa_ifwithaddr() compares the entire sockaddr struct 4714f8829a4aSRandall Stewart */ 471542551e99SRandall Stewart struct sctp_ifa * 471680fefe0aSRandall Stewart sctp_find_ifa_in_ep(struct sctp_inpcb *inp, struct sockaddr *addr, 471780fefe0aSRandall Stewart int holds_lock) 4718f8829a4aSRandall Stewart { 471942551e99SRandall Stewart struct sctp_laddr *laddr; 4720f8829a4aSRandall Stewart 4721ad81507eSRandall Stewart if (holds_lock == 0) { 472242551e99SRandall Stewart SCTP_INP_RLOCK(inp); 4723ad81507eSRandall Stewart } 472442551e99SRandall Stewart LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { 472542551e99SRandall Stewart if (laddr->ifa == NULL) 4726f8829a4aSRandall Stewart continue; 472742551e99SRandall Stewart if (addr->sa_family != laddr->ifa->address.sa.sa_family) 472842551e99SRandall Stewart continue; 4729e6194c2eSMichael Tuexen #ifdef INET 473042551e99SRandall Stewart if (addr->sa_family == AF_INET) { 473142551e99SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 473242551e99SRandall Stewart laddr->ifa->address.sin.sin_addr.s_addr) { 473342551e99SRandall Stewart /* found him. */ 4734ad81507eSRandall Stewart if (holds_lock == 0) { 473542551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4736ad81507eSRandall Stewart } 473742551e99SRandall Stewart return (laddr->ifa); 473842551e99SRandall Stewart break; 473942551e99SRandall Stewart } 47405e2c2d87SRandall Stewart } 4741e6194c2eSMichael Tuexen #endif 47425e2c2d87SRandall Stewart #ifdef INET6 47435e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 4744c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 4745c54a18d2SRandall Stewart &laddr->ifa->address.sin6)) { 474642551e99SRandall Stewart /* found him. */ 4747ad81507eSRandall Stewart if (holds_lock == 0) { 474842551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4749ad81507eSRandall Stewart } 475042551e99SRandall Stewart return (laddr->ifa); 475142551e99SRandall Stewart break; 475242551e99SRandall Stewart } 475342551e99SRandall Stewart } 47545e2c2d87SRandall Stewart #endif 475542551e99SRandall Stewart } 4756ad81507eSRandall Stewart if (holds_lock == 0) { 475742551e99SRandall Stewart SCTP_INP_RUNLOCK(inp); 4758ad81507eSRandall Stewart } 475942551e99SRandall Stewart return (NULL); 476042551e99SRandall Stewart } 4761f8829a4aSRandall Stewart 47626a27c376SRandall Stewart uint32_t 47636a27c376SRandall Stewart sctp_get_ifa_hash_val(struct sockaddr *addr) 47646a27c376SRandall Stewart { 4765ea5eba11SMichael Tuexen switch (addr->sa_family) { 4766ea5eba11SMichael Tuexen #ifdef INET 4767ea5eba11SMichael Tuexen case AF_INET: 4768ea5eba11SMichael Tuexen { 47696a27c376SRandall Stewart struct sockaddr_in *sin; 47706a27c376SRandall Stewart 47716a27c376SRandall Stewart sin = (struct sockaddr_in *)addr; 47726a27c376SRandall Stewart return (sin->sin_addr.s_addr ^ (sin->sin_addr.s_addr >> 16)); 4773ea5eba11SMichael Tuexen } 4774ea5eba11SMichael Tuexen #endif 4775ea5eba11SMichael Tuexen #ifdef INET6 4776ea5eba11SMichael Tuexen case INET6: 4777ea5eba11SMichael Tuexen { 47786a27c376SRandall Stewart struct sockaddr_in6 *sin6; 47796a27c376SRandall Stewart uint32_t hash_of_addr; 47806a27c376SRandall Stewart 47816a27c376SRandall Stewart sin6 = (struct sockaddr_in6 *)addr; 47826a27c376SRandall Stewart hash_of_addr = (sin6->sin6_addr.s6_addr32[0] + 47836a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[1] + 47846a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[2] + 47856a27c376SRandall Stewart sin6->sin6_addr.s6_addr32[3]); 47866a27c376SRandall Stewart hash_of_addr = (hash_of_addr ^ (hash_of_addr >> 16)); 47876a27c376SRandall Stewart return (hash_of_addr); 47886a27c376SRandall Stewart } 4789ea5eba11SMichael Tuexen #endif 4790ea5eba11SMichael Tuexen default: 4791ea5eba11SMichael Tuexen break; 4792ea5eba11SMichael Tuexen } 47936a27c376SRandall Stewart return (0); 47946a27c376SRandall Stewart } 47956a27c376SRandall Stewart 479642551e99SRandall Stewart struct sctp_ifa * 479742551e99SRandall Stewart sctp_find_ifa_by_addr(struct sockaddr *addr, uint32_t vrf_id, int holds_lock) 479842551e99SRandall Stewart { 479942551e99SRandall Stewart struct sctp_ifa *sctp_ifap; 480042551e99SRandall Stewart struct sctp_vrf *vrf; 48016a27c376SRandall Stewart struct sctp_ifalist *hash_head; 48026a27c376SRandall Stewart uint32_t hash_of_addr; 480342551e99SRandall Stewart 480442551e99SRandall Stewart if (holds_lock == 0) 4805c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 480642551e99SRandall Stewart 4807bff64a4dSRandall Stewart vrf = sctp_find_vrf(vrf_id); 4808bff64a4dSRandall Stewart if (vrf == NULL) { 4809df6e0cc3SRandall Stewart stage_right: 4810bff64a4dSRandall Stewart if (holds_lock == 0) 4811c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 4812bff64a4dSRandall Stewart return (NULL); 4813bff64a4dSRandall Stewart } 4814bff64a4dSRandall Stewart hash_of_addr = sctp_get_ifa_hash_val(addr); 4815bff64a4dSRandall Stewart 481617205eccSRandall Stewart hash_head = &vrf->vrf_addr_hash[(hash_of_addr & vrf->vrf_addr_hashmark)]; 4817bff64a4dSRandall Stewart if (hash_head == NULL) { 4818ad81507eSRandall Stewart SCTP_PRINTF("hash_of_addr:%x mask:%x table:%x - ", 4819c99efcf6SRandall Stewart hash_of_addr, (uint32_t) vrf->vrf_addr_hashmark, 4820c99efcf6SRandall Stewart (uint32_t) (hash_of_addr & vrf->vrf_addr_hashmark)); 4821bff64a4dSRandall Stewart sctp_print_address(addr); 4822ad81507eSRandall Stewart SCTP_PRINTF("No such bucket for address\n"); 4823bff64a4dSRandall Stewart if (holds_lock == 0) 4824c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 4825bff64a4dSRandall Stewart 4826bff64a4dSRandall Stewart return (NULL); 4827bff64a4dSRandall Stewart } 48286a27c376SRandall Stewart LIST_FOREACH(sctp_ifap, hash_head, next_bucket) { 4829bff64a4dSRandall Stewart if (sctp_ifap == NULL) { 4830df6e0cc3SRandall Stewart #ifdef INVARIANTS 4831bff64a4dSRandall Stewart panic("Huh LIST_FOREACH corrupt"); 4832df6e0cc3SRandall Stewart goto stage_right; 4833df6e0cc3SRandall Stewart #else 4834df6e0cc3SRandall Stewart SCTP_PRINTF("LIST corrupt of sctp_ifap's?\n"); 4835df6e0cc3SRandall Stewart goto stage_right; 4836df6e0cc3SRandall Stewart #endif 4837bff64a4dSRandall Stewart } 48386a27c376SRandall Stewart if (addr->sa_family != sctp_ifap->address.sa.sa_family) 48396a27c376SRandall Stewart continue; 4840e6194c2eSMichael Tuexen #ifdef INET 48416a27c376SRandall Stewart if (addr->sa_family == AF_INET) { 48426a27c376SRandall Stewart if (((struct sockaddr_in *)addr)->sin_addr.s_addr == 48436a27c376SRandall Stewart sctp_ifap->address.sin.sin_addr.s_addr) { 48446a27c376SRandall Stewart /* found him. */ 484542551e99SRandall Stewart if (holds_lock == 0) 4846c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 484742551e99SRandall Stewart return (sctp_ifap); 48486a27c376SRandall Stewart break; 48496a27c376SRandall Stewart } 48505e2c2d87SRandall Stewart } 4851e6194c2eSMichael Tuexen #endif 48525e2c2d87SRandall Stewart #ifdef INET6 48535e2c2d87SRandall Stewart if (addr->sa_family == AF_INET6) { 4854c54a18d2SRandall Stewart if (SCTP6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, 4855c54a18d2SRandall Stewart &sctp_ifap->address.sin6)) { 48566a27c376SRandall Stewart /* found him. */ 48576a27c376SRandall Stewart if (holds_lock == 0) 4858c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 48596a27c376SRandall Stewart return (sctp_ifap); 48606a27c376SRandall Stewart break; 48616a27c376SRandall Stewart } 486242551e99SRandall Stewart } 48635e2c2d87SRandall Stewart #endif 486442551e99SRandall Stewart } 486542551e99SRandall Stewart if (holds_lock == 0) 4866c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 4867f8829a4aSRandall Stewart return (NULL); 4868f8829a4aSRandall Stewart } 4869f8829a4aSRandall Stewart 4870f8829a4aSRandall Stewart static void 48714c9179adSRandall Stewart sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock, 4872f8829a4aSRandall Stewart uint32_t rwnd_req) 4873f8829a4aSRandall Stewart { 4874f8829a4aSRandall Stewart /* User pulled some data, do we need a rwnd update? */ 4875f8829a4aSRandall Stewart int r_unlocked = 0; 4876f8829a4aSRandall Stewart uint32_t dif, rwnd; 4877f8829a4aSRandall Stewart struct socket *so = NULL; 4878f8829a4aSRandall Stewart 4879f8829a4aSRandall Stewart if (stcb == NULL) 4880f8829a4aSRandall Stewart return; 4881f8829a4aSRandall Stewart 488250cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 4883f8829a4aSRandall Stewart 488462c1ff9cSRandall Stewart if (stcb->asoc.state & (SCTP_STATE_ABOUT_TO_BE_FREED | 488562c1ff9cSRandall Stewart SCTP_STATE_SHUTDOWN_RECEIVED | 48864c9179adSRandall Stewart SCTP_STATE_SHUTDOWN_ACK_SENT)) { 4887f8829a4aSRandall Stewart /* Pre-check If we are freeing no update */ 4888f8829a4aSRandall Stewart goto no_lock; 4889f8829a4aSRandall Stewart } 4890f8829a4aSRandall Stewart SCTP_INP_INCR_REF(stcb->sctp_ep); 4891f8829a4aSRandall Stewart if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 4892f8829a4aSRandall Stewart (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 4893f8829a4aSRandall Stewart goto out; 4894f8829a4aSRandall Stewart } 4895f8829a4aSRandall Stewart so = stcb->sctp_socket; 4896f8829a4aSRandall Stewart if (so == NULL) { 4897f8829a4aSRandall Stewart goto out; 4898f8829a4aSRandall Stewart } 4899f8829a4aSRandall Stewart atomic_add_int(&stcb->freed_by_sorcv_sincelast, *freed_so_far); 4900f8829a4aSRandall Stewart /* Have you have freed enough to look */ 4901f8829a4aSRandall Stewart *freed_so_far = 0; 4902f8829a4aSRandall Stewart /* Yep, its worth a look and the lock overhead */ 4903f8829a4aSRandall Stewart 4904f8829a4aSRandall Stewart /* Figure out what the rwnd would be */ 4905f8829a4aSRandall Stewart rwnd = sctp_calc_rwnd(stcb, &stcb->asoc); 4906f8829a4aSRandall Stewart if (rwnd >= stcb->asoc.my_last_reported_rwnd) { 4907f8829a4aSRandall Stewart dif = rwnd - stcb->asoc.my_last_reported_rwnd; 4908f8829a4aSRandall Stewart } else { 4909f8829a4aSRandall Stewart dif = 0; 4910f8829a4aSRandall Stewart } 4911f8829a4aSRandall Stewart if (dif >= rwnd_req) { 4912f8829a4aSRandall Stewart if (hold_rlock) { 4913f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(stcb->sctp_ep); 4914f8829a4aSRandall Stewart r_unlocked = 1; 4915f8829a4aSRandall Stewart } 4916f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 4917f8829a4aSRandall Stewart /* 4918f8829a4aSRandall Stewart * One last check before we allow the guy possibly 4919f8829a4aSRandall Stewart * to get in. There is a race, where the guy has not 4920f8829a4aSRandall Stewart * reached the gate. In that case 4921f8829a4aSRandall Stewart */ 4922f8829a4aSRandall Stewart goto out; 4923f8829a4aSRandall Stewart } 4924f8829a4aSRandall Stewart SCTP_TCB_LOCK(stcb); 4925f8829a4aSRandall Stewart if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 4926f8829a4aSRandall Stewart /* No reports here */ 4927f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4928f8829a4aSRandall Stewart goto out; 4929f8829a4aSRandall Stewart } 4930f8829a4aSRandall Stewart SCTP_STAT_INCR(sctps_wu_sacks_sent); 4931689e6a5fSMichael Tuexen sctp_send_sack(stcb, SCTP_SO_LOCKED); 4932830d754dSRandall Stewart 4933f8829a4aSRandall Stewart sctp_chunk_output(stcb->sctp_ep, stcb, 4934ceaad40aSRandall Stewart SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED); 4935f8829a4aSRandall Stewart /* make sure no timer is running */ 4936a5d547adSRandall Stewart sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_6); 4937f8829a4aSRandall Stewart SCTP_TCB_UNLOCK(stcb); 4938f8829a4aSRandall Stewart } else { 4939f8829a4aSRandall Stewart /* Update how much we have pending */ 4940f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = dif; 4941f8829a4aSRandall Stewart } 4942f8829a4aSRandall Stewart out: 4943f8829a4aSRandall Stewart if (so && r_unlocked && hold_rlock) { 4944f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(stcb->sctp_ep); 4945f8829a4aSRandall Stewart } 4946f8829a4aSRandall Stewart SCTP_INP_DECR_REF(stcb->sctp_ep); 4947f8829a4aSRandall Stewart no_lock: 494850cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 4949f8829a4aSRandall Stewart return; 4950f8829a4aSRandall Stewart } 4951f8829a4aSRandall Stewart 4952f8829a4aSRandall Stewart int 4953f8829a4aSRandall Stewart sctp_sorecvmsg(struct socket *so, 4954f8829a4aSRandall Stewart struct uio *uio, 4955f8829a4aSRandall Stewart struct mbuf **mp, 4956f8829a4aSRandall Stewart struct sockaddr *from, 4957f8829a4aSRandall Stewart int fromlen, 4958f8829a4aSRandall Stewart int *msg_flags, 4959f8829a4aSRandall Stewart struct sctp_sndrcvinfo *sinfo, 4960f8829a4aSRandall Stewart int filling_sinfo) 4961f8829a4aSRandall Stewart { 4962f8829a4aSRandall Stewart /* 4963f8829a4aSRandall Stewart * MSG flags we will look at MSG_DONTWAIT - non-blocking IO. 4964f8829a4aSRandall Stewart * MSG_PEEK - Look don't touch :-D (only valid with OUT mbuf copy 4965f8829a4aSRandall Stewart * mp=NULL thus uio is the copy method to userland) MSG_WAITALL - ?? 4966f8829a4aSRandall Stewart * On the way out we may send out any combination of: 4967f8829a4aSRandall Stewart * MSG_NOTIFICATION MSG_EOR 4968f8829a4aSRandall Stewart * 4969f8829a4aSRandall Stewart */ 4970f8829a4aSRandall Stewart struct sctp_inpcb *inp = NULL; 4971f8829a4aSRandall Stewart int my_len = 0; 4972f8829a4aSRandall Stewart int cp_len = 0, error = 0; 4973f8829a4aSRandall Stewart struct sctp_queued_to_read *control = NULL, *ctl = NULL, *nxt = NULL; 497494b0d969SMichael Tuexen struct mbuf *m = NULL; 4975f8829a4aSRandall Stewart struct sctp_tcb *stcb = NULL; 4976f8829a4aSRandall Stewart int wakeup_read_socket = 0; 4977f8829a4aSRandall Stewart int freecnt_applied = 0; 4978f8829a4aSRandall Stewart int out_flags = 0, in_flags = 0; 4979f8829a4aSRandall Stewart int block_allowed = 1; 49804c9179adSRandall Stewart uint32_t freed_so_far = 0; 498181aca91aSRandall Stewart uint32_t copied_so_far = 0; 498293164cf9SRandall Stewart int in_eeor_mode = 0; 4983f8829a4aSRandall Stewart int no_rcv_needed = 0; 4984f8829a4aSRandall Stewart uint32_t rwnd_req = 0; 4985f8829a4aSRandall Stewart int hold_sblock = 0; 4986f8829a4aSRandall Stewart int hold_rlock = 0; 498742551e99SRandall Stewart int slen = 0; 49884c9179adSRandall Stewart uint32_t held_length = 0; 49897abab911SRobert Watson int sockbuf_lock = 0; 4990f8829a4aSRandall Stewart 499117205eccSRandall Stewart if (uio == NULL) { 4992c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 499317205eccSRandall Stewart return (EINVAL); 499417205eccSRandall Stewart } 4995f8829a4aSRandall Stewart if (msg_flags) { 4996f8829a4aSRandall Stewart in_flags = *msg_flags; 4997c105859eSRandall Stewart if (in_flags & MSG_PEEK) 4998c105859eSRandall Stewart SCTP_STAT_INCR(sctps_read_peeks); 4999f8829a4aSRandall Stewart } else { 5000f8829a4aSRandall Stewart in_flags = 0; 5001f8829a4aSRandall Stewart } 5002f8829a4aSRandall Stewart slen = uio->uio_resid; 500317205eccSRandall Stewart 5004f8829a4aSRandall Stewart /* Pull in and set up our int flags */ 5005f8829a4aSRandall Stewart if (in_flags & MSG_OOB) { 5006f8829a4aSRandall Stewart /* Out of band's NOT supported */ 5007f8829a4aSRandall Stewart return (EOPNOTSUPP); 5008f8829a4aSRandall Stewart } 5009f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) && (mp != NULL)) { 5010c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 5011f8829a4aSRandall Stewart return (EINVAL); 5012f8829a4aSRandall Stewart } 5013f8829a4aSRandall Stewart if ((in_flags & (MSG_DONTWAIT 5014f8829a4aSRandall Stewart | MSG_NBIO 5015f8829a4aSRandall Stewart )) || 501642551e99SRandall Stewart SCTP_SO_IS_NBIO(so)) { 5017f8829a4aSRandall Stewart block_allowed = 0; 5018f8829a4aSRandall Stewart } 5019f8829a4aSRandall Stewart /* setup the endpoint */ 5020f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 5021f8829a4aSRandall Stewart if (inp == NULL) { 5022c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EFAULT); 5023f8829a4aSRandall Stewart return (EFAULT); 5024f8829a4aSRandall Stewart } 502562c1ff9cSRandall Stewart rwnd_req = (SCTP_SB_LIMIT_RCV(so) >> SCTP_RWND_HIWAT_SHIFT); 5026f8829a4aSRandall Stewart /* Must be at least a MTU's worth */ 5027f8829a4aSRandall Stewart if (rwnd_req < SCTP_MIN_RWND) 5028f8829a4aSRandall Stewart rwnd_req = SCTP_MIN_RWND; 5029f8829a4aSRandall Stewart in_eeor_mode = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); 5030b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5031f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTER, 503217205eccSRandall Stewart rwnd_req, in_eeor_mode, so->so_rcv.sb_cc, uio->uio_resid); 503380fefe0aSRandall Stewart } 5034b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5035f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_ENTERPL, 503617205eccSRandall Stewart rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid); 503780fefe0aSRandall Stewart } 5038265de5bbSRobert Watson error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); 50397abab911SRobert Watson sockbuf_lock = 1; 5040f8829a4aSRandall Stewart if (error) { 5041f8829a4aSRandall Stewart goto release_unlocked; 5042f8829a4aSRandall Stewart } 5043f8829a4aSRandall Stewart restart: 50447abab911SRobert Watson 5045f8829a4aSRandall Stewart 5046f8829a4aSRandall Stewart restart_nosblocks: 5047f8829a4aSRandall Stewart if (hold_sblock == 0) { 5048f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5049f8829a4aSRandall Stewart hold_sblock = 1; 5050f8829a4aSRandall Stewart } 5051f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || 5052f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { 5053f8829a4aSRandall Stewart goto out; 5054f8829a4aSRandall Stewart } 505544b7479bSRandall Stewart if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { 5056f8829a4aSRandall Stewart if (so->so_error) { 5057f8829a4aSRandall Stewart error = so->so_error; 505844b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 505944b7479bSRandall Stewart so->so_error = 0; 50609f22f500SRandall Stewart goto out; 5061f8829a4aSRandall Stewart } else { 50629f22f500SRandall Stewart if (so->so_rcv.sb_cc == 0) { 5063c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 50647924093fSRandall Stewart /* indicate EOF */ 50657924093fSRandall Stewart error = 0; 5066f8829a4aSRandall Stewart goto out; 5067f8829a4aSRandall Stewart } 50689f22f500SRandall Stewart } 50699f22f500SRandall Stewart } 5070f8829a4aSRandall Stewart if ((so->so_rcv.sb_cc <= held_length) && block_allowed) { 5071f8829a4aSRandall Stewart /* we need to wait for data */ 5072f8829a4aSRandall Stewart if ((so->so_rcv.sb_cc == 0) && 5073f8829a4aSRandall Stewart ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 5074f8829a4aSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { 5075f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 5076f8829a4aSRandall Stewart /* 5077f8829a4aSRandall Stewart * For active open side clear flags for 5078f8829a4aSRandall Stewart * re-use passive open is blocked by 5079f8829a4aSRandall Stewart * connect. 5080f8829a4aSRandall Stewart */ 5081f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 5082f8829a4aSRandall Stewart /* 5083f8829a4aSRandall Stewart * You were aborted, passive side 5084f8829a4aSRandall Stewart * always hits here 5085f8829a4aSRandall Stewart */ 5086c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 5087f8829a4aSRandall Stewart error = ECONNRESET; 5088f8829a4aSRandall Stewart } 5089f8829a4aSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 5090f8829a4aSRandall Stewart SS_ISDISCONNECTING | 5091f8829a4aSRandall Stewart SS_ISCONFIRMING | 5092f8829a4aSRandall Stewart SS_ISCONNECTED); 5093f8829a4aSRandall Stewart if (error == 0) { 5094f8829a4aSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5095c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 5096f8829a4aSRandall Stewart error = ENOTCONN; 5097f8829a4aSRandall Stewart } 5098f8829a4aSRandall Stewart } 5099f8829a4aSRandall Stewart goto out; 5100f8829a4aSRandall Stewart } 5101f8829a4aSRandall Stewart } 5102f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5103f8829a4aSRandall Stewart if (error) { 5104f8829a4aSRandall Stewart goto out; 5105f8829a4aSRandall Stewart } 5106f8829a4aSRandall Stewart held_length = 0; 5107f8829a4aSRandall Stewart goto restart_nosblocks; 5108f8829a4aSRandall Stewart } else if (so->so_rcv.sb_cc == 0) { 510944b7479bSRandall Stewart if (so->so_error) { 511044b7479bSRandall Stewart error = so->so_error; 511144b7479bSRandall Stewart if ((in_flags & MSG_PEEK) == 0) 511244b7479bSRandall Stewart so->so_error = 0; 511344b7479bSRandall Stewart } else { 511444b7479bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || 511544b7479bSRandall Stewart (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { 511644b7479bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0) { 511744b7479bSRandall Stewart /* 511844b7479bSRandall Stewart * For active open side clear flags 511944b7479bSRandall Stewart * for re-use passive open is 512044b7479bSRandall Stewart * blocked by connect. 512144b7479bSRandall Stewart */ 512244b7479bSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_WAS_ABORTED) { 512344b7479bSRandall Stewart /* 512444b7479bSRandall Stewart * You were aborted, passive 512544b7479bSRandall Stewart * side always hits here 512644b7479bSRandall Stewart */ 5127c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ECONNRESET); 512844b7479bSRandall Stewart error = ECONNRESET; 512944b7479bSRandall Stewart } 513044b7479bSRandall Stewart so->so_state &= ~(SS_ISCONNECTING | 513144b7479bSRandall Stewart SS_ISDISCONNECTING | 513244b7479bSRandall Stewart SS_ISCONFIRMING | 513344b7479bSRandall Stewart SS_ISCONNECTED); 513444b7479bSRandall Stewart if (error == 0) { 513544b7479bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_WAS_CONNECTED) == 0) { 5136c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOTCONN); 513744b7479bSRandall Stewart error = ENOTCONN; 513844b7479bSRandall Stewart } 513944b7479bSRandall Stewart } 514044b7479bSRandall Stewart goto out; 514144b7479bSRandall Stewart } 514244b7479bSRandall Stewart } 5143c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EWOULDBLOCK); 5144f8829a4aSRandall Stewart error = EWOULDBLOCK; 514544b7479bSRandall Stewart } 5146f8829a4aSRandall Stewart goto out; 5147f8829a4aSRandall Stewart } 5148d06c82f1SRandall Stewart if (hold_sblock == 1) { 5149d06c82f1SRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5150d06c82f1SRandall Stewart hold_sblock = 0; 5151d06c82f1SRandall Stewart } 5152f8829a4aSRandall Stewart /* we possibly have data we can read */ 51533c503c28SRandall Stewart /* sa_ignore FREED_MEMORY */ 5154f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5155f8829a4aSRandall Stewart if (control == NULL) { 5156f8829a4aSRandall Stewart /* 5157f8829a4aSRandall Stewart * This could be happening since the appender did the 5158f8829a4aSRandall Stewart * increment but as not yet did the tailq insert onto the 5159f8829a4aSRandall Stewart * read_queue 5160f8829a4aSRandall Stewart */ 5161f8829a4aSRandall Stewart if (hold_rlock == 0) { 5162f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5163f8829a4aSRandall Stewart hold_rlock = 1; 5164f8829a4aSRandall Stewart } 5165f8829a4aSRandall Stewart control = TAILQ_FIRST(&inp->read_queue); 5166f8829a4aSRandall Stewart if ((control == NULL) && (so->so_rcv.sb_cc != 0)) { 5167a5d547adSRandall Stewart #ifdef INVARIANTS 5168f8829a4aSRandall Stewart panic("Huh, its non zero and nothing on control?"); 5169f8829a4aSRandall Stewart #endif 5170f8829a4aSRandall Stewart so->so_rcv.sb_cc = 0; 5171f8829a4aSRandall Stewart } 5172f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5173f8829a4aSRandall Stewart hold_rlock = 0; 5174f8829a4aSRandall Stewart goto restart; 5175f8829a4aSRandall Stewart } 5176f8829a4aSRandall Stewart if ((control->length == 0) && 5177f8829a4aSRandall Stewart (control->do_not_ref_stcb)) { 5178f8829a4aSRandall Stewart /* 5179f8829a4aSRandall Stewart * Clean up code for freeing assoc that left behind a 5180f8829a4aSRandall Stewart * pdapi.. maybe a peer in EEOR that just closed after 5181f8829a4aSRandall Stewart * sending and never indicated a EOR. 5182f8829a4aSRandall Stewart */ 5183f8829a4aSRandall Stewart if (hold_rlock == 0) { 5184f8829a4aSRandall Stewart hold_rlock = 1; 5185f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5186f8829a4aSRandall Stewart } 5187f8829a4aSRandall Stewart control->held_length = 0; 5188f8829a4aSRandall Stewart if (control->data) { 5189f8829a4aSRandall Stewart /* Hmm there is data here .. fix */ 51904c9179adSRandall Stewart struct mbuf *m_tmp; 5191f8829a4aSRandall Stewart int cnt = 0; 5192f8829a4aSRandall Stewart 51934c9179adSRandall Stewart m_tmp = control->data; 51944c9179adSRandall Stewart while (m_tmp) { 51954c9179adSRandall Stewart cnt += SCTP_BUF_LEN(m_tmp); 51964c9179adSRandall Stewart if (SCTP_BUF_NEXT(m_tmp) == NULL) { 51974c9179adSRandall Stewart control->tail_mbuf = m_tmp; 5198f8829a4aSRandall Stewart control->end_added = 1; 5199f8829a4aSRandall Stewart } 52004c9179adSRandall Stewart m_tmp = SCTP_BUF_NEXT(m_tmp); 5201f8829a4aSRandall Stewart } 5202f8829a4aSRandall Stewart control->length = cnt; 5203f8829a4aSRandall Stewart } else { 5204f8829a4aSRandall Stewart /* remove it */ 5205f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5206f8829a4aSRandall Stewart /* Add back any hiddend data */ 5207f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5208f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5209f8829a4aSRandall Stewart } 5210f8829a4aSRandall Stewart if (hold_rlock) { 5211f8829a4aSRandall Stewart hold_rlock = 0; 5212f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5213f8829a4aSRandall Stewart } 5214f8829a4aSRandall Stewart goto restart; 5215f8829a4aSRandall Stewart } 5216810ec536SMichael Tuexen if ((control->length == 0) && 5217810ec536SMichael Tuexen (control->end_added == 1)) { 5218810ec536SMichael Tuexen /* 5219810ec536SMichael Tuexen * Do we also need to check for (control->pdapi_aborted == 5220810ec536SMichael Tuexen * 1)? 5221810ec536SMichael Tuexen */ 5222810ec536SMichael Tuexen if (hold_rlock == 0) { 5223810ec536SMichael Tuexen hold_rlock = 1; 5224810ec536SMichael Tuexen SCTP_INP_READ_LOCK(inp); 5225810ec536SMichael Tuexen } 5226810ec536SMichael Tuexen TAILQ_REMOVE(&inp->read_queue, control, next); 5227810ec536SMichael Tuexen if (control->data) { 5228810ec536SMichael Tuexen #ifdef INVARIANTS 5229810ec536SMichael Tuexen panic("control->data not null but control->length == 0"); 5230810ec536SMichael Tuexen #else 5231810ec536SMichael Tuexen SCTP_PRINTF("Strange, data left in the control buffer. Cleaning up.\n"); 5232810ec536SMichael Tuexen sctp_m_freem(control->data); 5233810ec536SMichael Tuexen control->data = NULL; 5234810ec536SMichael Tuexen #endif 5235810ec536SMichael Tuexen } 5236810ec536SMichael Tuexen if (control->aux_data) { 5237810ec536SMichael Tuexen sctp_m_free(control->aux_data); 5238810ec536SMichael Tuexen control->aux_data = NULL; 5239810ec536SMichael Tuexen } 5240810ec536SMichael Tuexen sctp_free_remote_addr(control->whoFrom); 5241810ec536SMichael Tuexen sctp_free_a_readq(stcb, control); 5242810ec536SMichael Tuexen if (hold_rlock) { 5243810ec536SMichael Tuexen hold_rlock = 0; 5244810ec536SMichael Tuexen SCTP_INP_READ_UNLOCK(inp); 5245810ec536SMichael Tuexen } 5246810ec536SMichael Tuexen goto restart; 5247810ec536SMichael Tuexen } 5248f8829a4aSRandall Stewart if (control->length == 0) { 5249f8829a4aSRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) && 5250f8829a4aSRandall Stewart (filling_sinfo)) { 5251f8829a4aSRandall Stewart /* find a more suitable one then this */ 5252f8829a4aSRandall Stewart ctl = TAILQ_NEXT(control, next); 5253f8829a4aSRandall Stewart while (ctl) { 52549a6142d8SRandall Stewart if ((ctl->stcb != control->stcb) && (ctl->length) && 52559a6142d8SRandall Stewart (ctl->some_taken || 52566114cd96SRandall Stewart (ctl->spec_flags & M_NOTIFICATION) || 52579a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 52589a6142d8SRandall Stewart (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0))) 52599a6142d8SRandall Stewart ) { 52609a6142d8SRandall Stewart /*- 52619a6142d8SRandall Stewart * If we have a different TCB next, and there is data 52629a6142d8SRandall Stewart * present. If we have already taken some (pdapi), OR we can 52639a6142d8SRandall Stewart * ref the tcb and no delivery as started on this stream, we 526417205eccSRandall Stewart * take it. Note we allow a notification on a different 526517205eccSRandall Stewart * assoc to be delivered.. 52669a6142d8SRandall Stewart */ 52679a6142d8SRandall Stewart control = ctl; 52689a6142d8SRandall Stewart goto found_one; 52699a6142d8SRandall Stewart } else if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) && 52709a6142d8SRandall Stewart (ctl->length) && 52719a6142d8SRandall Stewart ((ctl->some_taken) || 52729a6142d8SRandall Stewart ((ctl->do_not_ref_stcb == 0) && 527317205eccSRandall Stewart ((ctl->spec_flags & M_NOTIFICATION) == 0) && 5274b5c16493SMichael Tuexen (ctl->stcb->asoc.strmin[ctl->sinfo_stream].delivery_started == 0)))) { 52759a6142d8SRandall Stewart /*- 52769a6142d8SRandall Stewart * If we have the same tcb, and there is data present, and we 52779a6142d8SRandall Stewart * have the strm interleave feature present. Then if we have 52789a6142d8SRandall Stewart * taken some (pdapi) or we can refer to tht tcb AND we have 52799a6142d8SRandall Stewart * not started a delivery for this stream, we can take it. 528017205eccSRandall Stewart * Note we do NOT allow a notificaiton on the same assoc to 528117205eccSRandall Stewart * be delivered. 52829a6142d8SRandall Stewart */ 5283f8829a4aSRandall Stewart control = ctl; 5284f8829a4aSRandall Stewart goto found_one; 5285f8829a4aSRandall Stewart } 5286f8829a4aSRandall Stewart ctl = TAILQ_NEXT(ctl, next); 5287f8829a4aSRandall Stewart } 5288f8829a4aSRandall Stewart } 5289f8829a4aSRandall Stewart /* 5290f8829a4aSRandall Stewart * if we reach here, not suitable replacement is available 5291f8829a4aSRandall Stewart * <or> fragment interleave is NOT on. So stuff the sb_cc 5292f8829a4aSRandall Stewart * into the our held count, and its time to sleep again. 5293f8829a4aSRandall Stewart */ 5294f8829a4aSRandall Stewart held_length = so->so_rcv.sb_cc; 5295f8829a4aSRandall Stewart control->held_length = so->so_rcv.sb_cc; 5296f8829a4aSRandall Stewart goto restart; 5297f8829a4aSRandall Stewart } 5298f8829a4aSRandall Stewart /* Clear the held length since there is something to read */ 5299f8829a4aSRandall Stewart control->held_length = 0; 5300f8829a4aSRandall Stewart if (hold_rlock) { 5301f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5302f8829a4aSRandall Stewart hold_rlock = 0; 5303f8829a4aSRandall Stewart } 5304f8829a4aSRandall Stewart found_one: 5305f8829a4aSRandall Stewart /* 5306f8829a4aSRandall Stewart * If we reach here, control has a some data for us to read off. 5307f8829a4aSRandall Stewart * Note that stcb COULD be NULL. 5308f8829a4aSRandall Stewart */ 53099c04b296SRandall Stewart control->some_taken++; 5310f8829a4aSRandall Stewart if (hold_sblock) { 5311f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5312f8829a4aSRandall Stewart hold_sblock = 0; 5313f8829a4aSRandall Stewart } 5314f8829a4aSRandall Stewart stcb = control->stcb; 5315f8829a4aSRandall Stewart if (stcb) { 53160696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 53170696e120SRandall Stewart (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED)) { 531850cec919SRandall Stewart if (freecnt_applied == 0) 5319f8829a4aSRandall Stewart stcb = NULL; 5320f8829a4aSRandall Stewart } else if (control->do_not_ref_stcb == 0) { 5321f8829a4aSRandall Stewart /* you can't free it on me please */ 5322f8829a4aSRandall Stewart /* 5323f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the 5324f8829a4aSRandall Stewart * free code will stop. But since we used the 5325f8829a4aSRandall Stewart * socketbuf lock and the sender uses the tcb_lock 5326f8829a4aSRandall Stewart * to increment, we need to use the atomic add to 5327f8829a4aSRandall Stewart * the refcnt 5328f8829a4aSRandall Stewart */ 5329d55b0b1bSRandall Stewart if (freecnt_applied) { 5330d55b0b1bSRandall Stewart #ifdef INVARIANTS 5331207304d4SRandall Stewart panic("refcnt already incremented"); 5332d55b0b1bSRandall Stewart #else 5333d55b0b1bSRandall Stewart printf("refcnt already incremented?\n"); 5334d55b0b1bSRandall Stewart #endif 5335d55b0b1bSRandall Stewart } else { 533650cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, 1); 5337f8829a4aSRandall Stewart freecnt_applied = 1; 5338d55b0b1bSRandall Stewart } 5339f8829a4aSRandall Stewart /* 5340f8829a4aSRandall Stewart * Setup to remember how much we have not yet told 5341f8829a4aSRandall Stewart * the peer our rwnd has opened up. Note we grab the 5342f8829a4aSRandall Stewart * value from the tcb from last time. Note too that 53430696e120SRandall Stewart * sack sending clears this when a sack is sent, 5344f8829a4aSRandall Stewart * which is fine. Once we hit the rwnd_req, we then 5345f8829a4aSRandall Stewart * will go to the sctp_user_rcvd() that will not 5346f8829a4aSRandall Stewart * lock until it KNOWs it MUST send a WUP-SACK. 5347f8829a4aSRandall Stewart */ 5348f8829a4aSRandall Stewart freed_so_far = stcb->freed_by_sorcv_sincelast; 5349f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = 0; 5350f8829a4aSRandall Stewart } 5351f8829a4aSRandall Stewart } 53526114cd96SRandall Stewart if (stcb && 53536114cd96SRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0) && 53546114cd96SRandall Stewart control->do_not_ref_stcb == 0) { 5355d06c82f1SRandall Stewart stcb->asoc.strmin[control->sinfo_stream].delivery_started = 1; 5356d06c82f1SRandall Stewart } 5357f8829a4aSRandall Stewart /* First lets get off the sinfo and sockaddr info */ 5358f8829a4aSRandall Stewart if ((sinfo) && filling_sinfo) { 5359f8829a4aSRandall Stewart memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo)); 5360f8829a4aSRandall Stewart nxt = TAILQ_NEXT(control, next); 5361e2e7c62eSMichael Tuexen if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 5362e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) { 5363f8829a4aSRandall Stewart struct sctp_extrcvinfo *s_extra; 5364f8829a4aSRandall Stewart 5365f8829a4aSRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 53669a6142d8SRandall Stewart if ((nxt) && 53679a6142d8SRandall Stewart (nxt->length)) { 53689a6142d8SRandall Stewart s_extra->sreinfo_next_flags = SCTP_NEXT_MSG_AVAIL; 5369f8829a4aSRandall Stewart if (nxt->sinfo_flags & SCTP_UNORDERED) { 53709a6142d8SRandall Stewart s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_UNORDERED; 5371f8829a4aSRandall Stewart } 5372f42a358aSRandall Stewart if (nxt->spec_flags & M_NOTIFICATION) { 53739a6142d8SRandall Stewart s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_IS_NOTIFICATION; 5374f42a358aSRandall Stewart } 53759a6142d8SRandall Stewart s_extra->sreinfo_next_aid = nxt->sinfo_assoc_id; 53769a6142d8SRandall Stewart s_extra->sreinfo_next_length = nxt->length; 53779a6142d8SRandall Stewart s_extra->sreinfo_next_ppid = nxt->sinfo_ppid; 53789a6142d8SRandall Stewart s_extra->sreinfo_next_stream = nxt->sinfo_stream; 5379f8829a4aSRandall Stewart if (nxt->tail_mbuf != NULL) { 5380139bc87fSRandall Stewart if (nxt->end_added) { 53819a6142d8SRandall Stewart s_extra->sreinfo_next_flags |= SCTP_NEXT_MSG_ISCOMPLETE; 5382f8829a4aSRandall Stewart } 5383f8829a4aSRandall Stewart } 5384f8829a4aSRandall Stewart } else { 5385f8829a4aSRandall Stewart /* 5386f8829a4aSRandall Stewart * we explicitly 0 this, since the memcpy 5387f8829a4aSRandall Stewart * got some other things beyond the older 5388f8829a4aSRandall Stewart * sinfo_ that is on the control's structure 5389f8829a4aSRandall Stewart * :-D 5390f8829a4aSRandall Stewart */ 53919a6142d8SRandall Stewart nxt = NULL; 53929a6142d8SRandall Stewart s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG; 53939a6142d8SRandall Stewart s_extra->sreinfo_next_aid = 0; 53949a6142d8SRandall Stewart s_extra->sreinfo_next_length = 0; 53959a6142d8SRandall Stewart s_extra->sreinfo_next_ppid = 0; 53969a6142d8SRandall Stewart s_extra->sreinfo_next_stream = 0; 5397f8829a4aSRandall Stewart } 5398f8829a4aSRandall Stewart } 5399f8829a4aSRandall Stewart /* 5400f8829a4aSRandall Stewart * update off the real current cum-ack, if we have an stcb. 5401f8829a4aSRandall Stewart */ 54020696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb) 5403f8829a4aSRandall Stewart sinfo->sinfo_cumtsn = stcb->asoc.cumulative_tsn; 5404f8829a4aSRandall Stewart /* 5405f8829a4aSRandall Stewart * mask off the high bits, we keep the actual chunk bits in 5406f8829a4aSRandall Stewart * there. 5407f8829a4aSRandall Stewart */ 5408f8829a4aSRandall Stewart sinfo->sinfo_flags &= 0x00ff; 54095f26a41dSRandall Stewart if ((control->sinfo_flags >> 8) & SCTP_DATA_UNORDERED) { 54105f26a41dSRandall Stewart sinfo->sinfo_flags |= SCTP_UNORDERED; 54115f26a41dSRandall Stewart } 5412f8829a4aSRandall Stewart } 541318e198d3SRandall Stewart #ifdef SCTP_ASOCLOG_OF_TSNS 541418e198d3SRandall Stewart { 541518e198d3SRandall Stewart int index, newindex; 541618e198d3SRandall Stewart struct sctp_pcbtsn_rlog *entry; 541718e198d3SRandall Stewart 541818e198d3SRandall Stewart do { 541918e198d3SRandall Stewart index = inp->readlog_index; 542018e198d3SRandall Stewart newindex = index + 1; 542118e198d3SRandall Stewart if (newindex >= SCTP_READ_LOG_SIZE) { 542218e198d3SRandall Stewart newindex = 0; 542318e198d3SRandall Stewart } 542418e198d3SRandall Stewart } while (atomic_cmpset_int(&inp->readlog_index, index, newindex) == 0); 542518e198d3SRandall Stewart entry = &inp->readlog[index]; 542618e198d3SRandall Stewart entry->vtag = control->sinfo_assoc_id; 542718e198d3SRandall Stewart entry->strm = control->sinfo_stream; 542818e198d3SRandall Stewart entry->seq = control->sinfo_ssn; 542918e198d3SRandall Stewart entry->sz = control->length; 543018e198d3SRandall Stewart entry->flgs = control->sinfo_flags; 543118e198d3SRandall Stewart } 543218e198d3SRandall Stewart #endif 5433f8829a4aSRandall Stewart if (fromlen && from) { 5434f8829a4aSRandall Stewart struct sockaddr *to; 5435f8829a4aSRandall Stewart 543642551e99SRandall Stewart #ifdef INET 5437baf3da66SRandall Stewart cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sin.sin_len); 5438f8829a4aSRandall Stewart memcpy(from, &control->whoFrom->ro._l_addr, cp_len); 5439f8829a4aSRandall Stewart ((struct sockaddr_in *)from)->sin_port = control->port_from; 5440f8829a4aSRandall Stewart #else 5441f8829a4aSRandall Stewart /* No AF_INET use AF_INET6 */ 5442baf3da66SRandall Stewart cp_len = min((size_t)fromlen, (size_t)control->whoFrom->ro._l_addr.sin6.sin6_len); 5443f8829a4aSRandall Stewart memcpy(from, &control->whoFrom->ro._l_addr, cp_len); 5444f8829a4aSRandall Stewart ((struct sockaddr_in6 *)from)->sin6_port = control->port_from; 5445f8829a4aSRandall Stewart #endif 5446f8829a4aSRandall Stewart 5447f8829a4aSRandall Stewart to = from; 544842551e99SRandall Stewart #if defined(INET) && defined(INET6) 54495e2c2d87SRandall Stewart if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && 5450f8829a4aSRandall Stewart (to->sa_family == AF_INET) && 5451f8829a4aSRandall Stewart ((size_t)fromlen >= sizeof(struct sockaddr_in6))) { 5452f8829a4aSRandall Stewart struct sockaddr_in *sin; 5453f8829a4aSRandall Stewart struct sockaddr_in6 sin6; 5454f8829a4aSRandall Stewart 5455f8829a4aSRandall Stewart sin = (struct sockaddr_in *)to; 5456f8829a4aSRandall Stewart bzero(&sin6, sizeof(sin6)); 5457f8829a4aSRandall Stewart sin6.sin6_family = AF_INET6; 5458f8829a4aSRandall Stewart sin6.sin6_len = sizeof(struct sockaddr_in6); 5459d6af161aSRandall Stewart sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); 5460f8829a4aSRandall Stewart bcopy(&sin->sin_addr, 5461d6af161aSRandall Stewart &sin6.sin6_addr.s6_addr32[3], 5462d6af161aSRandall Stewart sizeof(sin6.sin6_addr.s6_addr32[3])); 5463f8829a4aSRandall Stewart sin6.sin6_port = sin->sin_port; 5464f8829a4aSRandall Stewart memcpy(from, (caddr_t)&sin6, sizeof(sin6)); 5465f8829a4aSRandall Stewart } 5466f8829a4aSRandall Stewart #endif 546742551e99SRandall Stewart #if defined(INET6) 5468f8829a4aSRandall Stewart { 5469f8829a4aSRandall Stewart struct sockaddr_in6 lsa6, *to6; 5470f8829a4aSRandall Stewart 5471f8829a4aSRandall Stewart to6 = (struct sockaddr_in6 *)to; 5472f8829a4aSRandall Stewart sctp_recover_scope_mac(to6, (&lsa6)); 5473f8829a4aSRandall Stewart } 5474f8829a4aSRandall Stewart #endif 5475f8829a4aSRandall Stewart } 5476f8829a4aSRandall Stewart /* now copy out what data we can */ 5477f8829a4aSRandall Stewart if (mp == NULL) { 5478f8829a4aSRandall Stewart /* copy out each mbuf in the chain up to length */ 5479f8829a4aSRandall Stewart get_more_data: 5480f8829a4aSRandall Stewart m = control->data; 5481f8829a4aSRandall Stewart while (m) { 5482f8829a4aSRandall Stewart /* Move out all we can */ 5483f8829a4aSRandall Stewart cp_len = (int)uio->uio_resid; 5484139bc87fSRandall Stewart my_len = (int)SCTP_BUF_LEN(m); 5485f8829a4aSRandall Stewart if (cp_len > my_len) { 5486f8829a4aSRandall Stewart /* not enough in this buf */ 5487f8829a4aSRandall Stewart cp_len = my_len; 5488f8829a4aSRandall Stewart } 5489f8829a4aSRandall Stewart if (hold_rlock) { 5490f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5491f8829a4aSRandall Stewart hold_rlock = 0; 5492f8829a4aSRandall Stewart } 5493f8829a4aSRandall Stewart if (cp_len > 0) 5494f8829a4aSRandall Stewart error = uiomove(mtod(m, char *), cp_len, uio); 5495f8829a4aSRandall Stewart /* re-read */ 5496f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { 5497f8829a4aSRandall Stewart goto release; 5498f8829a4aSRandall Stewart } 54990696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && stcb && 5500f8829a4aSRandall Stewart stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { 5501f8829a4aSRandall Stewart no_rcv_needed = 1; 5502f8829a4aSRandall Stewart } 5503f8829a4aSRandall Stewart if (error) { 5504f8829a4aSRandall Stewart /* error we are out of here */ 5505f8829a4aSRandall Stewart goto release; 5506f8829a4aSRandall Stewart } 5507139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 5508139bc87fSRandall Stewart (cp_len >= SCTP_BUF_LEN(m)) && 5509f8829a4aSRandall Stewart ((control->end_added == 0) || 55100696e120SRandall Stewart (control->end_added && 55110696e120SRandall Stewart (TAILQ_NEXT(control, next) == NULL))) 5512f8829a4aSRandall Stewart ) { 5513f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5514f8829a4aSRandall Stewart hold_rlock = 1; 5515f8829a4aSRandall Stewart } 5516139bc87fSRandall Stewart if (cp_len == SCTP_BUF_LEN(m)) { 5517139bc87fSRandall Stewart if ((SCTP_BUF_NEXT(m) == NULL) && 5518139bc87fSRandall Stewart (control->end_added)) { 5519f8829a4aSRandall Stewart out_flags |= MSG_EOR; 552052129fcdSRandall Stewart if ((control->do_not_ref_stcb == 0) && 552152129fcdSRandall Stewart (control->stcb != NULL) && 552252129fcdSRandall Stewart ((control->spec_flags & M_NOTIFICATION) == 0)) 5523ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 5524f8829a4aSRandall Stewart } 5525139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5526f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5527f8829a4aSRandall Stewart } 5528f8829a4aSRandall Stewart /* we ate up the mbuf */ 5529f8829a4aSRandall Stewart if (in_flags & MSG_PEEK) { 5530f8829a4aSRandall Stewart /* just looking */ 5531139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 5532f8829a4aSRandall Stewart copied_so_far += cp_len; 5533f8829a4aSRandall Stewart } else { 5534f8829a4aSRandall Stewart /* dispose of the mbuf */ 5535b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5536f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5537139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 553880fefe0aSRandall Stewart } 5539f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 5540b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5541f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5542f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 554380fefe0aSRandall Stewart } 5544f8829a4aSRandall Stewart copied_so_far += cp_len; 5545f8829a4aSRandall Stewart freed_so_far += cp_len; 5546c4739e2fSRandall Stewart freed_so_far += MSIZE; 554718e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 5548f8829a4aSRandall Stewart control->data = sctp_m_free(m); 5549f8829a4aSRandall Stewart m = control->data; 5550f8829a4aSRandall Stewart /* 5551f8829a4aSRandall Stewart * been through it all, must hold sb 5552f8829a4aSRandall Stewart * lock ok to null tail 5553f8829a4aSRandall Stewart */ 5554f8829a4aSRandall Stewart if (control->data == NULL) { 5555a5d547adSRandall Stewart #ifdef INVARIANTS 5556f8829a4aSRandall Stewart if ((control->end_added == 0) || 5557f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 5558f8829a4aSRandall Stewart /* 5559f8829a4aSRandall Stewart * If the end is not 5560f8829a4aSRandall Stewart * added, OR the 5561f8829a4aSRandall Stewart * next is NOT null 5562f8829a4aSRandall Stewart * we MUST have the 5563f8829a4aSRandall Stewart * lock. 5564f8829a4aSRandall Stewart */ 5565f8829a4aSRandall Stewart if (mtx_owned(&inp->inp_rdata_mtx) == 0) { 5566f8829a4aSRandall Stewart panic("Hmm we don't own the lock?"); 5567f8829a4aSRandall Stewart } 5568f8829a4aSRandall Stewart } 5569f8829a4aSRandall Stewart #endif 5570f8829a4aSRandall Stewart control->tail_mbuf = NULL; 5571a5d547adSRandall Stewart #ifdef INVARIANTS 5572f8829a4aSRandall Stewart if ((control->end_added) && ((out_flags & MSG_EOR) == 0)) { 5573f8829a4aSRandall Stewart panic("end_added, nothing left and no MSG_EOR"); 5574f8829a4aSRandall Stewart } 5575f8829a4aSRandall Stewart #endif 5576f8829a4aSRandall Stewart } 5577f8829a4aSRandall Stewart } 5578f8829a4aSRandall Stewart } else { 5579f8829a4aSRandall Stewart /* Do we need to trim the mbuf? */ 5580139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5581f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5582f8829a4aSRandall Stewart } 5583f8829a4aSRandall Stewart if ((in_flags & MSG_PEEK) == 0) { 5584139bc87fSRandall Stewart SCTP_BUF_RESV_UF(m, cp_len); 5585139bc87fSRandall Stewart SCTP_BUF_LEN(m) -= cp_len; 5586b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5587f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, cp_len); 558880fefe0aSRandall Stewart } 5589f8829a4aSRandall Stewart atomic_subtract_int(&so->so_rcv.sb_cc, cp_len); 55900696e120SRandall Stewart if ((control->do_not_ref_stcb == 0) && 55910696e120SRandall Stewart stcb) { 5592f8829a4aSRandall Stewart atomic_subtract_int(&stcb->asoc.sb_cc, cp_len); 5593f8829a4aSRandall Stewart } 5594f8829a4aSRandall Stewart copied_so_far += cp_len; 5595f8829a4aSRandall Stewart freed_so_far += cp_len; 5596c4739e2fSRandall Stewart freed_so_far += MSIZE; 5597b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5598f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, control->do_not_ref_stcb ? NULL : stcb, 5599f8829a4aSRandall Stewart SCTP_LOG_SBRESULT, 0); 560080fefe0aSRandall Stewart } 560118e198d3SRandall Stewart atomic_subtract_int(&control->length, cp_len); 5602f8829a4aSRandall Stewart } else { 5603f8829a4aSRandall Stewart copied_so_far += cp_len; 5604f8829a4aSRandall Stewart } 5605f8829a4aSRandall Stewart } 5606d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) || (uio->uio_resid == 0)) { 5607f8829a4aSRandall Stewart break; 5608f8829a4aSRandall Stewart } 5609f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 5610f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 5611f8829a4aSRandall Stewart (freed_so_far >= rwnd_req)) { 5612f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5613f8829a4aSRandall Stewart } 5614f8829a4aSRandall Stewart } /* end while(m) */ 5615f8829a4aSRandall Stewart /* 5616f8829a4aSRandall Stewart * At this point we have looked at it all and we either have 5617f8829a4aSRandall Stewart * a MSG_EOR/or read all the user wants... <OR> 5618f8829a4aSRandall Stewart * control->length == 0. 5619f8829a4aSRandall Stewart */ 5620d61a0ae0SRandall Stewart if ((out_flags & MSG_EOR) && ((in_flags & MSG_PEEK) == 0)) { 5621f8829a4aSRandall Stewart /* we are done with this control */ 5622f8829a4aSRandall Stewart if (control->length == 0) { 5623f8829a4aSRandall Stewart if (control->data) { 5624a5d547adSRandall Stewart #ifdef INVARIANTS 5625f8829a4aSRandall Stewart panic("control->data not null at read eor?"); 5626f8829a4aSRandall Stewart #else 5627ad81507eSRandall Stewart SCTP_PRINTF("Strange, data left in the control buffer .. invarients would panic?\n"); 5628f8829a4aSRandall Stewart sctp_m_freem(control->data); 5629f8829a4aSRandall Stewart control->data = NULL; 5630f8829a4aSRandall Stewart #endif 5631f8829a4aSRandall Stewart } 5632f8829a4aSRandall Stewart done_with_control: 5633f8829a4aSRandall Stewart if (TAILQ_NEXT(control, next) == NULL) { 5634f8829a4aSRandall Stewart /* 5635f8829a4aSRandall Stewart * If we don't have a next we need a 5636b201f536SRandall Stewart * lock, if there is a next 5637b201f536SRandall Stewart * interrupt is filling ahead of us 5638b201f536SRandall Stewart * and we don't need a lock to 5639b201f536SRandall Stewart * remove this guy (which is the 5640b201f536SRandall Stewart * head of the queue). 5641f8829a4aSRandall Stewart */ 5642f8829a4aSRandall Stewart if (hold_rlock == 0) { 5643f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5644f8829a4aSRandall Stewart hold_rlock = 1; 5645f8829a4aSRandall Stewart } 5646f8829a4aSRandall Stewart } 5647f8829a4aSRandall Stewart TAILQ_REMOVE(&inp->read_queue, control, next); 5648f8829a4aSRandall Stewart /* Add back any hiddend data */ 5649f8829a4aSRandall Stewart if (control->held_length) { 5650f8829a4aSRandall Stewart held_length = 0; 5651f8829a4aSRandall Stewart control->held_length = 0; 5652f8829a4aSRandall Stewart wakeup_read_socket = 1; 5653f8829a4aSRandall Stewart } 565417205eccSRandall Stewart if (control->aux_data) { 565517205eccSRandall Stewart sctp_m_free(control->aux_data); 565617205eccSRandall Stewart control->aux_data = NULL; 565717205eccSRandall Stewart } 5658f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 5659f8829a4aSRandall Stewart sctp_free_remote_addr(control->whoFrom); 5660f8829a4aSRandall Stewart control->data = NULL; 5661f8829a4aSRandall Stewart sctp_free_a_readq(stcb, control); 5662f8829a4aSRandall Stewart control = NULL; 56630696e120SRandall Stewart if ((freed_so_far >= rwnd_req) && 56640696e120SRandall Stewart (no_rcv_needed == 0)) 5665f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5666f8829a4aSRandall Stewart 5667f8829a4aSRandall Stewart } else { 5668f8829a4aSRandall Stewart /* 5669f8829a4aSRandall Stewart * The user did not read all of this 5670f8829a4aSRandall Stewart * message, turn off the returned MSG_EOR 5671f8829a4aSRandall Stewart * since we are leaving more behind on the 5672f8829a4aSRandall Stewart * control to read. 5673f8829a4aSRandall Stewart */ 5674a5d547adSRandall Stewart #ifdef INVARIANTS 56750696e120SRandall Stewart if (control->end_added && 56760696e120SRandall Stewart (control->data == NULL) && 5677f8829a4aSRandall Stewart (control->tail_mbuf == NULL)) { 5678f8829a4aSRandall Stewart panic("Gak, control->length is corrupt?"); 5679f8829a4aSRandall Stewart } 5680f8829a4aSRandall Stewart #endif 5681f8829a4aSRandall Stewart no_rcv_needed = control->do_not_ref_stcb; 5682f8829a4aSRandall Stewart out_flags &= ~MSG_EOR; 5683f8829a4aSRandall Stewart } 5684f8829a4aSRandall Stewart } 5685f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 5686f8829a4aSRandall Stewart goto release; 5687f8829a4aSRandall Stewart } 5688f8829a4aSRandall Stewart if ((uio->uio_resid == 0) || 5689f8829a4aSRandall Stewart ((in_eeor_mode) && (copied_so_far >= max(so->so_rcv.sb_lowat, 1))) 5690f8829a4aSRandall Stewart ) { 5691f8829a4aSRandall Stewart goto release; 5692f8829a4aSRandall Stewart } 5693f8829a4aSRandall Stewart /* 5694f8829a4aSRandall Stewart * If I hit here the receiver wants more and this message is 5695f8829a4aSRandall Stewart * NOT done (pd-api). So two questions. Can we block? if not 5696f8829a4aSRandall Stewart * we are done. Did the user NOT set MSG_WAITALL? 5697f8829a4aSRandall Stewart */ 5698f8829a4aSRandall Stewart if (block_allowed == 0) { 5699f8829a4aSRandall Stewart goto release; 5700f8829a4aSRandall Stewart } 5701f8829a4aSRandall Stewart /* 5702f8829a4aSRandall Stewart * We need to wait for more data a few things: - We don't 5703f8829a4aSRandall Stewart * sbunlock() so we don't get someone else reading. - We 5704f8829a4aSRandall Stewart * must be sure to account for the case where what is added 5705f8829a4aSRandall Stewart * is NOT to our control when we wakeup. 5706f8829a4aSRandall Stewart */ 5707f8829a4aSRandall Stewart 5708f8829a4aSRandall Stewart /* 5709f8829a4aSRandall Stewart * Do we need to tell the transport a rwnd update might be 5710f8829a4aSRandall Stewart * needed before we go to sleep? 5711f8829a4aSRandall Stewart */ 5712f8829a4aSRandall Stewart if (((stcb) && (in_flags & MSG_PEEK) == 0) && 5713f8829a4aSRandall Stewart ((freed_so_far >= rwnd_req) && 5714f8829a4aSRandall Stewart (control->do_not_ref_stcb == 0) && 5715f8829a4aSRandall Stewart (no_rcv_needed == 0))) { 5716f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5717f8829a4aSRandall Stewart } 5718f8829a4aSRandall Stewart wait_some_more: 571944b7479bSRandall Stewart if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { 5720f8829a4aSRandall Stewart goto release; 5721f8829a4aSRandall Stewart } 5722f8829a4aSRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) 5723f8829a4aSRandall Stewart goto release; 5724f8829a4aSRandall Stewart 5725f8829a4aSRandall Stewart if (hold_rlock == 1) { 5726f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5727f8829a4aSRandall Stewart hold_rlock = 0; 5728f8829a4aSRandall Stewart } 5729f8829a4aSRandall Stewart if (hold_sblock == 0) { 5730f8829a4aSRandall Stewart SOCKBUF_LOCK(&so->so_rcv); 5731f8829a4aSRandall Stewart hold_sblock = 1; 5732f8829a4aSRandall Stewart } 5733851b7298SRandall Stewart if ((copied_so_far) && (control->length == 0) && 5734b5c16493SMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))) { 5735851b7298SRandall Stewart goto release; 5736851b7298SRandall Stewart } 5737f8829a4aSRandall Stewart if (so->so_rcv.sb_cc <= control->held_length) { 5738f8829a4aSRandall Stewart error = sbwait(&so->so_rcv); 5739f8829a4aSRandall Stewart if (error) { 5740f8829a4aSRandall Stewart goto release; 5741f8829a4aSRandall Stewart } 5742f8829a4aSRandall Stewart control->held_length = 0; 5743f8829a4aSRandall Stewart } 5744f8829a4aSRandall Stewart if (hold_sblock) { 5745f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5746f8829a4aSRandall Stewart hold_sblock = 0; 5747f8829a4aSRandall Stewart } 5748f8829a4aSRandall Stewart if (control->length == 0) { 5749f8829a4aSRandall Stewart /* still nothing here */ 5750f8829a4aSRandall Stewart if (control->end_added == 1) { 5751f8829a4aSRandall Stewart /* he aborted, or is done i.e.did a shutdown */ 5752f8829a4aSRandall Stewart out_flags |= MSG_EOR; 57539a6142d8SRandall Stewart if (control->pdapi_aborted) { 57546114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5755ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 57569a6142d8SRandall Stewart 575703b0b021SRandall Stewart out_flags |= MSG_TRUNC; 57589a6142d8SRandall Stewart } else { 57596114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5760ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 57619a6142d8SRandall Stewart } 5762f8829a4aSRandall Stewart goto done_with_control; 5763f8829a4aSRandall Stewart } 5764f8829a4aSRandall Stewart if (so->so_rcv.sb_cc > held_length) { 5765f8829a4aSRandall Stewart control->held_length = so->so_rcv.sb_cc; 5766f8829a4aSRandall Stewart held_length = 0; 5767f8829a4aSRandall Stewart } 5768f8829a4aSRandall Stewart goto wait_some_more; 5769f8829a4aSRandall Stewart } else if (control->data == NULL) { 577050cec919SRandall Stewart /* 577150cec919SRandall Stewart * we must re-sync since data is probably being 577250cec919SRandall Stewart * added 577350cec919SRandall Stewart */ 577450cec919SRandall Stewart SCTP_INP_READ_LOCK(inp); 577550cec919SRandall Stewart if ((control->length > 0) && (control->data == NULL)) { 577650cec919SRandall Stewart /* 577750cec919SRandall Stewart * big trouble.. we have the lock and its 577850cec919SRandall Stewart * corrupt? 577950cec919SRandall Stewart */ 57809c04b296SRandall Stewart #ifdef INVARIANTS 5781f8829a4aSRandall Stewart panic("Impossible data==NULL length !=0"); 57829c04b296SRandall Stewart #endif 57839c04b296SRandall Stewart out_flags |= MSG_EOR; 57849c04b296SRandall Stewart out_flags |= MSG_TRUNC; 57859c04b296SRandall Stewart control->length = 0; 57869c04b296SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 57879c04b296SRandall Stewart goto done_with_control; 5788f8829a4aSRandall Stewart } 578950cec919SRandall Stewart SCTP_INP_READ_UNLOCK(inp); 579050cec919SRandall Stewart /* We will fall around to get more data */ 579150cec919SRandall Stewart } 5792f8829a4aSRandall Stewart goto get_more_data; 5793f8829a4aSRandall Stewart } else { 579417205eccSRandall Stewart /*- 579517205eccSRandall Stewart * Give caller back the mbuf chain, 579617205eccSRandall Stewart * store in uio_resid the length 5797f8829a4aSRandall Stewart */ 579817205eccSRandall Stewart wakeup_read_socket = 0; 5799f8829a4aSRandall Stewart if ((control->end_added == 0) || 5800f8829a4aSRandall Stewart (TAILQ_NEXT(control, next) == NULL)) { 5801f8829a4aSRandall Stewart /* Need to get rlock */ 5802f8829a4aSRandall Stewart if (hold_rlock == 0) { 5803f8829a4aSRandall Stewart SCTP_INP_READ_LOCK(inp); 5804f8829a4aSRandall Stewart hold_rlock = 1; 5805f8829a4aSRandall Stewart } 5806f8829a4aSRandall Stewart } 5807139bc87fSRandall Stewart if (control->end_added) { 5808f8829a4aSRandall Stewart out_flags |= MSG_EOR; 58096114cd96SRandall Stewart if ((control->do_not_ref_stcb == 0) && ((control->spec_flags & M_NOTIFICATION) == 0)) 5810ee7f9857SRandall Stewart control->stcb->asoc.strmin[control->sinfo_stream].delivery_started = 0; 5811f8829a4aSRandall Stewart } 5812139bc87fSRandall Stewart if (control->spec_flags & M_NOTIFICATION) { 5813f8829a4aSRandall Stewart out_flags |= MSG_NOTIFICATION; 5814f8829a4aSRandall Stewart } 581517205eccSRandall Stewart uio->uio_resid = control->length; 5816f8829a4aSRandall Stewart *mp = control->data; 5817f8829a4aSRandall Stewart m = control->data; 5818f8829a4aSRandall Stewart while (m) { 5819b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5820f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5821139bc87fSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBFREE, SCTP_BUF_LEN(m)); 582280fefe0aSRandall Stewart } 5823f8829a4aSRandall Stewart sctp_sbfree(control, stcb, &so->so_rcv, m); 5824139bc87fSRandall Stewart freed_so_far += SCTP_BUF_LEN(m); 5825c4739e2fSRandall Stewart freed_so_far += MSIZE; 5826b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_SB_LOGGING_ENABLE) { 5827f8829a4aSRandall Stewart sctp_sblog(&so->so_rcv, 5828f8829a4aSRandall Stewart control->do_not_ref_stcb ? NULL : stcb, SCTP_LOG_SBRESULT, 0); 582980fefe0aSRandall Stewart } 5830139bc87fSRandall Stewart m = SCTP_BUF_NEXT(m); 5831f8829a4aSRandall Stewart } 5832f8829a4aSRandall Stewart control->data = control->tail_mbuf = NULL; 5833f8829a4aSRandall Stewart control->length = 0; 5834f8829a4aSRandall Stewart if (out_flags & MSG_EOR) { 5835f8829a4aSRandall Stewart /* Done with this control */ 5836f8829a4aSRandall Stewart goto done_with_control; 5837f8829a4aSRandall Stewart } 5838f8829a4aSRandall Stewart } 5839f8829a4aSRandall Stewart release: 5840f8829a4aSRandall Stewart if (hold_rlock == 1) { 5841f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5842f8829a4aSRandall Stewart hold_rlock = 0; 5843f8829a4aSRandall Stewart } 58447abab911SRobert Watson if (hold_sblock == 1) { 58457abab911SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 58467abab911SRobert Watson hold_sblock = 0; 5847f8829a4aSRandall Stewart } 5848f8829a4aSRandall Stewart sbunlock(&so->so_rcv); 58497abab911SRobert Watson sockbuf_lock = 0; 5850f8829a4aSRandall Stewart 5851f8829a4aSRandall Stewart release_unlocked: 5852f8829a4aSRandall Stewart if (hold_sblock) { 5853f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5854f8829a4aSRandall Stewart hold_sblock = 0; 5855f8829a4aSRandall Stewart } 5856f8829a4aSRandall Stewart if ((stcb) && (in_flags & MSG_PEEK) == 0) { 5857f8829a4aSRandall Stewart if ((freed_so_far >= rwnd_req) && 5858f8829a4aSRandall Stewart (control && (control->do_not_ref_stcb == 0)) && 5859f8829a4aSRandall Stewart (no_rcv_needed == 0)) 5860f8829a4aSRandall Stewart sctp_user_rcvd(stcb, &freed_so_far, hold_rlock, rwnd_req); 5861f8829a4aSRandall Stewart } 5862f8829a4aSRandall Stewart out: 58631b9f62a0SRandall Stewart if (msg_flags) { 58641b9f62a0SRandall Stewart *msg_flags = out_flags; 58651b9f62a0SRandall Stewart } 58669a6142d8SRandall Stewart if (((out_flags & MSG_EOR) == 0) && 58679a6142d8SRandall Stewart ((in_flags & MSG_PEEK) == 0) && 58689a6142d8SRandall Stewart (sinfo) && 5869e2e7c62eSMichael Tuexen (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) || 5870e2e7c62eSMichael Tuexen sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) { 58719a6142d8SRandall Stewart struct sctp_extrcvinfo *s_extra; 58729a6142d8SRandall Stewart 58739a6142d8SRandall Stewart s_extra = (struct sctp_extrcvinfo *)sinfo; 58749a6142d8SRandall Stewart s_extra->sreinfo_next_flags = SCTP_NO_NEXT_MSG; 58759a6142d8SRandall Stewart } 5876f8829a4aSRandall Stewart if (hold_rlock == 1) { 5877f8829a4aSRandall Stewart SCTP_INP_READ_UNLOCK(inp); 5878f8829a4aSRandall Stewart hold_rlock = 0; 5879f8829a4aSRandall Stewart } 5880f8829a4aSRandall Stewart if (hold_sblock) { 5881f8829a4aSRandall Stewart SOCKBUF_UNLOCK(&so->so_rcv); 5882f8829a4aSRandall Stewart hold_sblock = 0; 5883f8829a4aSRandall Stewart } 58847abab911SRobert Watson if (sockbuf_lock) { 58857abab911SRobert Watson sbunlock(&so->so_rcv); 58867abab911SRobert Watson } 588750cec919SRandall Stewart if (freecnt_applied) { 5888f8829a4aSRandall Stewart /* 5889f8829a4aSRandall Stewart * The lock on the socket buffer protects us so the free 5890f8829a4aSRandall Stewart * code will stop. But since we used the socketbuf lock and 5891f8829a4aSRandall Stewart * the sender uses the tcb_lock to increment, we need to use 5892f8829a4aSRandall Stewart * the atomic add to the refcnt. 5893f8829a4aSRandall Stewart */ 589450cec919SRandall Stewart if (stcb == NULL) { 5895df6e0cc3SRandall Stewart #ifdef INVARIANTS 589650cec919SRandall Stewart panic("stcb for refcnt has gone NULL?"); 5897df6e0cc3SRandall Stewart goto stage_left; 5898df6e0cc3SRandall Stewart #else 5899df6e0cc3SRandall Stewart goto stage_left; 5900df6e0cc3SRandall Stewart #endif 590150cec919SRandall Stewart } 590250cec919SRandall Stewart atomic_add_int(&stcb->asoc.refcnt, -1); 5903f8829a4aSRandall Stewart freecnt_applied = 0; 5904f8829a4aSRandall Stewart /* Save the value back for next time */ 5905f8829a4aSRandall Stewart stcb->freed_by_sorcv_sincelast = freed_so_far; 5906f8829a4aSRandall Stewart } 5907b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_RECV_RWND_LOGGING_ENABLE) { 5908f8829a4aSRandall Stewart if (stcb) { 5909f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 5910f8829a4aSRandall Stewart freed_so_far, 5911f8829a4aSRandall Stewart ((uio) ? (slen - uio->uio_resid) : slen), 5912f8829a4aSRandall Stewart stcb->asoc.my_rwnd, 5913f8829a4aSRandall Stewart so->so_rcv.sb_cc); 5914f8829a4aSRandall Stewart } else { 5915f8829a4aSRandall Stewart sctp_misc_ints(SCTP_SORECV_DONE, 5916f8829a4aSRandall Stewart freed_so_far, 5917f8829a4aSRandall Stewart ((uio) ? (slen - uio->uio_resid) : slen), 5918f8829a4aSRandall Stewart 0, 5919f8829a4aSRandall Stewart so->so_rcv.sb_cc); 5920f8829a4aSRandall Stewart } 592180fefe0aSRandall Stewart } 5922df6e0cc3SRandall Stewart stage_left: 5923f8829a4aSRandall Stewart if (wakeup_read_socket) { 5924f8829a4aSRandall Stewart sctp_sorwakeup(inp, so); 5925f8829a4aSRandall Stewart } 5926f8829a4aSRandall Stewart return (error); 5927f8829a4aSRandall Stewart } 5928f8829a4aSRandall Stewart 5929f8829a4aSRandall Stewart 5930f8829a4aSRandall Stewart #ifdef SCTP_MBUF_LOGGING 5931f8829a4aSRandall Stewart struct mbuf * 5932f8829a4aSRandall Stewart sctp_m_free(struct mbuf *m) 5933f8829a4aSRandall Stewart { 5934b3f1ea41SRandall Stewart if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_MBUF_LOGGING_ENABLE) { 5935139bc87fSRandall Stewart if (SCTP_BUF_IS_EXTENDED(m)) { 5936f8829a4aSRandall Stewart sctp_log_mb(m, SCTP_MBUF_IFREE); 5937f8829a4aSRandall Stewart } 593880fefe0aSRandall Stewart } 5939f8829a4aSRandall Stewart return (m_free(m)); 5940f8829a4aSRandall Stewart } 5941f8829a4aSRandall Stewart 5942f8829a4aSRandall Stewart void 5943f8829a4aSRandall Stewart sctp_m_freem(struct mbuf *mb) 5944f8829a4aSRandall Stewart { 5945f8829a4aSRandall Stewart while (mb != NULL) 5946f8829a4aSRandall Stewart mb = sctp_m_free(mb); 5947f8829a4aSRandall Stewart } 5948f8829a4aSRandall Stewart 5949f8829a4aSRandall Stewart #endif 5950f8829a4aSRandall Stewart 595142551e99SRandall Stewart int 595242551e99SRandall Stewart sctp_dynamic_set_primary(struct sockaddr *sa, uint32_t vrf_id) 595342551e99SRandall Stewart { 595442551e99SRandall Stewart /* 595542551e99SRandall Stewart * Given a local address. For all associations that holds the 595642551e99SRandall Stewart * address, request a peer-set-primary. 595742551e99SRandall Stewart */ 595842551e99SRandall Stewart struct sctp_ifa *ifa; 595942551e99SRandall Stewart struct sctp_laddr *wi; 596042551e99SRandall Stewart 596142551e99SRandall Stewart ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0); 596242551e99SRandall Stewart if (ifa == NULL) { 5963c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, EADDRNOTAVAIL); 596442551e99SRandall Stewart return (EADDRNOTAVAIL); 596542551e99SRandall Stewart } 596642551e99SRandall Stewart /* 596742551e99SRandall Stewart * Now that we have the ifa we must awaken the iterator with this 596842551e99SRandall Stewart * message. 596942551e99SRandall Stewart */ 5970b3f1ea41SRandall Stewart wi = SCTP_ZONE_GET(SCTP_BASE_INFO(ipi_zone_laddr), struct sctp_laddr); 597142551e99SRandall Stewart if (wi == NULL) { 5972c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTPUTIL, ENOMEM); 597342551e99SRandall Stewart return (ENOMEM); 597442551e99SRandall Stewart } 597542551e99SRandall Stewart /* Now incr the count and int wi structure */ 597642551e99SRandall Stewart SCTP_INCR_LADDR_COUNT(); 597742551e99SRandall Stewart bzero(wi, sizeof(*wi)); 5978d61a0ae0SRandall Stewart (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); 597942551e99SRandall Stewart wi->ifa = ifa; 598042551e99SRandall Stewart wi->action = SCTP_SET_PRIM_ADDR; 598142551e99SRandall Stewart atomic_add_int(&ifa->refcount, 1); 598242551e99SRandall Stewart 598342551e99SRandall Stewart /* Now add it to the work queue */ 5984f7517433SRandall Stewart SCTP_WQ_ADDR_LOCK(); 598542551e99SRandall Stewart /* 598642551e99SRandall Stewart * Should this really be a tailq? As it is we will process the 598742551e99SRandall Stewart * newest first :-0 598842551e99SRandall Stewart */ 5989b3f1ea41SRandall Stewart LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); 5990f7517433SRandall Stewart SCTP_WQ_ADDR_UNLOCK(); 599142551e99SRandall Stewart sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, 599242551e99SRandall Stewart (struct sctp_inpcb *)NULL, 599342551e99SRandall Stewart (struct sctp_tcb *)NULL, 599442551e99SRandall Stewart (struct sctp_nets *)NULL); 599542551e99SRandall Stewart return (0); 599642551e99SRandall Stewart } 599742551e99SRandall Stewart 599842551e99SRandall Stewart 5999f8829a4aSRandall Stewart int 600017205eccSRandall Stewart sctp_soreceive(struct socket *so, 600117205eccSRandall Stewart struct sockaddr **psa, 600217205eccSRandall Stewart struct uio *uio, 600317205eccSRandall Stewart struct mbuf **mp0, 600417205eccSRandall Stewart struct mbuf **controlp, 600517205eccSRandall Stewart int *flagsp) 6006f8829a4aSRandall Stewart { 6007f8829a4aSRandall Stewart int error, fromlen; 6008f8829a4aSRandall Stewart uint8_t sockbuf[256]; 6009f8829a4aSRandall Stewart struct sockaddr *from; 6010f8829a4aSRandall Stewart struct sctp_extrcvinfo sinfo; 6011f8829a4aSRandall Stewart int filling_sinfo = 1; 6012f8829a4aSRandall Stewart struct sctp_inpcb *inp; 6013f8829a4aSRandall Stewart 6014f8829a4aSRandall Stewart inp = (struct sctp_inpcb *)so->so_pcb; 6015f8829a4aSRandall Stewart /* pickup the assoc we are reading from */ 6016f8829a4aSRandall Stewart if (inp == NULL) { 6017c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6018f8829a4aSRandall Stewart return (EINVAL); 6019f8829a4aSRandall Stewart } 6020e2e7c62eSMichael Tuexen if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) && 6021e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) && 6022e2e7c62eSMichael Tuexen sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) || 6023f8829a4aSRandall Stewart (controlp == NULL)) { 6024f8829a4aSRandall Stewart /* user does not want the sndrcv ctl */ 6025f8829a4aSRandall Stewart filling_sinfo = 0; 6026f8829a4aSRandall Stewart } 6027f8829a4aSRandall Stewart if (psa) { 6028f8829a4aSRandall Stewart from = (struct sockaddr *)sockbuf; 6029f8829a4aSRandall Stewart fromlen = sizeof(sockbuf); 6030f8829a4aSRandall Stewart from->sa_len = 0; 6031f8829a4aSRandall Stewart } else { 6032f8829a4aSRandall Stewart from = NULL; 6033f8829a4aSRandall Stewart fromlen = 0; 6034f8829a4aSRandall Stewart } 6035f8829a4aSRandall Stewart 6036f8829a4aSRandall Stewart error = sctp_sorecvmsg(so, uio, mp0, from, fromlen, flagsp, 6037f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo, filling_sinfo); 6038f8829a4aSRandall Stewart if ((controlp) && (filling_sinfo)) { 6039f8829a4aSRandall Stewart /* copy back the sinfo in a CMSG format */ 6040f8829a4aSRandall Stewart if (filling_sinfo) 6041f8829a4aSRandall Stewart *controlp = sctp_build_ctl_nchunk(inp, 6042f8829a4aSRandall Stewart (struct sctp_sndrcvinfo *)&sinfo); 6043f8829a4aSRandall Stewart else 6044f8829a4aSRandall Stewart *controlp = NULL; 6045f8829a4aSRandall Stewart } 6046f8829a4aSRandall Stewart if (psa) { 6047f8829a4aSRandall Stewart /* copy back the address info */ 6048f8829a4aSRandall Stewart if (from && from->sa_len) { 6049f8829a4aSRandall Stewart *psa = sodupsockaddr(from, M_NOWAIT); 6050f8829a4aSRandall Stewart } else { 6051f8829a4aSRandall Stewart *psa = NULL; 6052f8829a4aSRandall Stewart } 6053f8829a4aSRandall Stewart } 6054f8829a4aSRandall Stewart return (error); 6055f8829a4aSRandall Stewart } 605617205eccSRandall Stewart 605717205eccSRandall Stewart 605817205eccSRandall Stewart 605917205eccSRandall Stewart 606017205eccSRandall Stewart 606117205eccSRandall Stewart int 6062d61a0ae0SRandall Stewart sctp_connectx_helper_add(struct sctp_tcb *stcb, struct sockaddr *addr, 6063d61a0ae0SRandall Stewart int totaddr, int *error) 606417205eccSRandall Stewart { 606517205eccSRandall Stewart int added = 0; 606617205eccSRandall Stewart int i; 606717205eccSRandall Stewart struct sctp_inpcb *inp; 606817205eccSRandall Stewart struct sockaddr *sa; 606917205eccSRandall Stewart size_t incr = 0; 607017205eccSRandall Stewart 607192776dfdSMichael Tuexen #ifdef INET 607292776dfdSMichael Tuexen struct sockaddr_in *sin; 607392776dfdSMichael Tuexen 607492776dfdSMichael Tuexen #endif 607592776dfdSMichael Tuexen #ifdef INET6 607692776dfdSMichael Tuexen struct sockaddr_in6 *sin6; 607792776dfdSMichael Tuexen 607892776dfdSMichael Tuexen #endif 607992776dfdSMichael Tuexen 608017205eccSRandall Stewart sa = addr; 608117205eccSRandall Stewart inp = stcb->sctp_ep; 608217205eccSRandall Stewart *error = 0; 608317205eccSRandall Stewart for (i = 0; i < totaddr; i++) { 6084ea5eba11SMichael Tuexen switch (sa->sa_family) { 6085ea5eba11SMichael Tuexen #ifdef INET 6086ea5eba11SMichael Tuexen case AF_INET: 608717205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 608892776dfdSMichael Tuexen sin = (struct sockaddr_in *)sa; 608992776dfdSMichael Tuexen if ((sin->sin_addr.s_addr == INADDR_ANY) || 609092776dfdSMichael Tuexen (sin->sin_addr.s_addr == INADDR_BROADCAST) || 609192776dfdSMichael Tuexen IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 609292776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 609392776dfdSMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 609492776dfdSMichael Tuexen *error = EINVAL; 609592776dfdSMichael Tuexen goto out_now; 609692776dfdSMichael Tuexen } 6097ca85e948SMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { 609817205eccSRandall Stewart /* assoc gone no un-lock */ 6099c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6100c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); 610117205eccSRandall Stewart *error = ENOBUFS; 610217205eccSRandall Stewart goto out_now; 610317205eccSRandall Stewart } 610417205eccSRandall Stewart added++; 6105ea5eba11SMichael Tuexen break; 6106ea5eba11SMichael Tuexen #endif 6107ea5eba11SMichael Tuexen #ifdef INET6 6108ea5eba11SMichael Tuexen case AF_INET6: 610917205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 611092776dfdSMichael Tuexen sin6 = (struct sockaddr_in6 *)sa; 611192776dfdSMichael Tuexen if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) || 611292776dfdSMichael Tuexen IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 611392776dfdSMichael Tuexen SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 611492776dfdSMichael Tuexen (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); 611592776dfdSMichael Tuexen *error = EINVAL; 611692776dfdSMichael Tuexen goto out_now; 611792776dfdSMichael Tuexen } 6118ca85e948SMichael Tuexen if (sctp_add_remote_addr(stcb, sa, NULL, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { 611917205eccSRandall Stewart /* assoc gone no un-lock */ 6120c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOBUFS); 6121c4739e2fSRandall Stewart (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); 612217205eccSRandall Stewart *error = ENOBUFS; 612317205eccSRandall Stewart goto out_now; 612417205eccSRandall Stewart } 612517205eccSRandall Stewart added++; 6126ea5eba11SMichael Tuexen break; 6127ea5eba11SMichael Tuexen #endif 6128ea5eba11SMichael Tuexen default: 6129ea5eba11SMichael Tuexen break; 613017205eccSRandall Stewart } 613117205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 613217205eccSRandall Stewart } 613317205eccSRandall Stewart out_now: 613417205eccSRandall Stewart return (added); 613517205eccSRandall Stewart } 613617205eccSRandall Stewart 613717205eccSRandall Stewart struct sctp_tcb * 6138d61a0ae0SRandall Stewart sctp_connectx_helper_find(struct sctp_inpcb *inp, struct sockaddr *addr, 6139d61a0ae0SRandall Stewart int *totaddr, int *num_v4, int *num_v6, int *error, 6140d61a0ae0SRandall Stewart int limit, int *bad_addr) 614117205eccSRandall Stewart { 614217205eccSRandall Stewart struct sockaddr *sa; 614317205eccSRandall Stewart struct sctp_tcb *stcb = NULL; 614417205eccSRandall Stewart size_t incr, at, i; 614517205eccSRandall Stewart 614617205eccSRandall Stewart at = incr = 0; 614717205eccSRandall Stewart sa = addr; 6148ea5eba11SMichael Tuexen 614917205eccSRandall Stewart *error = *num_v6 = *num_v4 = 0; 615017205eccSRandall Stewart /* account and validate addresses */ 61514c9179adSRandall Stewart for (i = 0; i < (size_t)*totaddr; i++) { 6152ea5eba11SMichael Tuexen switch (sa->sa_family) { 6153ea5eba11SMichael Tuexen #ifdef INET 6154ea5eba11SMichael Tuexen case AF_INET: 615517205eccSRandall Stewart (*num_v4) += 1; 615617205eccSRandall Stewart incr = sizeof(struct sockaddr_in); 6157d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6158c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6159d61a0ae0SRandall Stewart *error = EINVAL; 6160d61a0ae0SRandall Stewart *bad_addr = 1; 6161d61a0ae0SRandall Stewart return (NULL); 6162d61a0ae0SRandall Stewart } 6163ea5eba11SMichael Tuexen break; 6164ea5eba11SMichael Tuexen #endif 6165ea5eba11SMichael Tuexen #ifdef INET6 6166ea5eba11SMichael Tuexen case AF_INET6: 6167ea5eba11SMichael Tuexen { 616817205eccSRandall Stewart struct sockaddr_in6 *sin6; 616917205eccSRandall Stewart 617017205eccSRandall Stewart sin6 = (struct sockaddr_in6 *)sa; 617117205eccSRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 617217205eccSRandall Stewart /* Must be non-mapped for connectx */ 6173c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 617417205eccSRandall Stewart *error = EINVAL; 6175d61a0ae0SRandall Stewart *bad_addr = 1; 617617205eccSRandall Stewart return (NULL); 617717205eccSRandall Stewart } 617817205eccSRandall Stewart (*num_v6) += 1; 617917205eccSRandall Stewart incr = sizeof(struct sockaddr_in6); 6180d61a0ae0SRandall Stewart if (sa->sa_len != incr) { 6181c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6182d61a0ae0SRandall Stewart *error = EINVAL; 6183d61a0ae0SRandall Stewart *bad_addr = 1; 6184d61a0ae0SRandall Stewart return (NULL); 6185d61a0ae0SRandall Stewart } 6186ea5eba11SMichael Tuexen break; 6187ea5eba11SMichael Tuexen } 6188ea5eba11SMichael Tuexen #endif 6189ea5eba11SMichael Tuexen default: 619017205eccSRandall Stewart *totaddr = i; 619117205eccSRandall Stewart /* we are done */ 619217205eccSRandall Stewart break; 619317205eccSRandall Stewart } 6194ea5eba11SMichael Tuexen if (i == (size_t)*totaddr) { 6195ea5eba11SMichael Tuexen break; 6196ea5eba11SMichael Tuexen } 6197d61a0ae0SRandall Stewart SCTP_INP_INCR_REF(inp); 619817205eccSRandall Stewart stcb = sctp_findassociation_ep_addr(&inp, sa, NULL, NULL, NULL); 619917205eccSRandall Stewart if (stcb != NULL) { 620017205eccSRandall Stewart /* Already have or am bring up an association */ 620117205eccSRandall Stewart return (stcb); 6202d61a0ae0SRandall Stewart } else { 6203d61a0ae0SRandall Stewart SCTP_INP_DECR_REF(inp); 620417205eccSRandall Stewart } 62054c9179adSRandall Stewart if ((at + incr) > (size_t)limit) { 620617205eccSRandall Stewart *totaddr = i; 620717205eccSRandall Stewart break; 620817205eccSRandall Stewart } 620917205eccSRandall Stewart sa = (struct sockaddr *)((caddr_t)sa + incr); 621017205eccSRandall Stewart } 621117205eccSRandall Stewart return ((struct sctp_tcb *)NULL); 621217205eccSRandall Stewart } 621335918f85SRandall Stewart 621435918f85SRandall Stewart /* 621535918f85SRandall Stewart * sctp_bindx(ADD) for one address. 621635918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 621735918f85SRandall Stewart */ 621835918f85SRandall Stewart void 621935918f85SRandall Stewart sctp_bindx_add_address(struct socket *so, struct sctp_inpcb *inp, 622035918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 622135918f85SRandall Stewart uint32_t vrf_id, int *error, void *p) 622235918f85SRandall Stewart { 622335918f85SRandall Stewart struct sockaddr *addr_touse; 62245e2c2d87SRandall Stewart 62255e2c2d87SRandall Stewart #ifdef INET6 622635918f85SRandall Stewart struct sockaddr_in sin; 622735918f85SRandall Stewart 62285e2c2d87SRandall Stewart #endif 62295e2c2d87SRandall Stewart 623035918f85SRandall Stewart /* see if we're bound all already! */ 623135918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6232c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 623335918f85SRandall Stewart *error = EINVAL; 623435918f85SRandall Stewart return; 623535918f85SRandall Stewart } 623635918f85SRandall Stewart addr_touse = sa; 6237ea5eba11SMichael Tuexen #ifdef INET6 623835918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 623935918f85SRandall Stewart struct sockaddr_in6 *sin6; 624035918f85SRandall Stewart 624135918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6242c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 624335918f85SRandall Stewart *error = EINVAL; 624435918f85SRandall Stewart return; 624535918f85SRandall Stewart } 6246db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6247db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6248c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6249db4fd95bSRandall Stewart *error = EINVAL; 6250db4fd95bSRandall Stewart return; 6251db4fd95bSRandall Stewart } 625235918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 625335918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6254db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6255db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6256db4fd95bSRandall Stewart /* can't bind v4-mapped on PF_INET sockets */ 6257c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6258db4fd95bSRandall Stewart *error = EINVAL; 6259db4fd95bSRandall Stewart return; 6260db4fd95bSRandall Stewart } 626135918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 626235918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 626335918f85SRandall Stewart } 626435918f85SRandall Stewart } 626535918f85SRandall Stewart #endif 6266ea5eba11SMichael Tuexen #ifdef INET 626735918f85SRandall Stewart if (sa->sa_family == AF_INET) { 626835918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6269c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 627035918f85SRandall Stewart *error = EINVAL; 627135918f85SRandall Stewart return; 627235918f85SRandall Stewart } 6273db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6274db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6275db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6276c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6277db4fd95bSRandall Stewart *error = EINVAL; 6278db4fd95bSRandall Stewart return; 6279db4fd95bSRandall Stewart } 628035918f85SRandall Stewart } 6281ea5eba11SMichael Tuexen #endif 628235918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { 628335918f85SRandall Stewart if (p == NULL) { 628435918f85SRandall Stewart /* Can't get proc for Net/Open BSD */ 6285c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 628635918f85SRandall Stewart *error = EINVAL; 628735918f85SRandall Stewart return; 628835918f85SRandall Stewart } 62891b649582SRandall Stewart *error = sctp_inpcb_bind(so, addr_touse, NULL, p); 629035918f85SRandall Stewart return; 629135918f85SRandall Stewart } 629235918f85SRandall Stewart /* 629335918f85SRandall Stewart * No locks required here since bind and mgmt_ep_sa all do their own 629435918f85SRandall Stewart * locking. If we do something for the FIX: below we may need to 629535918f85SRandall Stewart * lock in that case. 629635918f85SRandall Stewart */ 629735918f85SRandall Stewart if (assoc_id == 0) { 629835918f85SRandall Stewart /* add the address */ 629935918f85SRandall Stewart struct sctp_inpcb *lep; 630097c76f10SRandall Stewart struct sockaddr_in *lsin = (struct sockaddr_in *)addr_touse; 630135918f85SRandall Stewart 630297c76f10SRandall Stewart /* validate the incoming port */ 630397c76f10SRandall Stewart if ((lsin->sin_port != 0) && 630497c76f10SRandall Stewart (lsin->sin_port != inp->sctp_lport)) { 6305c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 630697c76f10SRandall Stewart *error = EINVAL; 630797c76f10SRandall Stewart return; 630897c76f10SRandall Stewart } else { 630997c76f10SRandall Stewart /* user specified 0 port, set it to existing port */ 631097c76f10SRandall Stewart lsin->sin_port = inp->sctp_lport; 631197c76f10SRandall Stewart } 631297c76f10SRandall Stewart 631335918f85SRandall Stewart lep = sctp_pcb_findep(addr_touse, 1, 0, vrf_id); 631435918f85SRandall Stewart if (lep != NULL) { 631535918f85SRandall Stewart /* 631635918f85SRandall Stewart * We must decrement the refcount since we have the 631735918f85SRandall Stewart * ep already and are binding. No remove going on 631835918f85SRandall Stewart * here. 631935918f85SRandall Stewart */ 63206d9e8f2bSRandall Stewart SCTP_INP_DECR_REF(lep); 632135918f85SRandall Stewart } 632235918f85SRandall Stewart if (lep == inp) { 632335918f85SRandall Stewart /* already bound to it.. ok */ 632435918f85SRandall Stewart return; 632535918f85SRandall Stewart } else if (lep == NULL) { 632635918f85SRandall Stewart ((struct sockaddr_in *)addr_touse)->sin_port = 0; 632735918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 632835918f85SRandall Stewart SCTP_ADD_IP_ADDRESS, 632980fefe0aSRandall Stewart vrf_id, NULL); 633035918f85SRandall Stewart } else { 633135918f85SRandall Stewart *error = EADDRINUSE; 633235918f85SRandall Stewart } 633335918f85SRandall Stewart if (*error) 633435918f85SRandall Stewart return; 633535918f85SRandall Stewart } else { 633635918f85SRandall Stewart /* 633735918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 633835918f85SRandall Stewart */ 633935918f85SRandall Stewart } 634035918f85SRandall Stewart } 634135918f85SRandall Stewart 634235918f85SRandall Stewart /* 634335918f85SRandall Stewart * sctp_bindx(DELETE) for one address. 634435918f85SRandall Stewart * assumes all arguments are valid/checked by caller. 634535918f85SRandall Stewart */ 634635918f85SRandall Stewart void 6347*7215cc1bSMichael Tuexen sctp_bindx_delete_address(struct sctp_inpcb *inp, 634835918f85SRandall Stewart struct sockaddr *sa, sctp_assoc_t assoc_id, 634935918f85SRandall Stewart uint32_t vrf_id, int *error) 635035918f85SRandall Stewart { 635135918f85SRandall Stewart struct sockaddr *addr_touse; 63525e2c2d87SRandall Stewart 63535e2c2d87SRandall Stewart #ifdef INET6 635435918f85SRandall Stewart struct sockaddr_in sin; 635535918f85SRandall Stewart 63565e2c2d87SRandall Stewart #endif 63575e2c2d87SRandall Stewart 635835918f85SRandall Stewart /* see if we're bound all already! */ 635935918f85SRandall Stewart if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 6360c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 636135918f85SRandall Stewart *error = EINVAL; 636235918f85SRandall Stewart return; 636335918f85SRandall Stewart } 636435918f85SRandall Stewart addr_touse = sa; 6365fc14de76SRandall Stewart #if defined(INET6) && !defined(__Userspace__) /* TODO port in6_sin6_2_sin */ 636635918f85SRandall Stewart if (sa->sa_family == AF_INET6) { 636735918f85SRandall Stewart struct sockaddr_in6 *sin6; 636835918f85SRandall Stewart 636935918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in6)) { 6370c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 637135918f85SRandall Stewart *error = EINVAL; 637235918f85SRandall Stewart return; 637335918f85SRandall Stewart } 6374db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { 6375db4fd95bSRandall Stewart /* can only bind v6 on PF_INET6 sockets */ 6376c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6377db4fd95bSRandall Stewart *error = EINVAL; 6378db4fd95bSRandall Stewart return; 6379db4fd95bSRandall Stewart } 638035918f85SRandall Stewart sin6 = (struct sockaddr_in6 *)addr_touse; 638135918f85SRandall Stewart if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 6382db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6383db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6384db4fd95bSRandall Stewart /* can't bind mapped-v4 on PF_INET sockets */ 6385c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6386db4fd95bSRandall Stewart *error = EINVAL; 6387db4fd95bSRandall Stewart return; 6388db4fd95bSRandall Stewart } 638935918f85SRandall Stewart in6_sin6_2_sin(&sin, sin6); 639035918f85SRandall Stewart addr_touse = (struct sockaddr *)&sin; 639135918f85SRandall Stewart } 639235918f85SRandall Stewart } 639335918f85SRandall Stewart #endif 6394ea5eba11SMichael Tuexen #ifdef INET 639535918f85SRandall Stewart if (sa->sa_family == AF_INET) { 639635918f85SRandall Stewart if (sa->sa_len != sizeof(struct sockaddr_in)) { 6397c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 639835918f85SRandall Stewart *error = EINVAL; 639935918f85SRandall Stewart return; 640035918f85SRandall Stewart } 6401db4fd95bSRandall Stewart if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && 6402db4fd95bSRandall Stewart SCTP_IPV6_V6ONLY(inp)) { 6403db4fd95bSRandall Stewart /* can't bind v4 on PF_INET sockets */ 6404c4739e2fSRandall Stewart SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL); 6405db4fd95bSRandall Stewart *error = EINVAL; 6406db4fd95bSRandall Stewart return; 6407db4fd95bSRandall Stewart } 640835918f85SRandall Stewart } 6409ea5eba11SMichael Tuexen #endif 641035918f85SRandall Stewart /* 641135918f85SRandall Stewart * No lock required mgmt_ep_sa does its own locking. If the FIX: 641235918f85SRandall Stewart * below is ever changed we may need to lock before calling 641335918f85SRandall Stewart * association level binding. 641435918f85SRandall Stewart */ 641535918f85SRandall Stewart if (assoc_id == 0) { 641635918f85SRandall Stewart /* delete the address */ 641735918f85SRandall Stewart *error = sctp_addr_mgmt_ep_sa(inp, addr_touse, 641835918f85SRandall Stewart SCTP_DEL_IP_ADDRESS, 641980fefe0aSRandall Stewart vrf_id, NULL); 642035918f85SRandall Stewart } else { 642135918f85SRandall Stewart /* 642235918f85SRandall Stewart * FIX: decide whether we allow assoc based bindx 642335918f85SRandall Stewart */ 642435918f85SRandall Stewart } 642535918f85SRandall Stewart } 64261b649582SRandall Stewart 64271b649582SRandall Stewart /* 64281b649582SRandall Stewart * returns the valid local address count for an assoc, taking into account 64291b649582SRandall Stewart * all scoping rules 64301b649582SRandall Stewart */ 64311b649582SRandall Stewart int 64321b649582SRandall Stewart sctp_local_addr_count(struct sctp_tcb *stcb) 64331b649582SRandall Stewart { 64341b649582SRandall Stewart int loopback_scope, ipv4_local_scope, local_scope, site_scope; 64351b649582SRandall Stewart int ipv4_addr_legal, ipv6_addr_legal; 64361b649582SRandall Stewart struct sctp_vrf *vrf; 64371b649582SRandall Stewart struct sctp_ifn *sctp_ifn; 64381b649582SRandall Stewart struct sctp_ifa *sctp_ifa; 64391b649582SRandall Stewart int count = 0; 64401b649582SRandall Stewart 64411b649582SRandall Stewart /* Turn on all the appropriate scopes */ 64421b649582SRandall Stewart loopback_scope = stcb->asoc.loopback_scope; 64431b649582SRandall Stewart ipv4_local_scope = stcb->asoc.ipv4_local_scope; 64441b649582SRandall Stewart local_scope = stcb->asoc.local_scope; 64451b649582SRandall Stewart site_scope = stcb->asoc.site_scope; 64461b649582SRandall Stewart ipv4_addr_legal = ipv6_addr_legal = 0; 64471b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { 64481b649582SRandall Stewart ipv6_addr_legal = 1; 64491b649582SRandall Stewart if (SCTP_IPV6_V6ONLY(stcb->sctp_ep) == 0) { 64501b649582SRandall Stewart ipv4_addr_legal = 1; 64511b649582SRandall Stewart } 64521b649582SRandall Stewart } else { 64531b649582SRandall Stewart ipv4_addr_legal = 1; 64541b649582SRandall Stewart } 64551b649582SRandall Stewart 6456c99efcf6SRandall Stewart SCTP_IPI_ADDR_RLOCK(); 64571b649582SRandall Stewart vrf = sctp_find_vrf(stcb->asoc.vrf_id); 64581b649582SRandall Stewart if (vrf == NULL) { 64591b649582SRandall Stewart /* no vrf, no addresses */ 6460c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 64611b649582SRandall Stewart return (0); 64621b649582SRandall Stewart } 64631b649582SRandall Stewart if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { 64641b649582SRandall Stewart /* 64651b649582SRandall Stewart * bound all case: go through all ifns on the vrf 64661b649582SRandall Stewart */ 64671b649582SRandall Stewart LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { 64681b649582SRandall Stewart if ((loopback_scope == 0) && 64691b649582SRandall Stewart SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { 64701b649582SRandall Stewart continue; 64711b649582SRandall Stewart } 64721b649582SRandall Stewart LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { 64731b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, sctp_ifa)) 64741b649582SRandall Stewart continue; 64755e2c2d87SRandall Stewart switch (sctp_ifa->address.sa.sa_family) { 6476ea5eba11SMichael Tuexen #ifdef INET 64775e2c2d87SRandall Stewart case AF_INET: 64785e2c2d87SRandall Stewart if (ipv4_addr_legal) { 64791b649582SRandall Stewart struct sockaddr_in *sin; 64801b649582SRandall Stewart 64811b649582SRandall Stewart sin = (struct sockaddr_in *)&sctp_ifa->address.sa; 64821b649582SRandall Stewart if (sin->sin_addr.s_addr == 0) { 64835e2c2d87SRandall Stewart /* 64845e2c2d87SRandall Stewart * skip unspecified 64855e2c2d87SRandall Stewart * addrs 64865e2c2d87SRandall Stewart */ 64871b649582SRandall Stewart continue; 64881b649582SRandall Stewart } 64891b649582SRandall Stewart if ((ipv4_local_scope == 0) && 64901b649582SRandall Stewart (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { 64911b649582SRandall Stewart continue; 64921b649582SRandall Stewart } 64931b649582SRandall Stewart /* count this one */ 64941b649582SRandall Stewart count++; 64955e2c2d87SRandall Stewart } else { 64965e2c2d87SRandall Stewart continue; 64975e2c2d87SRandall Stewart } 64985e2c2d87SRandall Stewart break; 6499ea5eba11SMichael Tuexen #endif 65005e2c2d87SRandall Stewart #ifdef INET6 65015e2c2d87SRandall Stewart case AF_INET6: 65025e2c2d87SRandall Stewart if (ipv6_addr_legal) { 65031b649582SRandall Stewart struct sockaddr_in6 *sin6; 65041b649582SRandall Stewart 65051b649582SRandall Stewart sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; 65061b649582SRandall Stewart if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 65071b649582SRandall Stewart continue; 65081b649582SRandall Stewart } 65091b649582SRandall Stewart if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 65101b649582SRandall Stewart if (local_scope == 0) 65111b649582SRandall Stewart continue; 65121b649582SRandall Stewart if (sin6->sin6_scope_id == 0) { 65131b649582SRandall Stewart if (sa6_recoverscope(sin6) != 0) 65141b649582SRandall Stewart /* 65155e2c2d87SRandall Stewart * 65165e2c2d87SRandall Stewart * bad 65175e2c2d87SRandall Stewart * 65185e2c2d87SRandall Stewart * li 65195e2c2d87SRandall Stewart * nk 65205e2c2d87SRandall Stewart * 65215e2c2d87SRandall Stewart * loc 65225e2c2d87SRandall Stewart * al 65235e2c2d87SRandall Stewart * 65245e2c2d87SRandall Stewart * add 65255e2c2d87SRandall Stewart * re 65265e2c2d87SRandall Stewart * ss 65275e2c2d87SRandall Stewart * */ 65281b649582SRandall Stewart continue; 65291b649582SRandall Stewart } 65301b649582SRandall Stewart } 65311b649582SRandall Stewart if ((site_scope == 0) && 65321b649582SRandall Stewart (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { 65331b649582SRandall Stewart continue; 65341b649582SRandall Stewart } 65351b649582SRandall Stewart /* count this one */ 65361b649582SRandall Stewart count++; 65371b649582SRandall Stewart } 65385e2c2d87SRandall Stewart break; 65395e2c2d87SRandall Stewart #endif 65405e2c2d87SRandall Stewart default: 65415e2c2d87SRandall Stewart /* TSNH */ 65425e2c2d87SRandall Stewart break; 65435e2c2d87SRandall Stewart } 65441b649582SRandall Stewart } 65451b649582SRandall Stewart } 65461b649582SRandall Stewart } else { 65471b649582SRandall Stewart /* 65481b649582SRandall Stewart * subset bound case 65491b649582SRandall Stewart */ 65501b649582SRandall Stewart struct sctp_laddr *laddr; 65511b649582SRandall Stewart 65521b649582SRandall Stewart LIST_FOREACH(laddr, &stcb->sctp_ep->sctp_addr_list, 65531b649582SRandall Stewart sctp_nxt_addr) { 65541b649582SRandall Stewart if (sctp_is_addr_restricted(stcb, laddr->ifa)) { 65551b649582SRandall Stewart continue; 65561b649582SRandall Stewart } 65571b649582SRandall Stewart /* count this one */ 65581b649582SRandall Stewart count++; 65591b649582SRandall Stewart } 65601b649582SRandall Stewart } 6561c99efcf6SRandall Stewart SCTP_IPI_ADDR_RUNLOCK(); 65621b649582SRandall Stewart return (count); 65631b649582SRandall Stewart } 6564c4739e2fSRandall Stewart 6565c4739e2fSRandall Stewart #if defined(SCTP_LOCAL_TRACE_BUF) 6566c4739e2fSRandall Stewart 6567c4739e2fSRandall Stewart void 6568b27a6b7dSRandall 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) 6569c4739e2fSRandall Stewart { 6570b27a6b7dSRandall Stewart uint32_t saveindex, newindex; 6571c4739e2fSRandall Stewart 6572c4739e2fSRandall Stewart do { 6573b3f1ea41SRandall Stewart saveindex = SCTP_BASE_SYSCTL(sctp_log).index; 6574c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 6575c4739e2fSRandall Stewart newindex = 1; 6576c4739e2fSRandall Stewart } else { 6577c4739e2fSRandall Stewart newindex = saveindex + 1; 6578c4739e2fSRandall Stewart } 6579b3f1ea41SRandall Stewart } while (atomic_cmpset_int(&SCTP_BASE_SYSCTL(sctp_log).index, saveindex, newindex) == 0); 6580c4739e2fSRandall Stewart if (saveindex >= SCTP_MAX_LOGGING_SIZE) { 6581c4739e2fSRandall Stewart saveindex = 0; 6582c4739e2fSRandall Stewart } 6583b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].timestamp = SCTP_GET_CYCLECOUNT; 6584b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].subsys = subsys; 6585b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[0] = a; 6586b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[1] = b; 6587b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[2] = c; 6588b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[3] = d; 6589b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[4] = e; 6590b3f1ea41SRandall Stewart SCTP_BASE_SYSCTL(sctp_log).entry[saveindex].params[5] = f; 6591c4739e2fSRandall Stewart } 6592c4739e2fSRandall Stewart 6593c4739e2fSRandall Stewart #endif 6594ea5eba11SMichael Tuexen /* XXX: Remove the #ifdef after tunneling over IPv6 works also on FreeBSD. */ 6595ea5eba11SMichael Tuexen #ifdef INET 6596c54a18d2SRandall Stewart /* We will need to add support 6597c54a18d2SRandall Stewart * to bind the ports and such here 6598c54a18d2SRandall Stewart * so we can do UDP tunneling. In 6599c54a18d2SRandall Stewart * the mean-time, we return error 6600c54a18d2SRandall Stewart */ 6601a99b6783SRandall Stewart #include <netinet/udp.h> 6602a99b6783SRandall Stewart #include <netinet/udp_var.h> 6603a99b6783SRandall Stewart #include <sys/proc.h> 6604a1f2f7a5SRandall Stewart #ifdef INET6 6605a99b6783SRandall Stewart #include <netinet6/sctp6_var.h> 6606a1f2f7a5SRandall Stewart #endif 6607a99b6783SRandall Stewart 6608a99b6783SRandall Stewart static void 6609a99b6783SRandall Stewart sctp_recv_udp_tunneled_packet(struct mbuf *m, int off, struct inpcb *ignored) 6610a99b6783SRandall Stewart { 6611a99b6783SRandall Stewart struct ip *iph; 6612a99b6783SRandall Stewart struct mbuf *sp, *last; 6613a99b6783SRandall Stewart struct udphdr *uhdr; 6614e6194c2eSMichael Tuexen uint16_t port = 0; 6615a99b6783SRandall Stewart int header_size = sizeof(struct udphdr) + sizeof(struct sctphdr); 6616a99b6783SRandall Stewart 6617a99b6783SRandall Stewart /* 6618a99b6783SRandall Stewart * Split out the mbuf chain. Leave the IP header in m, place the 6619a99b6783SRandall Stewart * rest in the sp. 6620a99b6783SRandall Stewart */ 6621a99b6783SRandall Stewart if ((m->m_flags & M_PKTHDR) == 0) { 6622a99b6783SRandall Stewart /* Can't handle one that is not a pkt hdr */ 6623a99b6783SRandall Stewart goto out; 6624a99b6783SRandall Stewart } 6625a99b6783SRandall Stewart /* pull the src port */ 6626a99b6783SRandall Stewart iph = mtod(m, struct ip *); 6627a99b6783SRandall Stewart uhdr = (struct udphdr *)((caddr_t)iph + off); 6628a99b6783SRandall Stewart 6629a99b6783SRandall Stewart port = uhdr->uh_sport; 6630a99b6783SRandall Stewart sp = m_split(m, off, M_DONTWAIT); 6631a99b6783SRandall Stewart if (sp == NULL) { 6632a99b6783SRandall Stewart /* Gak, drop packet, we can't do a split */ 6633a99b6783SRandall Stewart goto out; 6634a99b6783SRandall Stewart } 6635a99b6783SRandall Stewart if (sp->m_pkthdr.len < header_size) { 6636a99b6783SRandall Stewart /* Gak, packet can't have an SCTP header in it - to small */ 6637a99b6783SRandall Stewart m_freem(sp); 6638a99b6783SRandall Stewart goto out; 6639a99b6783SRandall Stewart } 6640a99b6783SRandall Stewart /* ok now pull up the UDP header and SCTP header together */ 6641a99b6783SRandall Stewart sp = m_pullup(sp, header_size); 6642a99b6783SRandall Stewart if (sp == NULL) { 6643a99b6783SRandall Stewart /* Gak pullup failed */ 6644a99b6783SRandall Stewart goto out; 6645a99b6783SRandall Stewart } 6646a99b6783SRandall Stewart /* trim out the UDP header */ 6647a99b6783SRandall Stewart m_adj(sp, sizeof(struct udphdr)); 6648a99b6783SRandall Stewart 6649a99b6783SRandall Stewart /* Now reconstruct the mbuf chain */ 6650a99b6783SRandall Stewart /* 1) find last one */ 6651a99b6783SRandall Stewart last = m; 6652a99b6783SRandall Stewart while (last->m_next != NULL) { 6653a99b6783SRandall Stewart last = last->m_next; 6654a99b6783SRandall Stewart } 6655a99b6783SRandall Stewart last->m_next = sp; 6656a99b6783SRandall Stewart m->m_pkthdr.len += sp->m_pkthdr.len; 6657a99b6783SRandall Stewart last = m; 6658a99b6783SRandall Stewart while (last != NULL) { 6659a99b6783SRandall Stewart last = last->m_next; 6660a99b6783SRandall Stewart } 6661a99b6783SRandall Stewart /* Now its ready for sctp_input or sctp6_input */ 6662a99b6783SRandall Stewart iph = mtod(m, struct ip *); 6663a99b6783SRandall Stewart switch (iph->ip_v) { 6664e6194c2eSMichael Tuexen #ifdef INET 6665a99b6783SRandall Stewart case IPVERSION: 6666a99b6783SRandall Stewart { 6667e6194c2eSMichael Tuexen uint16_t len; 6668e6194c2eSMichael Tuexen 6669a99b6783SRandall Stewart /* its IPv4 */ 6670a99b6783SRandall Stewart len = SCTP_GET_IPV4_LENGTH(iph); 6671a99b6783SRandall Stewart len -= sizeof(struct udphdr); 6672a99b6783SRandall Stewart SCTP_GET_IPV4_LENGTH(iph) = len; 6673a99b6783SRandall Stewart sctp_input_with_port(m, off, port); 6674a99b6783SRandall Stewart break; 6675a99b6783SRandall Stewart } 6676e6194c2eSMichael Tuexen #endif 6677a99b6783SRandall Stewart #ifdef INET6 6678a99b6783SRandall Stewart case IPV6_VERSION >> 4: 6679a99b6783SRandall Stewart { 6680a99b6783SRandall Stewart /* its IPv6 - NOT supported */ 6681a99b6783SRandall Stewart goto out; 6682a99b6783SRandall Stewart break; 6683a99b6783SRandall Stewart 6684a99b6783SRandall Stewart } 6685a99b6783SRandall Stewart #endif 6686a99b6783SRandall Stewart default: 6687a99b6783SRandall Stewart { 6688a99b6783SRandall Stewart m_freem(m); 6689a99b6783SRandall Stewart break; 6690a99b6783SRandall Stewart } 6691a99b6783SRandall Stewart } 6692a99b6783SRandall Stewart return; 6693a99b6783SRandall Stewart out: 6694a99b6783SRandall Stewart m_freem(m); 6695a99b6783SRandall Stewart } 6696c54a18d2SRandall Stewart 6697c54a18d2SRandall Stewart void 6698c54a18d2SRandall Stewart sctp_over_udp_stop(void) 6699c54a18d2SRandall Stewart { 6700a99b6783SRandall Stewart struct socket *sop; 6701a99b6783SRandall Stewart 6702a99b6783SRandall Stewart /* 6703a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 6704a99b6783SRandall Stewart * for writting! 6705a99b6783SRandall Stewart */ 6706a99b6783SRandall Stewart if (SCTP_BASE_INFO(udp_tun_socket) == NULL) { 6707a99b6783SRandall Stewart /* Nothing to do */ 6708c54a18d2SRandall Stewart return; 6709c54a18d2SRandall Stewart } 6710a99b6783SRandall Stewart sop = SCTP_BASE_INFO(udp_tun_socket); 6711a99b6783SRandall Stewart soclose(sop); 6712a99b6783SRandall Stewart SCTP_BASE_INFO(udp_tun_socket) = NULL; 6713a99b6783SRandall Stewart } 6714ea5eba11SMichael Tuexen 6715c54a18d2SRandall Stewart int 6716c54a18d2SRandall Stewart sctp_over_udp_start(void) 6717c54a18d2SRandall Stewart { 6718a99b6783SRandall Stewart uint16_t port; 6719a99b6783SRandall Stewart int ret; 6720a99b6783SRandall Stewart struct sockaddr_in sin; 6721a99b6783SRandall Stewart struct socket *sop = NULL; 6722a99b6783SRandall Stewart struct thread *th; 6723a99b6783SRandall Stewart struct ucred *cred; 6724a99b6783SRandall Stewart 6725a99b6783SRandall Stewart /* 6726a99b6783SRandall Stewart * This function assumes sysctl caller holds sctp_sysctl_info_lock() 6727a99b6783SRandall Stewart * for writting! 6728a99b6783SRandall Stewart */ 6729a99b6783SRandall Stewart port = SCTP_BASE_SYSCTL(sctp_udp_tunneling_port); 6730a99b6783SRandall Stewart if (port == 0) { 6731a99b6783SRandall Stewart /* Must have a port set */ 6732a99b6783SRandall Stewart return (EINVAL); 6733a99b6783SRandall Stewart } 6734a99b6783SRandall Stewart if (SCTP_BASE_INFO(udp_tun_socket) != NULL) { 6735a99b6783SRandall Stewart /* Already running -- must stop first */ 6736a99b6783SRandall Stewart return (EALREADY); 6737a99b6783SRandall Stewart } 6738a99b6783SRandall Stewart th = curthread; 6739a99b6783SRandall Stewart cred = th->td_ucred; 6740a99b6783SRandall Stewart if ((ret = socreate(PF_INET, &sop, 6741a99b6783SRandall Stewart SOCK_DGRAM, IPPROTO_UDP, cred, th))) { 6742a99b6783SRandall Stewart return (ret); 6743a99b6783SRandall Stewart } 6744a99b6783SRandall Stewart SCTP_BASE_INFO(udp_tun_socket) = sop; 6745a99b6783SRandall Stewart /* call the special UDP hook */ 6746a99b6783SRandall Stewart ret = udp_set_kernel_tunneling(sop, sctp_recv_udp_tunneled_packet); 6747a99b6783SRandall Stewart if (ret) { 6748a99b6783SRandall Stewart goto exit_stage_left; 6749a99b6783SRandall Stewart } 6750a99b6783SRandall Stewart /* Ok we have a socket, bind it to the port */ 6751a99b6783SRandall Stewart memset(&sin, 0, sizeof(sin)); 6752a99b6783SRandall Stewart sin.sin_len = sizeof(sin); 6753a99b6783SRandall Stewart sin.sin_family = AF_INET; 6754a99b6783SRandall Stewart sin.sin_port = htons(port); 6755a99b6783SRandall Stewart ret = sobind(sop, (struct sockaddr *)&sin, th); 6756a99b6783SRandall Stewart if (ret) { 6757a99b6783SRandall Stewart /* Close up we cant get the port */ 6758a99b6783SRandall Stewart exit_stage_left: 6759a99b6783SRandall Stewart sctp_over_udp_stop(); 6760a99b6783SRandall Stewart return (ret); 6761a99b6783SRandall Stewart } 6762a99b6783SRandall Stewart /* 6763a99b6783SRandall Stewart * Ok we should now get UDP packets directly to our input routine 6764a99b6783SRandall Stewart * sctp_recv_upd_tunneled_packet(). 6765a99b6783SRandall Stewart */ 6766a99b6783SRandall Stewart return (0); 6767c54a18d2SRandall Stewart } 6768ea5eba11SMichael Tuexen 6769ea5eba11SMichael Tuexen #endif 6770