Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/netwerk/sctp/src/netinet/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 246 kB image not shown  

Quelle  sctputil.c   Sprache: C

 
/*-
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * a) Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * b) Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the distribution.
 *
 * c) Neither the name of Cisco Systems, Inc. nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */


#include <netinet/sctp_os.h>
#include <netinet/sctp_pcb.h>
#include <netinet/sctputil.h>
#include <netinet/sctp_var.h>
#include <netinet/sctp_sysctl.h>
#ifdef INET6
#if defined(__Userspace__) || defined(__FreeBSD__)
#include <netinet6/sctp6_var.h>
#endif
#endif
#include <netinet/sctp_header.h>
#include <netinet/sctp_output.h>
#include <netinet/sctp_uio.h>
#include <netinet/sctp_timer.h>
#include <netinet/sctp_indata.h>
#include <netinet/sctp_auth.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
#if defined(__Userspace__)
#include <netinet/sctp_constants.h>
#endif
#if defined(__FreeBSD__) && !defined(__Userspace__)
#include <netinet/sctp_kdtrace.h>
#if defined(INET6) || defined(INET)
#include <netinet/tcp_var.h>
#endif
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <sys/proc.h>
#ifdef INET6
#include <netinet/icmp6.h>
#endif
#endif

#if defined(_WIN32) && !defined(__Userspace__)
#if !defined(SCTP_LOCAL_TRACE_BUF)
#include "eventrace_netinet.h"
#include "sctputil.tmh" /* this is the file that will be auto generated */
#endif
#else
#ifndef KTR_SCTP
#define KTR_SCTP KTR_SUBSYS
#endif
#endif

extern const struct sctp_cc_functions sctp_cc_functions[];
extern const struct sctp_ss_functions sctp_ss_functions[];

void
sctp_sblog(struct sockbuf *sb, struct sctp_tcb *stcb, int from, int incr)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.sb.stcb = stcb;
 sctp_clog.x.sb.so_sbcc = SCTP_SBAVAIL(sb);
 if (stcb)
  sctp_clog.x.sb.stcb_sbcc = stcb->asoc.sb_cc;
 else
  sctp_clog.x.sb.stcb_sbcc = 0;
 sctp_clog.x.sb.incr = incr;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_SB,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_closing(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int16_t loc)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.close.inp = (void *)inp;
 sctp_clog.x.close.sctp_flags = inp->sctp_flags;
 if (stcb) {
  sctp_clog.x.close.stcb = (void *)stcb;
  sctp_clog.x.close.state = (uint16_t)stcb->asoc.state;
 } else {
  sctp_clog.x.close.stcb = 0;
  sctp_clog.x.close.state = 0;
 }
 sctp_clog.x.close.loc = loc;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_CLOSE,
      0,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
rto_logging(struct sctp_nets *net, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 memset(&sctp_clog, 0, sizeof(sctp_clog));
 sctp_clog.x.rto.net = (void *) net;
 sctp_clog.x.rto.rtt = net->rtt / 1000;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_RTT,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_strm_del_alt(struct sctp_tcb *stcb, uint32_t tsn, uint16_t sseq, uint16_t stream, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.strlog.stcb = stcb;
 sctp_clog.x.strlog.n_tsn = tsn;
 sctp_clog.x.strlog.n_sseq = sseq;
 sctp_clog.x.strlog.e_tsn = 0;
 sctp_clog.x.strlog.e_sseq = 0;
 sctp_clog.x.strlog.strm = stream;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_STRM,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_nagle_event(struct sctp_tcb *stcb, int action)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.nagle.stcb = (void *)stcb;
 sctp_clog.x.nagle.total_flight = stcb->asoc.total_flight;
 sctp_clog.x.nagle.total_in_queue = stcb->asoc.total_output_queue_size;
 sctp_clog.x.nagle.count_in_queue = stcb->asoc.chunks_on_out_queue;
 sctp_clog.x.nagle.count_in_flight = stcb->asoc.total_flight_count;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_NAGLE,
      action,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_sack(uint32_t old_cumack, uint32_t cumack, uint32_t tsn, uint16_t gaps, uint16_t dups, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.sack.cumack = cumack;
 sctp_clog.x.sack.oldcumack = old_cumack;
 sctp_clog.x.sack.tsn = tsn;
 sctp_clog.x.sack.numGaps = gaps;
 sctp_clog.x.sack.numDups = dups;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_SACK,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_map(uint32_t map, uint32_t cum, uint32_t high, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 memset(&sctp_clog, 0, sizeof(sctp_clog));
 sctp_clog.x.map.base = map;
 sctp_clog.x.map.cum = cum;
 sctp_clog.x.map.high = high;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_MAP,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_fr(uint32_t biggest_tsn, uint32_t biggest_new_tsn, uint32_t tsn, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 memset(&sctp_clog, 0, sizeof(sctp_clog));
 sctp_clog.x.fr.largest_tsn = biggest_tsn;
 sctp_clog.x.fr.largest_new_tsn = biggest_new_tsn;
 sctp_clog.x.fr.tsn = tsn;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_FR,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

#ifdef SCTP_MBUF_LOGGING
void
sctp_log_mb(struct mbuf *m, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.mb.mp = m;
 sctp_clog.x.mb.mbuf_flags = (uint8_t)(SCTP_BUF_GET_FLAGS(m));
 sctp_clog.x.mb.size = (uint16_t)(SCTP_BUF_LEN(m));
 sctp_clog.x.mb.data = SCTP_BUF_AT(m, 0);
 if (SCTP_BUF_IS_EXTENDED(m)) {
  sctp_clog.x.mb.ext = SCTP_BUF_EXTEND_BASE(m);
#if defined(__APPLE__) && !defined(__Userspace__)
  /* APPLE does not use a ref_cnt, but a forward/backward ref queue */
#else
  sctp_clog.x.mb.refcnt = (uint8_t)(SCTP_BUF_EXTEND_REFCNT(m));
#endif
 } else {
  sctp_clog.x.mb.ext = 0;
  sctp_clog.x.mb.refcnt = 0;
 }
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_MBUF,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_mbc(struct mbuf *m, int from)
{
 struct mbuf *mat;

 for (mat = m; mat; mat = SCTP_BUF_NEXT(mat)) {
  sctp_log_mb(mat, from);
 }
}
#endif

void
sctp_log_strm_del(struct sctp_queued_to_read *control, struct sctp_queued_to_read *poschk, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 if (control == NULL) {
  SCTP_PRINTF("Gak log of NULL?\n");
  return;
 }
 sctp_clog.x.strlog.stcb = control->stcb;
 sctp_clog.x.strlog.n_tsn = control->sinfo_tsn;
 sctp_clog.x.strlog.n_sseq = (uint16_t)control->mid;
 sctp_clog.x.strlog.strm = control->sinfo_stream;
 if (poschk != NULL) {
  sctp_clog.x.strlog.e_tsn = poschk->sinfo_tsn;
  sctp_clog.x.strlog.e_sseq = (uint16_t)poschk->mid;
 } else {
  sctp_clog.x.strlog.e_tsn = 0;
  sctp_clog.x.strlog.e_sseq = 0;
 }
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_STRM,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_cwnd(struct sctp_tcb *stcb, struct sctp_nets *net, int augment, uint8_t from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.cwnd.net = net;
 if (stcb->asoc.send_queue_cnt > 255)
  sctp_clog.x.cwnd.cnt_in_send = 255;
 else
  sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
 if (stcb->asoc.stream_queue_cnt > 255)
  sctp_clog.x.cwnd.cnt_in_str = 255;
 else
  sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;

 if (net) {
  sctp_clog.x.cwnd.cwnd_new_value = net->cwnd;
  sctp_clog.x.cwnd.inflight = net->flight_size;
  sctp_clog.x.cwnd.pseudo_cumack = net->pseudo_cumack;
  sctp_clog.x.cwnd.meets_pseudo_cumack = net->new_pseudo_cumack;
  sctp_clog.x.cwnd.need_new_pseudo_cumack = net->find_pseudo_cumack;
 }
 if (SCTP_CWNDLOG_PRESEND == from) {
  sctp_clog.x.cwnd.meets_pseudo_cumack = stcb->asoc.peers_rwnd;
 }
 sctp_clog.x.cwnd.cwnd_augment = augment;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_CWND,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

#if !defined(__APPLE__) && !defined(__Userspace__)
void
sctp_log_lock(struct sctp_inpcb *inp, struct sctp_tcb *stcb, uint8_t from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 memset(&sctp_clog, 0, sizeof(sctp_clog));
 if (inp) {
  sctp_clog.x.lock.sock = (void *) inp->sctp_socket;

 } else {
  sctp_clog.x.lock.sock = (void *) NULL;
 }
 sctp_clog.x.lock.inp = (void *) inp;
#if defined(__FreeBSD__)
 if (stcb) {
  sctp_clog.x.lock.tcb_lock = mtx_owned(&stcb->tcb_mtx);
 } else {
  sctp_clog.x.lock.tcb_lock = SCTP_LOCK_UNKNOWN;
 }
 if (inp) {
  sctp_clog.x.lock.inp_lock = mtx_owned(&inp->inp_mtx);
  sctp_clog.x.lock.create_lock = mtx_owned(&inp->inp_create_mtx);
 } else {
  sctp_clog.x.lock.inp_lock = SCTP_LOCK_UNKNOWN;
  sctp_clog.x.lock.create_lock = SCTP_LOCK_UNKNOWN;
 }
 sctp_clog.x.lock.info_lock = rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx));
 if (inp && (inp->sctp_socket)) {
  sctp_clog.x.lock.sock_lock = mtx_owned(SOCK_MTX(inp->sctp_socket));
  sctp_clog.x.lock.sockrcvbuf_lock = mtx_owned(SOCKBUF_MTX(&inp->sctp_socket->so_rcv));
  sctp_clog.x.lock.socksndbuf_lock = mtx_owned(SOCKBUF_MTX(&inp->sctp_socket->so_snd));
 } else {
  sctp_clog.x.lock.sock_lock = SCTP_LOCK_UNKNOWN;
  sctp_clog.x.lock.sockrcvbuf_lock = SCTP_LOCK_UNKNOWN;
  sctp_clog.x.lock.socksndbuf_lock = SCTP_LOCK_UNKNOWN;
 }
#endif
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_LOCK_EVENT,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}
#endif

void
sctp_log_maxburst(struct sctp_tcb *stcb, struct sctp_nets *net, int error, int burst, uint8_t from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 memset(&sctp_clog, 0, sizeof(sctp_clog));
 sctp_clog.x.cwnd.net = net;
 sctp_clog.x.cwnd.cwnd_new_value = error;
 sctp_clog.x.cwnd.inflight = net->flight_size;
 sctp_clog.x.cwnd.cwnd_augment = burst;
 if (stcb->asoc.send_queue_cnt > 255)
  sctp_clog.x.cwnd.cnt_in_send = 255;
 else
  sctp_clog.x.cwnd.cnt_in_send = stcb->asoc.send_queue_cnt;
 if (stcb->asoc.stream_queue_cnt > 255)
  sctp_clog.x.cwnd.cnt_in_str = 255;
 else
  sctp_clog.x.cwnd.cnt_in_str = stcb->asoc.stream_queue_cnt;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_MAXBURST,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_rwnd(uint8_t from, uint32_t peers_rwnd, uint32_t snd_size, uint32_t overhead)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.rwnd.rwnd = peers_rwnd;
 sctp_clog.x.rwnd.send_size = snd_size;
 sctp_clog.x.rwnd.overhead = overhead;
 sctp_clog.x.rwnd.new_rwnd = 0;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_RWND,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_rwnd_set(uint8_t from, uint32_t peers_rwnd, uint32_t flight_size, uint32_t overhead, uint32_t a_rwndval)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.rwnd.rwnd = peers_rwnd;
 sctp_clog.x.rwnd.send_size = flight_size;
 sctp_clog.x.rwnd.overhead = overhead;
 sctp_clog.x.rwnd.new_rwnd = a_rwndval;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_RWND,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

#ifdef SCTP_MBCNT_LOGGING
static void
sctp_log_mbcnt(uint8_t from, uint32_t total_oq, uint32_t book, uint32_t total_mbcnt_q, uint32_t mbcnt)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.mbcnt.total_queue_size = total_oq;
 sctp_clog.x.mbcnt.size_change = book;
 sctp_clog.x.mbcnt.total_queue_mb_size = total_mbcnt_q;
 sctp_clog.x.mbcnt.mbcnt_change = mbcnt;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_MBCNT,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}
#endif

void
sctp_misc_ints(uint8_t from, uint32_t a, uint32_t b, uint32_t c, uint32_t d)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_MISC_EVENT,
      from,
      a, b, c, d);
#endif
}

void
sctp_wakeup_log(struct sctp_tcb *stcb, uint32_t wake_cnt, int from)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.wake.stcb = (void *)stcb;
 sctp_clog.x.wake.wake_cnt = wake_cnt;
 sctp_clog.x.wake.flight = stcb->asoc.total_flight_count;
 sctp_clog.x.wake.send_q = stcb->asoc.send_queue_cnt;
 sctp_clog.x.wake.sent_q = stcb->asoc.sent_queue_cnt;

 if (stcb->asoc.stream_queue_cnt < 0xff)
  sctp_clog.x.wake.stream_qcnt = (uint8_t) stcb->asoc.stream_queue_cnt;
 else
  sctp_clog.x.wake.stream_qcnt = 0xff;

 if (stcb->asoc.chunks_on_out_queue < 0xff)
  sctp_clog.x.wake.chunks_on_oque = (uint8_t) stcb->asoc.chunks_on_out_queue;
 else
  sctp_clog.x.wake.chunks_on_oque = 0xff;

 sctp_clog.x.wake.sctpflags = 0;
 /* set in the defered mode stuff */
 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE)
  sctp_clog.x.wake.sctpflags |= 1;
 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT)
  sctp_clog.x.wake.sctpflags |= 2;
 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT)
  sctp_clog.x.wake.sctpflags |= 4;
 /* what about the sb */
 if (stcb->sctp_socket) {
  struct socket *so = stcb->sctp_socket;

  sctp_clog.x.wake.sbflags = (uint8_t)((so->so_snd.sb_flags & 0x00ff));
 } else {
  sctp_clog.x.wake.sbflags = 0xff;
 }
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_WAKE,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

void
sctp_log_block(uint8_t from, struct sctp_association *asoc, ssize_t sendlen)
{
#if defined(SCTP_LOCAL_TRACE_BUF)
 struct sctp_cwnd_log sctp_clog;

 sctp_clog.x.blk.onsb = asoc->total_output_queue_size;
 sctp_clog.x.blk.send_sent_qcnt = (uint16_t) (asoc->send_queue_cnt + asoc->sent_queue_cnt);
 sctp_clog.x.blk.peer_rwnd = asoc->peers_rwnd;
 sctp_clog.x.blk.stream_qcnt = (uint16_t) asoc->stream_queue_cnt;
 sctp_clog.x.blk.chunks_on_oque = (uint16_t) asoc->chunks_on_out_queue;
 sctp_clog.x.blk.flight_size = (uint16_t) (asoc->total_flight/1024);
 sctp_clog.x.blk.sndlen = (uint32_t)sendlen;
 SCTP_CTR6(KTR_SCTP, "SCTP:%d[%d]:%x-%x-%x-%x",
      SCTP_LOG_EVENT_BLOCK,
      from,
      sctp_clog.x.misc.log1,
      sctp_clog.x.misc.log2,
      sctp_clog.x.misc.log3,
      sctp_clog.x.misc.log4);
#endif
}

int
sctp_fill_stat_log(void *optval SCTP_UNUSED, size_t *optsize SCTP_UNUSED)
{
 /* May need to fix this if ktrdump does not work */
 return (0);
}

#ifdef SCTP_AUDITING_ENABLED
uint8_t sctp_audit_data[SCTP_AUDIT_SIZE][2];
static int sctp_audit_indx = 0;

static
void
sctp_print_audit_report(void)
{
 int i;
 int cnt;

 cnt = 0;
 for (i = sctp_audit_indx; i < SCTP_AUDIT_SIZE; i++) {
  if ((sctp_audit_data[i][0] == 0xe0) &&
      (sctp_audit_data[i][1] == 0x01)) {
   cnt = 0;
   SCTP_PRINTF("\n");
  } else if (sctp_audit_data[i][0] == 0xf0) {
   cnt = 0;
   SCTP_PRINTF("\n");
  } else if ((sctp_audit_data[i][0] == 0xc0) &&
      (sctp_audit_data[i][1] == 0x01)) {
   SCTP_PRINTF("\n");
   cnt = 0;
  }
  SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0],
       (uint32_t) sctp_audit_data[i][1]);
  cnt++;
  if ((cnt % 14) == 0)
   SCTP_PRINTF("\n");
 }
 for (i = 0; i < sctp_audit_indx; i++) {
  if ((sctp_audit_data[i][0] == 0xe0) &&
      (sctp_audit_data[i][1] == 0x01)) {
   cnt = 0;
   SCTP_PRINTF("\n");
  } else if (sctp_audit_data[i][0] == 0xf0) {
   cnt = 0;
   SCTP_PRINTF("\n");
  } else if ((sctp_audit_data[i][0] == 0xc0) &&
      (sctp_audit_data[i][1] == 0x01)) {
   SCTP_PRINTF("\n");
   cnt = 0;
  }
  SCTP_PRINTF("%2.2x%2.2x ", (uint32_t) sctp_audit_data[i][0],
       (uint32_t) sctp_audit_data[i][1]);
  cnt++;
  if ((cnt % 14) == 0)
   SCTP_PRINTF("\n");
 }
 SCTP_PRINTF("\n");
}

void
sctp_auditing(int from, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
    struct sctp_nets *net)
{
 int resend_cnt, tot_out, rep, tot_book_cnt;
 struct sctp_nets *lnet;
 struct sctp_tmit_chunk *chk;

 sctp_audit_data[sctp_audit_indx][0] = 0xAA;
 sctp_audit_data[sctp_audit_indx][1] = 0x000000ff & from;
 sctp_audit_indx++;
 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
  sctp_audit_indx = 0;
 }
 if (inp == NULL) {
  sctp_audit_data[sctp_audit_indx][0] = 0xAF;
  sctp_audit_data[sctp_audit_indx][1] = 0x01;
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
  return;
 }
 if (stcb == NULL) {
  sctp_audit_data[sctp_audit_indx][0] = 0xAF;
  sctp_audit_data[sctp_audit_indx][1] = 0x02;
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
  return;
 }
 sctp_audit_data[sctp_audit_indx][0] = 0xA1;
 sctp_audit_data[sctp_audit_indx][1] =
     (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
 sctp_audit_indx++;
 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
  sctp_audit_indx = 0;
 }
 rep = 0;
 tot_book_cnt = 0;
 resend_cnt = tot_out = 0;
 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
  if (chk->sent == SCTP_DATAGRAM_RESEND) {
   resend_cnt++;
  } else if (chk->sent < SCTP_DATAGRAM_RESEND) {
   tot_out += chk->book_size;
   tot_book_cnt++;
  }
 }
 if (resend_cnt != stcb->asoc.sent_queue_retran_cnt) {
  sctp_audit_data[sctp_audit_indx][0] = 0xAF;
  sctp_audit_data[sctp_audit_indx][1] = 0xA1;
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
  SCTP_PRINTF("resend_cnt:%d asoc-tot:%d\n",
       resend_cnt, stcb->asoc.sent_queue_retran_cnt);
  rep = 1;
  stcb->asoc.sent_queue_retran_cnt = resend_cnt;
  sctp_audit_data[sctp_audit_indx][0] = 0xA2;
  sctp_audit_data[sctp_audit_indx][1] =
      (0x000000ff & stcb->asoc.sent_queue_retran_cnt);
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
 }
 if (tot_out != stcb->asoc.total_flight) {
  sctp_audit_data[sctp_audit_indx][0] = 0xAF;
  sctp_audit_data[sctp_audit_indx][1] = 0xA2;
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
  rep = 1;
  SCTP_PRINTF("tot_flt:%d asoc_tot:%d\n", tot_out,
       (int)stcb->asoc.total_flight);
  stcb->asoc.total_flight = tot_out;
 }
 if (tot_book_cnt != stcb->asoc.total_flight_count) {
  sctp_audit_data[sctp_audit_indx][0] = 0xAF;
  sctp_audit_data[sctp_audit_indx][1] = 0xA5;
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
  rep = 1;
  SCTP_PRINTF("tot_flt_book:%d\n", tot_book_cnt);

  stcb->asoc.total_flight_count = tot_book_cnt;
 }
 tot_out = 0;
 TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
  tot_out += lnet->flight_size;
 }
 if (tot_out != stcb->asoc.total_flight) {
  sctp_audit_data[sctp_audit_indx][0] = 0xAF;
  sctp_audit_data[sctp_audit_indx][1] = 0xA3;
  sctp_audit_indx++;
  if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
   sctp_audit_indx = 0;
  }
  rep = 1;
  SCTP_PRINTF("real flight:%d net total was %d\n",
       stcb->asoc.total_flight, tot_out);
  /* now corrective action */
  TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) {
   tot_out = 0;
   TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
    if ((chk->whoTo == lnet) &&
        (chk->sent < SCTP_DATAGRAM_RESEND)) {
     tot_out += chk->book_size;
    }
   }
   if (lnet->flight_size != tot_out) {
    SCTP_PRINTF("net:%p flight was %d corrected to %d\n",
         (void *)lnet, lnet->flight_size,
         tot_out);
    lnet->flight_size = tot_out;
   }
  }
 }
 if (rep) {
  sctp_print_audit_report();
 }
}

void
sctp_audit_log(uint8_t ev, uint8_t fd)
{

 sctp_audit_data[sctp_audit_indx][0] = ev;
 sctp_audit_data[sctp_audit_indx][1] = fd;
 sctp_audit_indx++;
 if (sctp_audit_indx >= SCTP_AUDIT_SIZE) {
  sctp_audit_indx = 0;
 }
}

#endif

/*
 * The conversion from time to ticks and vice versa is done by rounding
 * upwards. This way we can test in the code the time to be positive and
 * know that this corresponds to a positive number of ticks.
 */


uint32_t
sctp_msecs_to_ticks(uint32_t msecs)
{
 uint64_t temp;
 uint32_t ticks;

 if (hz == 1000) {
  ticks = msecs;
 } else {
  temp = (((uint64_t)msecs * hz) + 999) / 1000;
  if (temp > UINT32_MAX) {
   ticks = UINT32_MAX;
  } else {
   ticks = (uint32_t)temp;
  }
 }
 return (ticks);
}

uint32_t
sctp_ticks_to_msecs(uint32_t ticks)
{
 uint64_t temp;
 uint32_t msecs;

 if (hz == 1000) {
  msecs = ticks;
 } else {
  temp = (((uint64_t)ticks * 1000) + (hz - 1)) / hz;
  if (temp > UINT32_MAX) {
   msecs = UINT32_MAX;
  } else {
   msecs = (uint32_t)temp;
  }
 }
 return (msecs);
}

uint32_t
sctp_secs_to_ticks(uint32_t secs)
{
 uint64_t temp;
 uint32_t ticks;

 temp = (uint64_t)secs * hz;
 if (temp > UINT32_MAX) {
  ticks = UINT32_MAX;
 } else {
  ticks = (uint32_t)temp;
 }
 return (ticks);
}

uint32_t
sctp_ticks_to_secs(uint32_t ticks)
{
 uint64_t temp;
 uint32_t secs;

 temp = ((uint64_t)ticks + (hz - 1)) / hz;
 if (temp > UINT32_MAX) {
  secs = UINT32_MAX;
 } else {
  secs = (uint32_t)temp;
 }
 return (secs);
}

/*
 * sctp_stop_timers_for_shutdown() should be called
 * when entering the SHUTDOWN_SENT or SHUTDOWN_ACK_SENT
 * state to make sure that all timers are stopped.
 */

void
sctp_stop_timers_for_shutdown(struct sctp_tcb *stcb)
{
 struct sctp_inpcb *inp;
 struct sctp_nets *net;

 inp = stcb->sctp_ep;

 sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_12);
 sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_13);
 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_14);
 sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_15);
 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_16);
  sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_17);
 }
}

void
sctp_stop_association_timers(struct sctp_tcb *stcb, bool stop_assoc_kill_timer)
{
 struct sctp_inpcb *inp;
 struct sctp_nets *net;

 inp = stcb->sctp_ep;
 sctp_timer_stop(SCTP_TIMER_TYPE_RECV, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_18);
 sctp_timer_stop(SCTP_TIMER_TYPE_STRRESET, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_19);
 if (stop_assoc_kill_timer) {
  sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_20);
 }
 sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_21);
 sctp_timer_stop(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_22);
 sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNGUARD, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_23);
 /* Mobility adaptation */
 sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, inp, stcb, NULL,
                 SCTP_FROM_SCTPUTIL + SCTP_LOC_24);
 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
  sctp_timer_stop(SCTP_TIMER_TYPE_SEND, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_25);
  sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_26);
  sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_27);
  sctp_timer_stop(SCTP_TIMER_TYPE_COOKIE, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_28);
  sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_29);
  sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_30);
  sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_31);
 }
}

/*
 * A list of sizes based on typical mtu's, used only if next hop size not
 * returned. These values MUST be multiples of 4 and MUST be ordered.
 */

static uint32_t sctp_mtu_sizes[] = {
 68,
 296,
 508,
 512,
 544,
 576,
 1004,
 1492,
 1500,
 1536,
 2000,
 2048,
 4352,
 4464,
 8168,
 17912,
 32000,
 65532
};

/*
 * Return the largest MTU in sctp_mtu_sizes smaller than val.
 * If val is smaller than the minimum, just return the largest
 * multiple of 4 smaller or equal to val.
 * Ensure that the result is a multiple of 4.
 */

uint32_t
sctp_get_prev_mtu(uint32_t val)
{
 uint32_t i;

 val &= 0xfffffffc;
 if (val <= sctp_mtu_sizes[0]) {
  return (val);
 }
 for (i = 1; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
  if (val <= sctp_mtu_sizes[i]) {
   break;
  }
 }
 KASSERT((sctp_mtu_sizes[i - 1] & 0x00000003) == 0,
         ("sctp_mtu_sizes[%u] not a multiple of 4", i - 1));
 return (sctp_mtu_sizes[i - 1]);
}

/*
 * Return the smallest MTU in sctp_mtu_sizes larger than val.
 * If val is larger than the maximum, just return the largest multiple of 4 smaller
 * or equal to val.
 * Ensure that the result is a multiple of 4.
 */

uint32_t
sctp_get_next_mtu(uint32_t val)
{
 /* select another MTU that is just bigger than this one */
 uint32_t i;

 val &= 0xfffffffc;
 for (i = 0; i < (sizeof(sctp_mtu_sizes) / sizeof(uint32_t)); i++) {
  if (val < sctp_mtu_sizes[i]) {
   KASSERT((sctp_mtu_sizes[i] & 0x00000003) == 0,
    ("sctp_mtu_sizes[%u] not a multiple of 4", i));
   return (sctp_mtu_sizes[i]);
  }
 }
 return (val);
}

void
sctp_fill_random_store(struct sctp_pcb *m)
{
 /*
 * Here we use the MD5/SHA-1 to hash with our good randomNumbers and
 * our counter. The result becomes our good random numbers and we
 * then setup to give these out. Note that we do no locking to
 * protect this. This is ok, since if competing folks call this we
 * will get more gobbled gook in the random store which is what we
 * want. There is a danger that two guys will use the same random
 * numbers, but thats ok too since that is random as well :->
 */

 m->store_at = 0;
#if defined(__Userspace__) && defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 for (int i = 0; i < (int) (sizeof(m->random_store) / sizeof(m->random_store[0])); i++) {
  m->random_store[i] = (uint8_t) rand();
 }
#else
 (void)sctp_hmac(SCTP_HMAC, (uint8_t *)m->random_numbers,
     sizeof(m->random_numbers), (uint8_t *)&m->random_counter,
     sizeof(m->random_counter), (uint8_t *)m->random_store);
#endif
 m->random_counter++;
}

uint32_t
sctp_select_initial_TSN(struct sctp_pcb *inp)
{
 /*
 * A true implementation should use random selection process to get
 * the initial stream sequence number, using RFC1750 as a good
 * guideline
 */

 uint32_t x, *xp;
 uint8_t *p;
 int store_at, new_store;

 if (inp->initial_sequence_debug != 0) {
  uint32_t ret;

  ret = inp->initial_sequence_debug;
  inp->initial_sequence_debug++;
  return (ret);
 }
 retry:
 store_at = inp->store_at;
 new_store = store_at + sizeof(uint32_t);
 if (new_store >= (SCTP_SIGNATURE_SIZE-3)) {
  new_store = 0;
 }
 if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) {
  goto retry;
 }
 if (new_store == 0) {
  /* Refill the random store */
  sctp_fill_random_store(inp);
 }
 p = &inp->random_store[store_at];
 xp = (uint32_t *)p;
 x = *xp;
 return (x);
}

uint32_t
sctp_select_a_tag(struct sctp_inpcb *inp, uint16_t lport, uint16_t rport, int check)
{
 uint32_t x;
 struct timeval now;

 if (check) {
  (void)SCTP_GETTIME_TIMEVAL(&now);
 }
 for (;;) {
  x = sctp_select_initial_TSN(&inp->sctp_ep);
  if (x == 0) {
   /* we never use 0 */
   continue;
  }
  if (!check || sctp_is_vtag_good(x, lport, rport, &now)) {
   break;
  }
 }
 return (x);
}

int32_t
sctp_map_assoc_state(int kernel_state)
{
 int32_t user_state;

 if (kernel_state & SCTP_STATE_WAS_ABORTED) {
  user_state = SCTP_CLOSED;
 } else if (kernel_state & SCTP_STATE_SHUTDOWN_PENDING) {
  user_state = SCTP_SHUTDOWN_PENDING;
 } else {
  switch (kernel_state & SCTP_STATE_MASK) {
  case SCTP_STATE_EMPTY:
   user_state = SCTP_CLOSED;
   break;
  case SCTP_STATE_INUSE:
   user_state = SCTP_CLOSED;
   break;
  case SCTP_STATE_COOKIE_WAIT:
   user_state = SCTP_COOKIE_WAIT;
   break;
  case SCTP_STATE_COOKIE_ECHOED:
   user_state = SCTP_COOKIE_ECHOED;
   break;
  case SCTP_STATE_OPEN:
   user_state = SCTP_ESTABLISHED;
   break;
  case SCTP_STATE_SHUTDOWN_SENT:
   user_state = SCTP_SHUTDOWN_SENT;
   break;
  case SCTP_STATE_SHUTDOWN_RECEIVED:
   user_state = SCTP_SHUTDOWN_RECEIVED;
   break;
  case SCTP_STATE_SHUTDOWN_ACK_SENT:
   user_state = SCTP_SHUTDOWN_ACK_SENT;
   break;
  default:
   user_state = SCTP_CLOSED;
   break;
  }
 }
 return (user_state);
}

int
sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
               uint32_t override_tag, uint32_t initial_tsn, uint32_t vrf_id,
               uint16_t o_strms)
{
 struct sctp_association *asoc;
 /*
 * Anything set to zero is taken care of by the allocation routine's
 * bzero
 */


 /*
 * Up front select what scoping to apply on addresses I tell my peer
 * Not sure what to do with these right now, we will need to come up
 * with a way to set them. We may need to pass them through from the
 * caller in the sctp_aloc_assoc() function.
 */

 int i;
#if defined(SCTP_DETAILED_STR_STATS)
 int j;
#endif

 asoc = &stcb->asoc;
 /* init all variables to a known value. */
 SCTP_SET_STATE(stcb, SCTP_STATE_INUSE);
 asoc->max_burst = inp->sctp_ep.max_burst;
 asoc->fr_max_burst = inp->sctp_ep.fr_max_burst;
 asoc->heart_beat_delay = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
 asoc->cookie_life = inp->sctp_ep.def_cookie_life;
 asoc->sctp_cmt_on_off = inp->sctp_cmt_on_off;
 asoc->ecn_supported = inp->ecn_supported;
 asoc->prsctp_supported = inp->prsctp_supported;
 asoc->auth_supported = inp->auth_supported;
 asoc->asconf_supported = inp->asconf_supported;
 asoc->reconfig_supported = inp->reconfig_supported;
 asoc->nrsack_supported = inp->nrsack_supported;
 asoc->pktdrop_supported = inp->pktdrop_supported;
 asoc->idata_supported = inp->idata_supported;
 asoc->rcv_edmid = inp->rcv_edmid;
 asoc->snd_edmid = SCTP_EDMID_NONE;
 asoc->sctp_cmt_pf = (uint8_t)0;
 asoc->sctp_frag_point = inp->sctp_frag_point;
 asoc->sctp_features = inp->sctp_features;
 asoc->default_dscp = inp->sctp_ep.default_dscp;
 asoc->max_cwnd = inp->max_cwnd;
#ifdef INET6
 if (inp->sctp_ep.default_flowlabel) {
  asoc->default_flowlabel = inp->sctp_ep.default_flowlabel;
 } else {
  if (inp->ip_inp.inp.inp_flags & IN6P_AUTOFLOWLABEL) {
   asoc->default_flowlabel = sctp_select_initial_TSN(&inp->sctp_ep);
   asoc->default_flowlabel &= 0x000fffff;
   asoc->default_flowlabel |= 0x80000000;
  } else {
   asoc->default_flowlabel = 0;
  }
 }
#endif
 asoc->sb_send_resv = 0;
 if (override_tag) {
  asoc->my_vtag = override_tag;
 } else {
  asoc->my_vtag = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport,  1);
 }
 /* Get the nonce tags */
 asoc->my_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
 asoc->peer_vtag_nonce = sctp_select_a_tag(inp, stcb->sctp_ep->sctp_lport, stcb->rport, 0);
 asoc->vrf_id = vrf_id;

#ifdef SCTP_ASOCLOG_OF_TSNS
 asoc->tsn_in_at = 0;
 asoc->tsn_out_at = 0;
 asoc->tsn_in_wrapped = 0;
 asoc->tsn_out_wrapped = 0;
 asoc->cumack_log_at = 0;
 asoc->cumack_log_atsnt = 0;
#endif
#ifdef SCTP_FS_SPEC_LOG
 asoc->fs_index = 0;
#endif
 asoc->refcnt = 0;
 asoc->assoc_up_sent = 0;
 if (override_tag) {
  asoc->init_seq_number = initial_tsn;
 } else {
  asoc->init_seq_number = sctp_select_initial_TSN(&inp->sctp_ep);
 }
 asoc->asconf_seq_out = asoc->init_seq_number;
 asoc->str_reset_seq_out = asoc->init_seq_number;
 asoc->sending_seq = asoc->init_seq_number;
 asoc->asconf_seq_out_acked = asoc->init_seq_number - 1;
 /* we are optimistic here */
 asoc->peer_supports_nat = 0;
 asoc->sent_queue_retran_cnt = 0;

 /* for CMT */
 asoc->last_net_cmt_send_started = NULL;

 asoc->last_acked_seq = asoc->init_seq_number - 1;
 asoc->advanced_peer_ack_point = asoc->init_seq_number - 1;
 asoc->asconf_seq_in = asoc->init_seq_number - 1;

 /* here we are different, we hold the next one we expect */
 asoc->str_reset_seq_in = asoc->init_seq_number;

 asoc->initial_init_rto_max = inp->sctp_ep.initial_init_rto_max;
 asoc->initial_rto = inp->sctp_ep.initial_rto;

 asoc->default_mtu = inp->sctp_ep.default_mtu;
 asoc->max_init_times = inp->sctp_ep.max_init_times;
 asoc->max_send_times = inp->sctp_ep.max_send_times;
 asoc->def_net_failure = inp->sctp_ep.def_net_failure;
 asoc->def_net_pf_threshold = inp->sctp_ep.def_net_pf_threshold;
 asoc->free_chunk_cnt = 0;

 asoc->iam_blocking = 0;
 asoc->context = inp->sctp_context;
 asoc->local_strreset_support = inp->local_strreset_support;
 asoc->def_send = inp->def_send;
 asoc->delayed_ack = sctp_ticks_to_msecs(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
 asoc->sack_freq = inp->sctp_ep.sctp_sack_freq;
 asoc->pr_sctp_cnt = 0;
 asoc->total_output_queue_size = 0;

 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
  asoc->scope.ipv6_addr_legal = 1;
  if (SCTP_IPV6_V6ONLY(inp) == 0) {
   asoc->scope.ipv4_addr_legal = 1;
  } else {
   asoc->scope.ipv4_addr_legal = 0;
  }
#if defined(__Userspace__)
   asoc->scope.conn_addr_legal = 0;
#endif
 } else {
  asoc->scope.ipv6_addr_legal = 0;
#if defined(__Userspace__)
  if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) {
   asoc->scope.conn_addr_legal = 1;
   asoc->scope.ipv4_addr_legal = 0;
  } else {
   asoc->scope.conn_addr_legal = 0;
   asoc->scope.ipv4_addr_legal = 1;
  }
#else
  asoc->scope.ipv4_addr_legal = 1;
#endif
 }

 asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND);
 asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket);

 asoc->smallest_mtu = 0;
 asoc->minrto = inp->sctp_ep.sctp_minrto;
 asoc->maxrto = inp->sctp_ep.sctp_maxrto;

 asoc->stream_locked_on = 0;
 asoc->ecn_echo_cnt_onq = 0;
 asoc->stream_locked = 0;

 asoc->send_sack = 1;

 LIST_INIT(&asoc->sctp_restricted_addrs);

 TAILQ_INIT(&asoc->nets);
 TAILQ_INIT(&asoc->pending_reply_queue);
 TAILQ_INIT(&asoc->asconf_ack_sent);
 /* Setup to fill the hb random cache at first HB */
 asoc->hb_random_idx = 4;

 asoc->sctp_autoclose_ticks = inp->sctp_ep.auto_close_time;

 stcb->asoc.congestion_control_module = inp->sctp_ep.sctp_default_cc_module;
 stcb->asoc.cc_functions = sctp_cc_functions[inp->sctp_ep.sctp_default_cc_module];

 stcb->asoc.stream_scheduling_module = inp->sctp_ep.sctp_default_ss_module;
 stcb->asoc.ss_functions = sctp_ss_functions[inp->sctp_ep.sctp_default_ss_module];

 /*
 * Now the stream parameters, here we allocate space for all streams
 * that we request by default.
 */

 asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams =
     o_strms;
 SCTP_MALLOC(asoc->strmout, struct sctp_stream_out *,
      asoc->streamoutcnt * sizeof(struct sctp_stream_out),
      SCTP_M_STRMO);
 if (asoc->strmout == NULL) {
  /* big trouble no memory */
  SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
  return (ENOMEM);
 }
 SCTP_TCB_LOCK(stcb);
 for (i = 0; i < asoc->streamoutcnt; i++) {
  /*
 * inbound side must be set to 0xffff, also NOTE when we get
 * the INIT-ACK back (for INIT sender) we MUST reduce the
 * count (streamoutcnt) but first check if we sent to any of
 * the upper streams that were dropped (if some were). Those
 * that were dropped must be notified to the upper layer as
 * failed to send.
 */

  TAILQ_INIT(&asoc->strmout[i].outqueue);
  asoc->ss_functions.sctp_ss_init_stream(stcb, &asoc->strmout[i], NULL);
  asoc->strmout[i].chunks_on_queues = 0;
#if defined(SCTP_DETAILED_STR_STATS)
  for (j = 0; j < SCTP_PR_SCTP_MAX + 1; j++) {
   asoc->strmout[i].abandoned_sent[j] = 0;
   asoc->strmout[i].abandoned_unsent[j] = 0;
  }
#else
  asoc->strmout[i].abandoned_sent[0] = 0;
  asoc->strmout[i].abandoned_unsent[0] = 0;
#endif
  asoc->strmout[i].next_mid_ordered = 0;
  asoc->strmout[i].next_mid_unordered = 0;
  asoc->strmout[i].sid = i;
  asoc->strmout[i].last_msg_incomplete = 0;
  asoc->strmout[i].state = SCTP_STREAM_OPENING;
 }
 asoc->ss_functions.sctp_ss_init(stcb, asoc);
 SCTP_TCB_UNLOCK(stcb);

 /* Now the mapping array */
 asoc->mapping_array_size = SCTP_INITIAL_MAPPING_ARRAY;
 SCTP_MALLOC(asoc->mapping_array, uint8_t *, asoc->mapping_array_size,
      SCTP_M_MAP);
 if (asoc->mapping_array == NULL) {
  SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
  SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
  return (ENOMEM);
 }
 memset(asoc->mapping_array, 0, asoc->mapping_array_size);
 SCTP_MALLOC(asoc->nr_mapping_array, uint8_t *, asoc->mapping_array_size,
     SCTP_M_MAP);
 if (asoc->nr_mapping_array == NULL) {
  SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
  SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
  SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTPUTIL, ENOMEM);
  return (ENOMEM);
 }
 memset(asoc->nr_mapping_array, 0, asoc->mapping_array_size);

 /* Now the init of the other outqueues */
 TAILQ_INIT(&asoc->free_chunks);
 TAILQ_INIT(&asoc->control_send_queue);
 TAILQ_INIT(&asoc->asconf_send_queue);
 TAILQ_INIT(&asoc->send_queue);
 TAILQ_INIT(&asoc->sent_queue);
 TAILQ_INIT(&asoc->resetHead);
 asoc->max_inbound_streams = inp->sctp_ep.max_open_streams_intome;
 TAILQ_INIT(&asoc->asconf_queue);
 /* authentication fields */
 asoc->authinfo.random = NULL;
 asoc->authinfo.active_keyid = 0;
 asoc->authinfo.assoc_key = NULL;
 asoc->authinfo.assoc_keyid = 0;
 asoc->authinfo.recv_key = NULL;
 asoc->authinfo.recv_keyid = 0;
 LIST_INIT(&asoc->shared_keys);
 asoc->marked_retrans = 0;
 asoc->port = inp->sctp_ep.port;
 asoc->timoinit = 0;
 asoc->timodata = 0;
 asoc->timosack = 0;
 asoc->timoshutdown = 0;
 asoc->timoheartbeat = 0;
 asoc->timocookie = 0;
 asoc->timoshutdownack = 0;
 (void)SCTP_GETTIME_TIMEVAL(&asoc->start_time);
 asoc->discontinuity_time = asoc->start_time;
 for (i = 0; i < SCTP_PR_SCTP_MAX + 1; i++) {
  asoc->abandoned_unsent[i] = 0;
  asoc->abandoned_sent[i] = 0;
 }
 /* sa_ignore MEMLEAK {memory is put in the assoc mapping array and freed later when
 * the association is freed.
 */

 return (0);
}

void
sctp_print_mapping_array(struct sctp_association *asoc)
{
 unsigned int i, limit;

 SCTP_PRINTF("Mapping array size: %d, baseTSN: %8.8x, cumAck: %8.8x, highestTSN: (%8.8x, %8.8x).\n",
             asoc->mapping_array_size,
             asoc->mapping_array_base_tsn,
             asoc->cumulative_tsn,
             asoc->highest_tsn_inside_map,
             asoc->highest_tsn_inside_nr_map);
 for (limit = asoc->mapping_array_size; limit > 1; limit--) {
  if (asoc->mapping_array[limit - 1] != 0) {
   break;
  }
 }
 SCTP_PRINTF("Renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
 for (i = 0; i < limit; i++) {
  SCTP_PRINTF("%2.2x%c", asoc->mapping_array[i], ((i + 1) % 16) ? ' ' : '\n');
 }
 if (limit % 16)
  SCTP_PRINTF("\n");
 for (limit = asoc->mapping_array_size; limit > 1; limit--) {
  if (asoc->nr_mapping_array[limit - 1]) {
   break;
  }
 }
 SCTP_PRINTF("Non renegable mapping array (last %d entries are zero):\n", asoc->mapping_array_size - limit);
 for (i = 0; i < limit; i++) {
  SCTP_PRINTF("%2.2x%c", asoc->nr_mapping_array[i], ((i + 1) % 16) ? ' ''\n');
 }
 if (limit % 16)
  SCTP_PRINTF("\n");
}

int
sctp_expand_mapping_array(struct sctp_association *asoc, uint32_t needed)
{
 /* mapping array needs to grow */
 uint8_t *new_array1, *new_array2;
 uint32_t new_size;

 new_size = asoc->mapping_array_size + ((needed+7)/8 + SCTP_MAPPING_ARRAY_INCR);
 SCTP_MALLOC(new_array1, uint8_t *, new_size, SCTP_M_MAP);
 SCTP_MALLOC(new_array2, uint8_t *, new_size, SCTP_M_MAP);
 if ((new_array1 == NULL) || (new_array2 == NULL)) {
  /* can't get more, forget it */
  SCTP_PRINTF("No memory for expansion of SCTP mapping array %d\n", new_size);
  if (new_array1) {
   SCTP_FREE(new_array1, SCTP_M_MAP);
  }
  if (new_array2) {
   SCTP_FREE(new_array2, SCTP_M_MAP);
  }
  return (-1);
 }
 memset(new_array1, 0, new_size);
 memset(new_array2, 0, new_size);
 memcpy(new_array1, asoc->mapping_array, asoc->mapping_array_size);
 memcpy(new_array2, asoc->nr_mapping_array, asoc->mapping_array_size);
 SCTP_FREE(asoc->mapping_array, SCTP_M_MAP);
 SCTP_FREE(asoc->nr_mapping_array, SCTP_M_MAP);
 asoc->mapping_array = new_array1;
 asoc->nr_mapping_array = new_array2;
 asoc->mapping_array_size = new_size;
 return (0);
}

static void
sctp_iterator_work(struct sctp_iterator *it)
{
#if defined(__FreeBSD__) && !defined(__Userspace__)
 struct epoch_tracker et;
#endif
 struct sctp_inpcb *tinp;
 int iteration_count = 0;
 int inp_skip = 0;
 int first_in = 1;

#if defined(__FreeBSD__) && !defined(__Userspace__)
 NET_EPOCH_ENTER(et);
#endif
 SCTP_INP_INFO_RLOCK();
 SCTP_ITERATOR_LOCK();
 sctp_it_ctl.cur_it = it;
 if (it->inp) {
  SCTP_INP_RLOCK(it->inp);
  SCTP_INP_DECR_REF(it->inp);
 }
 if (it->inp == NULL) {
  /* iterator is complete */
done_with_iterator:
  sctp_it_ctl.cur_it = NULL;
  SCTP_ITERATOR_UNLOCK();
  SCTP_INP_INFO_RUNLOCK();
  if (it->function_atend != NULL) {
   (*it->function_atend) (it->pointer, it->val);
  }
  SCTP_FREE(it, SCTP_M_ITER);
#if defined(__FreeBSD__) && !defined(__Userspace__)
  NET_EPOCH_EXIT(et);
#endif
  return;
 }
select_a_new_ep:
 if (first_in) {
  first_in = 0;
 } else {
  SCTP_INP_RLOCK(it->inp);
 }
 while (((it->pcb_flags) &&
         ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) ||
        ((it->pcb_features) &&
  ((it->inp->sctp_features & it->pcb_features) != it->pcb_features))) {
  /* endpoint flags or features don't match, so keep looking */
  if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
   SCTP_INP_RUNLOCK(it->inp);
   goto done_with_iterator;
  }
  tinp = it->inp;
  it->inp = LIST_NEXT(it->inp, sctp_list);
  it->stcb = NULL;
  SCTP_INP_RUNLOCK(tinp);
  if (it->inp == NULL) {
   goto done_with_iterator;
  }
  SCTP_INP_RLOCK(it->inp);
 }
 /* now go through each assoc which is in the desired state */
 if (it->done_current_ep == 0) {
  if (it->function_inp != NULL)
   inp_skip = (*it->function_inp)(it->inp, it->pointer, it->val);
  it->done_current_ep = 1;
 }
 if (it->stcb == NULL) {
  /* run the per instance function */
  it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
 }
 if ((inp_skip) || it->stcb == NULL) {
  if (it->function_inp_end != NULL) {
   inp_skip = (*it->function_inp_end)(it->inp,
          it->pointer,
          it->val);
  }
  SCTP_INP_RUNLOCK(it->inp);
  goto no_stcb;
 }
 while (it->stcb != NULL) {
  SCTP_TCB_LOCK(it->stcb);
  if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
   /* not in the right state... keep looking */
   SCTP_TCB_UNLOCK(it->stcb);
   goto next_assoc;
  }
  /* see if we have limited out the iterator loop */
  iteration_count++;
  if (iteration_count > SCTP_ITERATOR_MAX_AT_ONCE) {
   /* Pause to let others grab the lock */
   atomic_add_int(&it->stcb->asoc.refcnt, 1);
   SCTP_TCB_UNLOCK(it->stcb);
   SCTP_INP_INCR_REF(it->inp);
   SCTP_INP_RUNLOCK(it->inp);
   SCTP_ITERATOR_UNLOCK();
   SCTP_INP_INFO_RUNLOCK();
   SCTP_INP_INFO_RLOCK();
   SCTP_ITERATOR_LOCK();
   if (sctp_it_ctl.iterator_flags) {
    /* We won't be staying here */
    SCTP_INP_DECR_REF(it->inp);
    atomic_subtract_int(&it->stcb->asoc.refcnt, 1);
#if !(defined(__FreeBSD__) && !defined(__Userspace__))
    if (sctp_it_ctl.iterator_flags &
       SCTP_ITERATOR_MUST_EXIT) {
     goto done_with_iterator;
    }
#endif
    if (sctp_it_ctl.iterator_flags &
       SCTP_ITERATOR_STOP_CUR_IT) {
     sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_IT;
     goto done_with_iterator;
    }
    if (sctp_it_ctl.iterator_flags &
       SCTP_ITERATOR_STOP_CUR_INP) {
     sctp_it_ctl.iterator_flags &= ~SCTP_ITERATOR_STOP_CUR_INP;
     goto no_stcb;
    }
    /* If we reach here huh? */
    SCTP_PRINTF("Unknown it ctl flag %x\n",
         sctp_it_ctl.iterator_flags);
    sctp_it_ctl.iterator_flags = 0;
   }
   SCTP_INP_RLOCK(it->inp);
   SCTP_INP_DECR_REF(it->inp);
   SCTP_TCB_LOCK(it->stcb);
   atomic_subtract_int(&it->stcb->asoc.refcnt, 1);
   iteration_count = 0;
  }
  KASSERT(it->inp == it->stcb->sctp_ep,
          ("%s: stcb %p does not belong to inp %p, but inp %p",
           __func__, it->stcb, it->inp, it->stcb->sctp_ep));
  SCTP_INP_RLOCK_ASSERT(it->inp);
  SCTP_TCB_LOCK_ASSERT(it->stcb);

  /* run function on this one */
  (*it->function_assoc)(it->inp, it->stcb, it->pointer, it->val);
  SCTP_INP_RLOCK_ASSERT(it->inp);
  SCTP_TCB_LOCK_ASSERT(it->stcb);

  /*
 * we lie here, it really needs to have its own type but
 * first I must verify that this won't effect things :-0
 */

  if (it->no_chunk_output == 0) {
   sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
   SCTP_INP_RLOCK_ASSERT(it->inp);
   SCTP_TCB_LOCK_ASSERT(it->stcb);
  }

  SCTP_TCB_UNLOCK(it->stcb);
 next_assoc:
  it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
  if (it->stcb == NULL) {
   /* Run last function */
   if (it->function_inp_end != NULL) {
    inp_skip = (*it->function_inp_end)(it->inp,
           it->pointer,
           it->val);
   }
  }
 }
 SCTP_INP_RUNLOCK(it->inp);
 no_stcb:
 /* done with all assocs on this endpoint, move on to next endpoint */
 it->done_current_ep = 0;
 if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
  it->inp = NULL;
 } else {
  it->inp = LIST_NEXT(it->inp, sctp_list);
 }
 it->stcb = NULL;
 if (it->inp == NULL) {
  goto done_with_iterator;
 }
 goto select_a_new_ep;
}

void
sctp_iterator_worker(void)
{
 struct sctp_iterator *it;

 /* This function is called with the WQ lock in place */
 sctp_it_ctl.iterator_running = 1;
 while ((it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead)) != NULL) {
  /* now lets work on this one */
  TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
  SCTP_IPI_ITERATOR_WQ_UNLOCK();
#if defined(__FreeBSD__) && !defined(__Userspace__)
  CURVNET_SET(it->vn);
#endif
  sctp_iterator_work(it);
#if defined(__FreeBSD__) && !defined(__Userspace__)
  CURVNET_RESTORE();
#endif
  SCTP_IPI_ITERATOR_WQ_LOCK();
#if !defined(__FreeBSD__) && !defined(__Userspace__)
  if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) {
   break;
  }
#endif
  /*sa_ignore FREED_MEMORY*/
 }
 sctp_it_ctl.iterator_running = 0;
 return;
}

static void
sctp_handle_addr_wq(void)
{
 /* deal with the ADDR wq from the rtsock calls */
 struct sctp_laddr *wi, *nwi;
 struct sctp_asconf_iterator *asc;

 SCTP_MALLOC(asc, struct sctp_asconf_iterator *,
      sizeof(struct sctp_asconf_iterator), SCTP_M_ASC_IT);
 if (asc == NULL) {
  /* Try later, no memory */
  sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ,
     (struct sctp_inpcb *)NULL,
     (struct sctp_tcb *)NULL,
     (struct sctp_nets *)NULL);
  return;
 }
 LIST_INIT(&asc->list_of_work);
 asc->cnt = 0;

 LIST_FOREACH_SAFE(wi, &SCTP_BASE_INFO(addr_wq), sctp_nxt_addr, nwi) {
  LIST_REMOVE(wi, sctp_nxt_addr);
  LIST_INSERT_HEAD(&asc->list_of_work, wi, sctp_nxt_addr);
  asc->cnt++;
 }

 if (asc->cnt == 0) {
  SCTP_FREE(asc, SCTP_M_ASC_IT);
 } else {
  int ret;

  ret = sctp_initiate_iterator(sctp_asconf_iterator_ep,
                               sctp_asconf_iterator_stcb,
                               NULL, /* No ep end for boundall */
                               SCTP_PCB_FLAGS_BOUNDALL,
                               SCTP_PCB_ANY_FEATURES,
                               SCTP_ASOC_ANY_STATE,
                               (void *)asc, 0,
                               sctp_asconf_iterator_end, NULL, 0);
  if (ret) {
   SCTP_PRINTF("Failed to initiate iterator for handle_addr_wq\n");
   /* Freeing if we are stopping or put back on the addr_wq. */
   if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
    sctp_asconf_iterator_end(asc, 0);
   } else {
    LIST_FOREACH(wi, &asc->list_of_work, sctp_nxt_addr) {
     LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr);
    }
    SCTP_FREE(asc, SCTP_M_ASC_IT);
   }
  }
 }
}

/*-
 * The following table shows which pointers for the inp, stcb, or net are
 * stored for each timer after it was started.
 *
 *|Name                         |Timer                        |inp |stcb|net |
 *|-----------------------------|-----------------------------|----|----|----|
 *|SCTP_TIMER_TYPE_SEND         |net->rxt_timer               |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_INIT         |net->rxt_timer               |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_RECV         |stcb->asoc.dack_timer        |Yes |Yes |No  |
 *|SCTP_TIMER_TYPE_SHUTDOWN     |net->rxt_timer               |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_HEARTBEAT    |net->hb_timer                |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_COOKIE       |net->rxt_timer               |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_NEWCOOKIE    |inp->sctp_ep.signature_change|Yes |No  |No  |
 *|SCTP_TIMER_TYPE_PATHMTURAISE |net->pmtu_timer              |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_SHUTDOWNACK  |net->rxt_timer               |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_ASCONF       |stcb->asoc.asconf_timer      |Yes |Yes |Yes |
 *|SCTP_TIMER_TYPE_SHUTDOWNGUARD|stcb->asoc.shut_guard_timer  |Yes |Yes |No  |
 *|SCTP_TIMER_TYPE_AUTOCLOSE    |stcb->asoc.autoclose_timer   |Yes |Yes |No  |
 *|SCTP_TIMER_TYPE_STRRESET     |stcb->asoc.strreset_timer    |Yes |Yes |No  |
 *|SCTP_TIMER_TYPE_INPKILL      |inp->sctp_ep.signature_change|Yes |No  |No  |
 *|SCTP_TIMER_TYPE_ASOCKILL     |stcb->asoc.strreset_timer    |Yes |Yes |No  |
 *|SCTP_TIMER_TYPE_ADDR_WQ      |SCTP_BASE_INFO(addr_wq_timer)|No  |No  |No  |
 *|SCTP_TIMER_TYPE_PRIM_DELETED |stcb->asoc.delete_prim_timer |Yes |Yes |No  |
 */


void
sctp_timeout_handler(void *t)
{
#if defined(__FreeBSD__) && !defined(__Userspace__)
 struct epoch_tracker et;
#endif
 struct timeval tv;
 struct sctp_inpcb *inp;
 struct sctp_tcb *stcb;
 struct sctp_nets *net;
 struct sctp_timer *tmr;
 struct mbuf *op_err;
#if defined(__APPLE__) && !defined(__Userspace__)
 struct socket *so;
#endif
#if defined(__Userspace__)
 struct socket *upcall_socket = NULL;
#endif
 int type;
 int i, secret;
 bool did_output, released_asoc_reference;

 /*
 * If inp, stcb or net are not NULL, then references to these were
 * added when the timer was started, and must be released before this
 * function returns.
 */

 tmr = (struct sctp_timer *)t;
 inp = (struct sctp_inpcb *)tmr->ep;
 stcb = (struct sctp_tcb *)tmr->tcb;
 net = (struct sctp_nets *)tmr->net;
#if defined(__FreeBSD__) && !defined(__Userspace__)
 CURVNET_SET((struct vnet *)tmr->vnet);
 NET_EPOCH_ENTER(et);
#endif
 released_asoc_reference = false;

#ifdef SCTP_AUDITING_ENABLED
 sctp_audit_log(0xF0, (uint8_t) tmr->type);
 sctp_auditing(3, inp, stcb, net);
#endif

 /* sanity checks... */
 KASSERT(tmr->self == NULL || tmr->self == tmr,
         ("sctp_timeout_handler: tmr->self corrupted"));
 KASSERT(SCTP_IS_TIMER_TYPE_VALID(tmr->type),
         ("sctp_timeout_handler: invalid timer type %d", tmr->type));
 type = tmr->type;
 KASSERT(stcb == NULL || stcb->sctp_ep == inp,
         ("sctp_timeout_handler of type %d: inp = %p, stcb->sctp_ep %p",
          type, stcb, stcb->sctp_ep));
 tmr->stopped_from = 0xa001;
 if ((stcb != NULL) && (stcb->asoc.state == SCTP_STATE_EMPTY)) {
  SCTPDBG(SCTP_DEBUG_TIMER2,
          "Timer type %d handler exiting due to CLOSED association.\n",
          type);
  goto out_decr;
 }
 tmr->stopped_from = 0xa002;
 SCTPDBG(SCTP_DEBUG_TIMER2, "Timer type %d goes off.\n", type);
 if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
  SCTPDBG(SCTP_DEBUG_TIMER2,
   "Timer type %d handler exiting due to not being active.\n",
   type);
  goto out_decr;
 }

 tmr->stopped_from = 0xa003;
 if (stcb) {
  SCTP_TCB_LOCK(stcb);
  /*
 * Release reference so that association can be freed if
 * necessary below.
 * This is safe now that we have acquired the lock.
 */

  atomic_subtract_int(&stcb->asoc.refcnt, 1);
  released_asoc_reference = true;
  if ((type != SCTP_TIMER_TYPE_ASOCKILL) &&
      ((stcb->asoc.state == SCTP_STATE_EMPTY) ||
       (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED))) {
   SCTPDBG(SCTP_DEBUG_TIMER2,
           "Timer type %d handler exiting due to CLOSED association.\n",
           type);
   goto out;
  }
 } else if (inp != NULL) {
  SCTP_INP_WLOCK(inp);
 } else {
  SCTP_WQ_ADDR_LOCK();
 }

 /* Record in stopped_from which timeout occurred. */
 tmr->stopped_from = type;
 /* mark as being serviced now */
 if (SCTP_OS_TIMER_PENDING(&tmr->timer)) {
  /*
 * Callout has been rescheduled.
 */

  goto out;
 }
 if (!SCTP_OS_TIMER_ACTIVE(&tmr->timer)) {
  /*
 * Not active, so no action.
 */

  goto out;
 }
 SCTP_OS_TIMER_DEACTIVATE(&tmr->timer);

#if defined(__Userspace__)
 if ((stcb != NULL) &&
     ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) &&
     (stcb->sctp_socket != NULL)) {
  upcall_socket = stcb->sctp_socket;
  SOCK_LOCK(upcall_socket);
  soref(upcall_socket);
  SOCK_UNLOCK(upcall_socket);
 }
#endif
 /* call the handler for the appropriate timer type */
 switch (type) {
 case SCTP_TIMER_TYPE_SEND:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timodata);
  stcb->asoc.timodata++;
  stcb->asoc.num_send_timers_up--;
  if (stcb->asoc.num_send_timers_up < 0) {
   stcb->asoc.num_send_timers_up = 0;
  }
  SCTP_TCB_LOCK_ASSERT(stcb);
  if (sctp_t3rxt_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */

   goto out_decr;
  }
  SCTP_TCB_LOCK_ASSERT(stcb);
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, net);
#endif
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
  did_output = true;
  if ((stcb->asoc.num_send_timers_up == 0) &&
      (stcb->asoc.sent_queue_cnt > 0)) {
   struct sctp_tmit_chunk *chk;

   /*
 * Safeguard. If there on some on the sent queue
 * somewhere but no timers running something is
 * wrong... so we start a timer on the first chunk
 * on the send queue on whatever net it is sent to.
 */

   TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
    if (chk->whoTo != NULL) {
     break;
    }
   }
   if (chk != NULL) {
    sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, chk->whoTo);
   }
  }
  break;
 case SCTP_TIMER_TYPE_INIT:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoinit);
  stcb->asoc.timoinit++;
  if (sctp_t1init_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
  did_output = false;
  break;
 case SCTP_TIMER_TYPE_RECV:
  KASSERT(inp != NULL && stcb != NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timosack);
  stcb->asoc.timosack++;
  sctp_send_sack(stcb, SCTP_SO_NOT_LOCKED);
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, NULL);
#endif
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_SHUTDOWN:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoshutdown);
  stcb->asoc.timoshutdown++;
  if (sctp_shutdown_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, net);
#endif
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_HEARTBEAT:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoheartbeat);
  stcb->asoc.timoheartbeat++;
  if (sctp_heartbeat_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, net);
#endif
  if ((net->dest_state & SCTP_ADDR_NOHB) == 0) {
   sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net);
   sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
   did_output = true;
  } else {
   did_output = false;
  }
  break;
 case SCTP_TIMER_TYPE_COOKIE:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timocookie);
  stcb->asoc.timocookie++;
  if (sctp_cookie_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, net);
#endif
  /*
 * We consider T3 and Cookie timer pretty much the same with
 * respect to where from in chunk_output.
 */

  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_NEWCOOKIE:
  KASSERT(inp != NULL && stcb == NULL && net == NULL,
   ("timeout of type %d: inp = %p, stcb = %p, net = %p",
    type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timosecret);
  (void)SCTP_GETTIME_TIMEVAL(&tv);
  inp->sctp_ep.time_of_secret_change = tv.tv_sec;
  inp->sctp_ep.last_secret_number =
      inp->sctp_ep.current_secret_number;
  inp->sctp_ep.current_secret_number++;
  if (inp->sctp_ep.current_secret_number >=
      SCTP_HOW_MANY_SECRETS) {
   inp->sctp_ep.current_secret_number = 0;
  }
  secret = (int)inp->sctp_ep.current_secret_number;
  for (i = 0; i < SCTP_NUMBER_OF_SECRETS; i++) {
   inp->sctp_ep.secret_key[secret][i] =
       sctp_select_initial_TSN(&inp->sctp_ep);
  }
  sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL);
  did_output = false;
  break;
 case SCTP_TIMER_TYPE_PATHMTURAISE:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timopathmtu);
  sctp_pathmtu_timer(inp, stcb, net);
  did_output = false;
  break;
 case SCTP_TIMER_TYPE_SHUTDOWNACK:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  if (sctp_shutdownack_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
  SCTP_STAT_INCR(sctps_timoshutdownack);
  stcb->asoc.timoshutdownack++;
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, net);
#endif
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_ASCONF:
  KASSERT(inp != NULL && stcb != NULL && net != NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoasconf);
  if (sctp_asconf_timer(inp, stcb, net)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
#ifdef SCTP_AUDITING_ENABLED
  sctp_auditing(4, inp, stcb, net);
#endif
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
  KASSERT(inp != NULL && stcb != NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoshutdownguard);
  op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
                               "Shutdown guard timer expired");
  sctp_abort_an_association(inp, stcb, op_err, true, SCTP_SO_NOT_LOCKED);
  /* no need to unlock on tcb its gone */
  goto out_decr;
 case SCTP_TIMER_TYPE_AUTOCLOSE:
  KASSERT(inp != NULL && stcb != NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoautoclose);
  sctp_autoclose_timer(inp, stcb);
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_STRRESET:
  KASSERT(inp != NULL && stcb != NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timostrmrst);
  if (sctp_strreset_timer(inp, stcb)) {
   /* no need to unlock on tcb its gone */
   goto out_decr;
  }
  sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_INPKILL:
  KASSERT(inp != NULL && stcb == NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoinpkill);
  /*
 * special case, take away our increment since WE are the
 * killer
 */

  sctp_timer_stop(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_3);
#if defined(__APPLE__) && !defined(__Userspace__)
  SCTP_SOCKET_LOCK(SCTP_INP_SO(inp), 1);
#endif
  SCTP_INP_DECR_REF(inp);
  SCTP_INP_WUNLOCK(inp);
  sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT,
                  SCTP_CALLED_FROM_INPKILL_TIMER);
#if defined(__APPLE__) && !defined(__Userspace__)
  SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
#endif
  inp = NULL;
  goto out_decr;
 case SCTP_TIMER_TYPE_ASOCKILL:
  KASSERT(inp != NULL && stcb != NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timoassockill);
  /* Can we free it yet? */
  sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL,
                  SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
#if defined(__APPLE__) && !defined(__Userspace__)
  so = SCTP_INP_SO(inp);
  atomic_add_int(&stcb->asoc.refcnt, 1);
  SCTP_TCB_UNLOCK(stcb);
  SCTP_SOCKET_LOCK(so, 1);
  SCTP_TCB_LOCK(stcb);
  atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
  (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
                        SCTP_FROM_SCTPUTIL + SCTP_LOC_2);
#if defined(__APPLE__) && !defined(__Userspace__)
  SCTP_SOCKET_UNLOCK(so, 1);
#endif
  /*
 * free asoc, always unlocks (or destroy's) so prevent
 * duplicate unlock or unlock of a free mtx :-0
 */

  stcb = NULL;
  goto out_decr;
 case SCTP_TIMER_TYPE_ADDR_WQ:
  KASSERT(inp == NULL && stcb == NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  sctp_handle_addr_wq();
  did_output = true;
  break;
 case SCTP_TIMER_TYPE_PRIM_DELETED:
  KASSERT(inp != NULL && stcb != NULL && net == NULL,
          ("timeout of type %d: inp = %p, stcb = %p, net = %p",
           type, inp, stcb, net));
  SCTP_STAT_INCR(sctps_timodelprim);
  sctp_delete_prim_timer(inp, stcb);
  did_output = false;
  break;
 default:
#ifdef INVARIANTS
  panic("Unknown timer type %d", type);
#else
  goto out;
#endif
 }
#ifdef SCTP_AUDITING_ENABLED
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=86 G=91

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.