code:
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/* $KAME: sctp_header.h,v 1.14 2005/03/06 16:04:17 itojun Exp $	 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_header.h 228037 2011-11-27 19:13:45Z tuexen $");

#ifndef __sctp_header_h__
#define __sctp_header_h__

#include <sys/time.h>
#include <netinet/sctp.h>
#include <netinet/sctp_constants.h>

#define SCTP_PACKED __attribute__((packed))

/*
 * Parameter structures
 */
struct sctp_ipv4addr_param {
	struct sctp_paramhdr ph;/* type=SCTP_IPV4_PARAM_TYPE, len=8 */
	uint32_t addr;		/* IPV4 address */
}                   SCTP_PACKED;

#define SCTP_V6_ADDR_BYTES 16

struct sctp_ipv6addr_param {
	struct sctp_paramhdr ph;/* type=SCTP_IPV6_PARAM_TYPE, len=20 */
	uint8_t addr[SCTP_V6_ADDR_BYTES];	/* IPV6 address */
}                   SCTP_PACKED;

/* Cookie Preservative */
struct sctp_cookie_perserve_param {
	struct sctp_paramhdr ph;/* type=SCTP_COOKIE_PRESERVE, len=8 */
	uint32_t time;		/* time in ms to extend cookie */
}                          SCTP_PACKED;

#define SCTP_ARRAY_MIN_LEN 1
/* Host Name Address */
struct sctp_host_name_param {
	struct sctp_paramhdr ph;/* type=SCTP_HOSTNAME_ADDRESS */
	char name[SCTP_ARRAY_MIN_LEN];	/* host name */
}                    SCTP_PACKED;

/*
 * This is the maximum padded size of a s-a-p
 * so paramheadr + 3 address types (6 bytes) + 2 byte pad = 12
 */
#define SCTP_MAX_ADDR_PARAMS_SIZE 12
/* supported address type */
struct sctp_supported_addr_param {
	struct sctp_paramhdr ph;/* type=SCTP_SUPPORTED_ADDRTYPE */
	uint16_t addr_type[2];	/* array of supported address types */
}                         SCTP_PACKED;

/* ECN parameter */
struct sctp_ecn_supported_param {
	struct sctp_paramhdr ph;/* type=SCTP_ECN_CAPABLE */
}                        SCTP_PACKED;

/* heartbeat info parameter */
struct sctp_heartbeat_info_param {
	struct sctp_paramhdr ph;
	uint32_t time_value_1;
	uint32_t time_value_2;
	uint32_t random_value1;
	uint32_t random_value2;
	uint8_t addr_family;
	uint8_t addr_len;
	/* make sure that this structure is 4 byte aligned */
	uint8_t padding[2];
	char address[SCTP_ADDRMAX];
}                         SCTP_PACKED;

/* draft-ietf-tsvwg-prsctp */
/* PR-SCTP supported parameter */
struct sctp_prsctp_supported_param {
	struct sctp_paramhdr ph;
}                           SCTP_PACKED;

/* draft-ietf-tsvwg-addip-sctp */
struct sctp_asconf_paramhdr {	/* an ASCONF "parameter" */
	struct sctp_paramhdr ph;/* a SCTP parameter header */
	uint32_t correlation_id;/* correlation id for this param */
}                    SCTP_PACKED;

struct sctp_asconf_addr_param {	/* an ASCONF address parameter */
	struct sctp_asconf_paramhdr aph;	/* asconf "parameter" */
	struct sctp_ipv6addr_param addrp;	/* max storage size */
}                      SCTP_PACKED;

struct sctp_asconf_tag_param {	/* an ASCONF NAT-Vtag parameter */
	struct sctp_asconf_paramhdr aph;	/* asconf "parameter" */
	uint32_t local_vtag;
	uint32_t remote_vtag;
}                     SCTP_PACKED;

struct sctp_asconf_addrv4_param {	/* an ASCONF address (v4) parameter */
	struct sctp_asconf_paramhdr aph;	/* asconf "parameter" */
	struct sctp_ipv4addr_param addrp;	/* max storage size */
}                        SCTP_PACKED;

#define SCTP_MAX_SUPPORTED_EXT 256

struct sctp_supported_chunk_types_param {
	struct sctp_paramhdr ph;/* type = 0x8008  len = x */
	uint8_t chunk_types[];
}                                SCTP_PACKED;

/*
 * Structures for DATA chunks
 */
struct sctp_data {
	uint32_t tsn;
	uint16_t stream_id;
	uint16_t stream_sequence;
	uint32_t protocol_id;
	/* user data follows */
}         SCTP_PACKED;

struct sctp_data_chunk {
	struct sctp_chunkhdr ch;
	struct sctp_data dp;
}               SCTP_PACKED;

/*
 * Structures for the control chunks
 */

/* Initiate (INIT)/Initiate Ack (INIT ACK) */
struct sctp_init {
	uint32_t initiate_tag;	/* initiate tag */
	uint32_t a_rwnd;	/* a_rwnd */
	uint16_t num_outbound_streams;	/* OS */
	uint16_t num_inbound_streams;	/* MIS */
	uint32_t initial_tsn;	/* I-TSN */
	/* optional param's follow */
}         SCTP_PACKED;

#define SCTP_IDENTIFICATION_SIZE 16
#define SCTP_ADDRESS_SIZE 4
#define SCTP_RESERVE_SPACE 6
/* state cookie header */
struct sctp_state_cookie {	/* this is our definition... */
	uint8_t identification[SCTP_IDENTIFICATION_SIZE];	/* id of who we are */
	struct timeval time_entered;	/* the time I built cookie */
	uint32_t cookie_life;	/* life I will award this cookie */
	uint32_t tie_tag_my_vtag;	/* my tag in old association */

	uint32_t tie_tag_peer_vtag;	/* peers tag in old association */
	uint32_t peers_vtag;	/* peers tag in INIT (for quick ref) */

	uint32_t my_vtag;	/* my tag in INIT-ACK (for quick ref) */
	uint32_t address[SCTP_ADDRESS_SIZE];	/* 4 ints/128 bits */
	uint32_t addr_type;	/* address type */
	uint32_t laddress[SCTP_ADDRESS_SIZE];	/* my local from address */
	uint32_t laddr_type;	/* my local from address type */
	uint32_t scope_id;	/* v6 scope id for link-locals */

	uint16_t peerport;	/* port address of the peer in the INIT */
	uint16_t myport;	/* my port address used in the INIT */
	uint8_t ipv4_addr_legal;/* Are V4 addr legal? */
	uint8_t ipv6_addr_legal;/* Are V6 addr legal? */
	uint8_t local_scope;	/* IPv6 local scope flag */
	uint8_t site_scope;	/* IPv6 site scope flag */

	uint8_t ipv4_scope;	/* IPv4 private addr scope */
	uint8_t loopback_scope;	/* loopback scope information */
	uint8_t reserved[SCTP_RESERVE_SPACE];	/* Align to 64 bits */
	/*
	 * at the end is tacked on the INIT chunk and the INIT-ACK chunk
	 * (minus the cookie).
	 */
}                 SCTP_PACKED;

/* Used for NAT state error cause */
struct sctp_missing_nat_state {
	uint16_t cause;
	uint16_t length;
	uint8_t data[];
}                      SCTP_PACKED;

struct sctp_inv_mandatory_param {
	uint16_t cause;
	uint16_t length;
	uint32_t num_param;
	uint16_t param;
	/*
	 * We include this to 0 it since only a missing cookie will cause
	 * this error.
	 */
	uint16_t resv;
}                        SCTP_PACKED;

struct sctp_unresolv_addr {
	uint16_t cause;
	uint16_t length;
	uint16_t addr_type;
	uint16_t reserved;	/* Only one invalid addr type */
}                  SCTP_PACKED;

/* state cookie parameter */
struct sctp_state_cookie_param {
	struct sctp_paramhdr ph;
	struct sctp_state_cookie cookie;
}                       SCTP_PACKED;

struct sctp_init_chunk {
	struct sctp_chunkhdr ch;
	struct sctp_init init;
}               SCTP_PACKED;

struct sctp_init_msg {
	struct sctphdr sh;
	struct sctp_init_chunk msg;
}             SCTP_PACKED;

/* ... used for both INIT and INIT ACK */
#define sctp_init_ack		sctp_init
#define sctp_init_ack_chunk	sctp_init_chunk
#define sctp_init_ack_msg	sctp_init_msg

/* Selective Ack (SACK) */
struct sctp_gap_ack_block {
	uint16_t start;		/* Gap Ack block start */
	uint16_t end;		/* Gap Ack block end */
}                  SCTP_PACKED;

struct sctp_sack {
	uint32_t cum_tsn_ack;	/* cumulative TSN Ack */
	uint32_t a_rwnd;	/* updated a_rwnd of sender */
	uint16_t num_gap_ack_blks;	/* number of Gap Ack blocks */
	uint16_t num_dup_tsns;	/* number of duplicate TSNs */
	/* struct sctp_gap_ack_block's follow */
	/* uint32_t duplicate_tsn's follow */
}         SCTP_PACKED;

struct sctp_sack_chunk {
	struct sctp_chunkhdr ch;
	struct sctp_sack sack;
}               SCTP_PACKED;

struct sctp_nr_sack {
	uint32_t cum_tsn_ack;	/* cumulative TSN Ack */
	uint32_t a_rwnd;	/* updated a_rwnd of sender */
	uint16_t num_gap_ack_blks;	/* number of Gap Ack blocks */
	uint16_t num_nr_gap_ack_blks;	/* number of NR Gap Ack blocks */
	uint16_t num_dup_tsns;	/* number of duplicate TSNs */
	uint16_t reserved;	/* not currently used */
	/* struct sctp_gap_ack_block's follow */
	/* uint32_t duplicate_tsn's follow */
}            SCTP_PACKED;

struct sctp_nr_sack_chunk {
	struct sctp_chunkhdr ch;
	struct sctp_nr_sack nr_sack;
}                  SCTP_PACKED;

/* Heartbeat Request (HEARTBEAT) */
struct sctp_heartbeat {
	struct sctp_heartbeat_info_param hb_info;
}              SCTP_PACKED;

struct sctp_heartbeat_chunk {
	struct sctp_chunkhdr ch;
	struct sctp_heartbeat heartbeat;
}                    SCTP_PACKED;

/* ... used for Heartbeat Ack (HEARTBEAT ACK) */
#define sctp_heartbeat_ack		sctp_heartbeat
#define sctp_heartbeat_ack_chunk	sctp_heartbeat_chunk

/* Abort Asssociation (ABORT) */
struct sctp_abort_chunk {
	struct sctp_chunkhdr ch;
	/* optional error cause may follow */
}                SCTP_PACKED;

struct sctp_abort_msg {
	struct sctphdr sh;
	struct sctp_abort_chunk msg;
}              SCTP_PACKED;

/* Shutdown Association (SHUTDOWN) */
struct sctp_shutdown_chunk {
	struct sctp_chunkhdr ch;
	uint32_t cumulative_tsn_ack;
}                   SCTP_PACKED;

/* Shutdown Acknowledgment (SHUTDOWN ACK) */
struct sctp_shutdown_ack_chunk {
	struct sctp_chunkhdr ch;
}                       SCTP_PACKED;

/* Operation Error (ERROR) */
struct sctp_error_chunk {
	struct sctp_chunkhdr ch;
	/* optional error causes follow */
}                SCTP_PACKED;

/* Cookie Echo (COOKIE ECHO) */
struct sctp_cookie_echo_chunk {
	struct sctp_chunkhdr ch;
	struct sctp_state_cookie cookie;
}                      SCTP_PACKED;

/* Cookie Acknowledgment (COOKIE ACK) */
struct sctp_cookie_ack_chunk {
	struct sctp_chunkhdr ch;
}                     SCTP_PACKED;

/* Explicit Congestion Notification Echo (ECNE) */
struct old_sctp_ecne_chunk {
	struct sctp_chunkhdr ch;
	uint32_t tsn;
}                   SCTP_PACKED;

struct sctp_ecne_chunk {
	struct sctp_chunkhdr ch;
	uint32_t tsn;
	uint32_t num_pkts_since_cwr;
}               SCTP_PACKED;

/* Congestion Window Reduced (CWR) */
struct sctp_cwr_chunk {
	struct sctp_chunkhdr ch;
	uint32_t tsn;
}              SCTP_PACKED;

/* Shutdown Complete (SHUTDOWN COMPLETE) */
struct sctp_shutdown_complete_chunk {
	struct sctp_chunkhdr ch;
}                            SCTP_PACKED;

/* Oper error holding a stale cookie */
struct sctp_stale_cookie_msg {
	struct sctp_paramhdr ph;/* really an error cause */
	uint32_t time_usec;
}                     SCTP_PACKED;

struct sctp_adaptation_layer_indication {
	struct sctp_paramhdr ph;
	uint32_t indication;
}                                SCTP_PACKED;

struct sctp_cookie_while_shutting_down {
	struct sctphdr sh;
	struct sctp_chunkhdr ch;
	struct sctp_paramhdr ph;/* really an error cause */
}                               SCTP_PACKED;

struct sctp_shutdown_complete_msg {
	struct sctphdr sh;
	struct sctp_shutdown_complete_chunk shut_cmp;
}                          SCTP_PACKED;

/*
 * draft-ietf-tsvwg-addip-sctp
 */
/* Address/Stream Configuration Change (ASCONF) */
struct sctp_asconf_chunk {
	struct sctp_chunkhdr ch;
	uint32_t serial_number;
	/* lookup address parameter (mandatory) */
	/* asconf parameters follow */
}                 SCTP_PACKED;

/* Address/Stream Configuration Acknowledge (ASCONF ACK) */
struct sctp_asconf_ack_chunk {
	struct sctp_chunkhdr ch;
	uint32_t serial_number;
	/* asconf parameters follow */
}                     SCTP_PACKED;

/* draft-ietf-tsvwg-prsctp */
/* Forward Cumulative TSN (FORWARD TSN) */
struct sctp_forward_tsn_chunk {
	struct sctp_chunkhdr ch;
	uint32_t new_cumulative_tsn;
	/* stream/sequence pairs (sctp_strseq) follow */
}                      SCTP_PACKED;

struct sctp_strseq {
	uint16_t stream;
	uint16_t sequence;
}           SCTP_PACKED;

struct sctp_forward_tsn_msg {
	struct sctphdr sh;
	struct sctp_forward_tsn_chunk msg;
}                    SCTP_PACKED;

/* should be a multiple of 4 - 1 aka 3/7/11 etc. */

#define SCTP_NUM_DB_TO_VERIFY 31

struct sctp_chunk_desc {
	uint8_t chunk_type;
	uint8_t data_bytes[SCTP_NUM_DB_TO_VERIFY];
	uint32_t tsn_ifany;
}               SCTP_PACKED;

struct sctp_pktdrop_chunk {
	struct sctp_chunkhdr ch;
	uint32_t bottle_bw;
	uint32_t current_onq;
	uint16_t trunc_len;
	uint16_t reserved;
	uint8_t data[];
}                  SCTP_PACKED;

/**********STREAM RESET STUFF ******************/

struct sctp_stream_reset_out_request {
	struct sctp_paramhdr ph;
	uint32_t request_seq;	/* monotonically increasing seq no */
	uint32_t response_seq;	/* if a response, the resp seq no */
	uint32_t send_reset_at_tsn;	/* last TSN I assigned outbound */
	uint16_t list_of_streams[];	/* if not all list of streams */
}                             SCTP_PACKED;

struct sctp_stream_reset_in_request {
	struct sctp_paramhdr ph;
	uint32_t request_seq;
	uint16_t list_of_streams[];	/* if not all list of streams */
}                            SCTP_PACKED;

struct sctp_stream_reset_tsn_request {
	struct sctp_paramhdr ph;
	uint32_t request_seq;
}                             SCTP_PACKED;

struct sctp_stream_reset_response {
	struct sctp_paramhdr ph;
	uint32_t response_seq;	/* if a response, the resp seq no */
	uint32_t result;
}                          SCTP_PACKED;

struct sctp_stream_reset_response_tsn {
	struct sctp_paramhdr ph;
	uint32_t response_seq;	/* if a response, the resp seq no */
	uint32_t result;
	uint32_t senders_next_tsn;
	uint32_t receivers_next_tsn;
}                              SCTP_PACKED;

struct sctp_stream_reset_add_strm {
	struct sctp_paramhdr ph;
	uint32_t request_seq;
	uint16_t number_of_streams;
	uint16_t reserved;
}                          SCTP_PACKED;

#define SCTP_STREAM_RESET_NOTHING   0x00000000	/* Nothing for me to do */
#define SCTP_STREAM_RESET_PERFORMED 0x00000001	/* Did it */
#define SCTP_STREAM_RESET_DENIED    0x00000002	/* refused to do it */
#define SCTP_STREAM_RESET_ERROR_STR 0x00000003	/* bad Stream no */
#define SCTP_STREAM_RESET_TRY_LATER 0x00000004	/* collision, try again */
#define SCTP_STREAM_RESET_BAD_SEQNO 0x00000005	/* bad str-reset seq no */

/*
 * convience structures, note that if you are making a request for specific
 * streams then the request will need to be an overlay structure.
 */

struct sctp_stream_reset_out_req {
	struct sctp_chunkhdr ch;
	struct sctp_stream_reset_out_request sr_req;
}                         SCTP_PACKED;

struct sctp_stream_reset_in_req {
	struct sctp_chunkhdr ch;
	struct sctp_stream_reset_in_request sr_req;
}                        SCTP_PACKED;

struct sctp_stream_reset_tsn_req {
	struct sctp_chunkhdr ch;
	struct sctp_stream_reset_tsn_request sr_req;
}                         SCTP_PACKED;

struct sctp_stream_reset_resp {
	struct sctp_chunkhdr ch;
	struct sctp_stream_reset_response sr_resp;
}                      SCTP_PACKED;

/* respone only valid with a TSN request */
struct sctp_stream_reset_resp_tsn {
	struct sctp_chunkhdr ch;
	struct sctp_stream_reset_response_tsn sr_resp;
}                          SCTP_PACKED;

/****************************************************/

/*
 * Authenticated chunks support draft-ietf-tsvwg-sctp-auth
 */

/* Should we make the max be 32? */
#define SCTP_RANDOM_MAX_SIZE 256
struct sctp_auth_random {
	struct sctp_paramhdr ph;/* type = 0x8002 */
	uint8_t random_data[];
}                SCTP_PACKED;

struct sctp_auth_chunk_list {
	struct sctp_paramhdr ph;/* type = 0x8003 */
	uint8_t chunk_types[];
}                    SCTP_PACKED;

struct sctp_auth_hmac_algo {
	struct sctp_paramhdr ph;/* type = 0x8004 */
	uint16_t hmac_ids[];
}                   SCTP_PACKED;

struct sctp_auth_chunk {
	struct sctp_chunkhdr ch;
	uint16_t shared_key_id;
	uint16_t hmac_id;
	uint8_t hmac[];
}               SCTP_PACKED;

struct sctp_auth_invalid_hmac {
	struct sctp_paramhdr ph;
	uint16_t hmac_id;
	uint16_t padding;
}                      SCTP_PACKED;

/*
 * we pre-reserve enough room for a ECNE or CWR AND a SACK with no missing
 * pieces. If ENCE is missing we could have a couple of blocks. This way we
 * optimize so we MOST likely can bundle a SACK/ECN with the smallest size
 * data chunk I will split into. We could increase throughput slightly by
 * taking out these two but the  24-sack/8-CWR i.e. 32 bytes I pre-reserve I
 * feel is worth it for now.
 */
#ifndef SCTP_MAX_OVERHEAD
#ifdef INET6
#define SCTP_MAX_OVERHEAD (sizeof(struct sctp_data_chunk) + \
			   sizeof(struct sctphdr) + \
			   sizeof(struct sctp_ecne_chunk) + \
			   sizeof(struct sctp_sack_chunk) + \
			   sizeof(struct ip6_hdr))

#define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \
			   sizeof(struct sctphdr) + \
			   sizeof(struct ip6_hdr))

#define SCTP_MIN_OVERHEAD (sizeof(struct ip6_hdr) + \
			   sizeof(struct sctphdr))

#else
#define SCTP_MAX_OVERHEAD (sizeof(struct sctp_data_chunk) + \
			   sizeof(struct sctphdr) + \
			   sizeof(struct sctp_ecne_chunk) + \
			   sizeof(struct sctp_sack_chunk) + \
			   sizeof(struct ip))

#define SCTP_MED_OVERHEAD (sizeof(struct sctp_data_chunk) + \
			   sizeof(struct sctphdr) + \
			   sizeof(struct ip))

#define SCTP_MIN_OVERHEAD (sizeof(struct ip) + \
			   sizeof(struct sctphdr))

#endif				/* INET6 */
#endif				/* !SCTP_MAX_OVERHEAD */

#define SCTP_MED_V4_OVERHEAD (sizeof(struct sctp_data_chunk) + \
			      sizeof(struct sctphdr) + \
			      sizeof(struct ip))

#define SCTP_MIN_V4_OVERHEAD (sizeof(struct ip) + \
			      sizeof(struct sctphdr))

#undef SCTP_PACKED
#endif				/* !__sctp_header_h__ */


code:
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/* $KAME: sctp_indata.h,v 1.9 2005/03/06 16:04:17 itojun Exp $	 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_indata.h 222459 2011-05-29 18:41:06Z tuexen $");

#ifndef __sctp_indata_h__
#define __sctp_indata_h__

#if defined(_KERNEL) || defined(__Userspace__)

struct sctp_queued_to_read *
sctp_build_readq_entry(struct sctp_tcb *stcb,
    struct sctp_nets *net,
    uint32_t tsn, uint32_t ppid,
    uint32_t context, uint16_t stream_no,
    uint16_t stream_seq, uint8_t flags,
    struct mbuf *dm);

#define sctp_build_readq_entry_mac(_ctl, in_it, a, net, tsn, ppid, context, stream_no, stream_seq, flags, dm) do { \
	if (_ctl) { \
		atomic_add_int(&((net)->ref_count), 1); \
		(_ctl)->sinfo_stream = stream_no; \
		(_ctl)->sinfo_ssn = stream_seq; \
		(_ctl)->sinfo_flags = (flags << 8); \
		(_ctl)->sinfo_ppid = ppid; \
		(_ctl)->sinfo_context = a; \
		(_ctl)->sinfo_timetolive = 0; \
		(_ctl)->sinfo_tsn = tsn; \
		(_ctl)->sinfo_cumtsn = tsn; \
		(_ctl)->sinfo_assoc_id = sctp_get_associd((in_it)); \
		(_ctl)->length = 0; \
		(_ctl)->held_length = 0; \
		(_ctl)->whoFrom = net; \
		(_ctl)->data = dm; \
		(_ctl)->tail_mbuf = NULL; \
	        (_ctl)->aux_data = NULL; \
		(_ctl)->stcb = (in_it); \
		(_ctl)->port_from = (in_it)->rport; \
		(_ctl)->spec_flags = 0; \
		(_ctl)->do_not_ref_stcb = 0; \
		(_ctl)->end_added = 0; \
		(_ctl)->pdapi_aborted = 0; \
		(_ctl)->some_taken = 0; \
	} \
} while (0)

struct mbuf *
sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
    struct sctp_sndrcvinfo *sinfo);

void sctp_set_rwnd(struct sctp_tcb *, struct sctp_association *);

uint32_t
sctp_calc_rwnd(struct sctp_tcb *stcb, struct sctp_association *asoc);

void
sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
    uint32_t rwnd, int *abort_now, int ecne_seen);

void
sctp_handle_sack(struct mbuf *m, int offset_seg, int offset_dup,
    struct sctp_tcb *stcb, struct sctp_nets *net_from,
    uint16_t num_seg, uint16_t num_nr_seg, uint16_t num_dup,
    int *abort_now, uint8_t flags,
    uint32_t cum_ack, uint32_t rwnd, int ecne_seen);

/* draft-ietf-tsvwg-usctp */
void
sctp_handle_forward_tsn(struct sctp_tcb *,
    struct sctp_forward_tsn_chunk *, int *, struct mbuf *, int);

struct sctp_tmit_chunk *
                sctp_try_advance_peer_ack_point(struct sctp_tcb *, struct sctp_association *);

void sctp_service_queues(struct sctp_tcb *, struct sctp_association *);

void
sctp_update_acked(struct sctp_tcb *, struct sctp_shutdown_chunk *,
    struct sctp_nets *, int *);

int
sctp_process_data(struct mbuf **, int, int *, int, struct sctphdr *,
    struct sctp_inpcb *, struct sctp_tcb *,
    struct sctp_nets *, uint32_t *);

void sctp_slide_mapping_arrays(struct sctp_tcb *stcb);

void sctp_sack_check(struct sctp_tcb *, int, int *);

#endif
#endif

repo_name: veiledmerc/mira

license: mit


code:
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/* $KAME: sctp_input.h,v 1.6 2005/03/06 16:04:17 itojun Exp $	 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_input.h 221627 2011-05-08 09:11:59Z tuexen $");

#ifndef __sctp_input_h__
#define __sctp_input_h__

#if defined(_KERNEL) || defined(__Userspace__)
void
sctp_common_input_processing(struct mbuf **, int, int, int,
    struct sctphdr *, struct sctp_chunkhdr *, struct sctp_inpcb *,
    struct sctp_tcb *, struct sctp_nets *, uint8_t, uint32_t, uint16_t);

struct sctp_stream_reset_out_request *
sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq,
    struct sctp_tmit_chunk **bchk);

void
sctp_reset_in_stream(struct sctp_tcb *stcb, int number_entries,
    uint16_t * list);

int sctp_is_there_unsent_data(struct sctp_tcb *stcb, int so_locked);

#endif
#endif


code:
#ifndef __sctp_lock_bsd_h__
#define __sctp_lock_bsd_h__
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/*
 * General locking concepts: The goal of our locking is to of course provide
 * consistency and yet minimize overhead. We will attempt to use
 * non-recursive locks which are supposed to be quite inexpensive. Now in
 * order to do this the goal is that most functions are not aware of locking.
 * Once we have a TCB we lock it and unlock when we are through. This means
 * that the TCB lock is kind-of a "global" lock when working on an
 * association. Caution must be used when asserting a TCB_LOCK since if we
 * recurse we deadlock.
 *
 * Most other locks (INP and INFO) attempt to localize the locking i.e. we try
 * to contain the lock and unlock within the function that needs to lock it.
 * This sometimes mean we do extra locks and unlocks and lose a bit of
 * efficency, but if the performance statements about non-recursive locks are
 * true this should not be a problem.  One issue that arises with this only
 * lock when needed is that if an implicit association setup is done we have
 * a problem. If at the time I lookup an association I have NULL in the tcb
 * return, by the time I call to create the association some other processor
 * could have created it. This is what the CREATE lock on the endpoint.
 * Places where we will be implicitly creating the association OR just
 * creating an association (the connect call) will assert the CREATE_INP
 * lock. This will assure us that during all the lookup of INP and INFO if
 * another creator is also locking/looking up we can gate the two to
 * synchronize. So the CREATE_INP lock is also another one we must use
 * extreme caution in locking to make sure we don't hit a re-entrancy issue.
 *
 * For non FreeBSD 5.x we provide a bunch of EMPTY lock macros so we can
 * blatantly put locks everywhere and they reduce to nothing on
 * NetBSD/OpenBSD and FreeBSD 4.x
 *
 */

/*
 * When working with the global SCTP lists we lock and unlock the INP_INFO
 * lock. So when we go to lookup an association we will want to do a
 * SCTP_INP_INFO_RLOCK() and then when we want to add a new association to
 * the SCTP_BASE_INFO() list's we will do a SCTP_INP_INFO_WLOCK().
 */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_lock_bsd.h 218319 2011-02-05 12:12:51Z rrs $");

extern struct sctp_foo_stuff sctp_logoff[];
extern int sctp_logoff_stuff;

#define SCTP_IPI_COUNT_INIT()

#define SCTP_STATLOG_INIT_LOCK()
#define SCTP_STATLOG_LOCK()
#define SCTP_STATLOG_UNLOCK()
#define SCTP_STATLOG_DESTROY()

#define SCTP_INP_INFO_LOCK_DESTROY() do { \
        if(rw_wowned(&SCTP_BASE_INFO(ipi_ep_mtx))) { \
             rw_wunlock(&SCTP_BASE_INFO(ipi_ep_mtx)); \
        } \
        rw_destroy(&SCTP_BASE_INFO(ipi_ep_mtx)); \
      }  while (0)

#define SCTP_INP_INFO_LOCK_INIT() \
        rw_init(&SCTP_BASE_INFO(ipi_ep_mtx), "sctp-info");

#define SCTP_INP_INFO_RLOCK()	do { 					\
             rw_rlock(&SCTP_BASE_INFO(ipi_ep_mtx));                         \
} while (0)

#define SCTP_MCORE_QLOCK_INIT(cpstr) do { \
		mtx_init(&(cpstr)->que_mtx,	      \
			 "sctp-mcore_queue","queue_lock",	\
			 MTX_DEF|MTX_DUPOK);		\
} while (0)

#define SCTP_MCORE_QLOCK(cpstr)  do { \
		mtx_lock(&(cpstr)->que_mtx);	\
} while (0)

#define SCTP_MCORE_QUNLOCK(cpstr)  do { \
		mtx_unlock(&(cpstr)->que_mtx);	\
} while (0)

#define SCTP_MCORE_QDESTROY(cpstr)  do { \
	if(mtx_owned(&(cpstr)->core_mtx)) {	\
		mtx_unlock(&(cpstr)->que_mtx);	\
        } \
	mtx_destroy(&(cpstr)->que_mtx);	\
} while (0)

#define SCTP_MCORE_LOCK_INIT(cpstr) do { \
		mtx_init(&(cpstr)->core_mtx,	      \
			 "sctp-cpulck","cpu_proc_lock",	\
			 MTX_DEF|MTX_DUPOK);		\
} while (0)

#define SCTP_MCORE_LOCK(cpstr)  do { \
		mtx_lock(&(cpstr)->core_mtx);	\
} while (0)

#define SCTP_MCORE_UNLOCK(cpstr)  do { \
		mtx_unlock(&(cpstr)->core_mtx);	\
} while (0)

#define SCTP_MCORE_DESTROY(cpstr)  do { \
	if(mtx_owned(&(cpstr)->core_mtx)) {	\
		mtx_unlock(&(cpstr)->core_mtx);	\
        } \
	mtx_destroy(&(cpstr)->core_mtx);	\
} while (0)

#define SCTP_INP_INFO_WLOCK()	do { 					\
            rw_wlock(&SCTP_BASE_INFO(ipi_ep_mtx));                         \
} while (0)

#define SCTP_INP_INFO_RUNLOCK()		rw_runlock(&SCTP_BASE_INFO(ipi_ep_mtx))
#define SCTP_INP_INFO_WUNLOCK()		rw_wunlock(&SCTP_BASE_INFO(ipi_ep_mtx))

#define SCTP_IPI_ADDR_INIT()								\
        rw_init(&SCTP_BASE_INFO(ipi_addr_mtx), "sctp-addr")
#define SCTP_IPI_ADDR_DESTROY() do  { \
        if(rw_wowned(&SCTP_BASE_INFO(ipi_addr_mtx))) { \
             rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \
        } \
	rw_destroy(&SCTP_BASE_INFO(ipi_addr_mtx)); \
      }  while (0)
#define SCTP_IPI_ADDR_RLOCK()	do { 					\
             rw_rlock(&SCTP_BASE_INFO(ipi_addr_mtx));                         \
} while (0)
#define SCTP_IPI_ADDR_WLOCK()	do { 					\
             rw_wlock(&SCTP_BASE_INFO(ipi_addr_mtx));                         \
} while (0)

#define SCTP_IPI_ADDR_RUNLOCK()		rw_runlock(&SCTP_BASE_INFO(ipi_addr_mtx))
#define SCTP_IPI_ADDR_WUNLOCK()		rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx))

#define SCTP_IPI_ITERATOR_WQ_INIT() \
        mtx_init(&sctp_it_ctl.ipi_iterator_wq_mtx, "sctp-it-wq", "sctp_it_wq", MTX_DEF)

#define SCTP_IPI_ITERATOR_WQ_DESTROY() \
	mtx_destroy(&sctp_it_ctl.ipi_iterator_wq_mtx)

#define SCTP_IPI_ITERATOR_WQ_LOCK()	do { 					\
             mtx_lock(&sctp_it_ctl.ipi_iterator_wq_mtx);                \
} while (0)

#define SCTP_IPI_ITERATOR_WQ_UNLOCK()		mtx_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx)

#define SCTP_IP_PKTLOG_INIT() \
        mtx_init(&SCTP_BASE_INFO(ipi_pktlog_mtx), "sctp-pktlog", "packetlog", MTX_DEF)

#define SCTP_IP_PKTLOG_LOCK()	do { 			\
             mtx_lock(&SCTP_BASE_INFO(ipi_pktlog_mtx));     \
} while (0)

#define SCTP_IP_PKTLOG_UNLOCK()	mtx_unlock(&SCTP_BASE_INFO(ipi_pktlog_mtx))

#define SCTP_IP_PKTLOG_DESTROY() \
	mtx_destroy(&SCTP_BASE_INFO(ipi_pktlog_mtx))

/*
 * The INP locks we will use for locking an SCTP endpoint, so for example if
 * we want to change something at the endpoint level for example random_store
 * or cookie secrets we lock the INP level.
 */

#define SCTP_INP_READ_INIT(_inp) \
	mtx_init(&(_inp)->inp_rdata_mtx, "sctp-read", "inpr", MTX_DEF | MTX_DUPOK)

#define SCTP_INP_READ_DESTROY(_inp) \
	mtx_destroy(&(_inp)->inp_rdata_mtx)

#define SCTP_INP_READ_LOCK(_inp)	do { \
        mtx_lock(&(_inp)->inp_rdata_mtx);    \
} while (0)

#define SCTP_INP_READ_UNLOCK(_inp) mtx_unlock(&(_inp)->inp_rdata_mtx)

#define SCTP_INP_LOCK_INIT(_inp) \
	mtx_init(&(_inp)->inp_mtx, "sctp-inp", "inp", MTX_DEF | MTX_DUPOK)
#define SCTP_ASOC_CREATE_LOCK_INIT(_inp) \
	mtx_init(&(_inp)->inp_create_mtx, "sctp-create", "inp_create", \
		 MTX_DEF | MTX_DUPOK)

#define SCTP_INP_LOCK_DESTROY(_inp) \
	mtx_destroy(&(_inp)->inp_mtx)

#define SCTP_INP_LOCK_CONTENDED(_inp) ((_inp)->inp_mtx.mtx_lock & MTX_CONTESTED)

#define SCTP_INP_READ_CONTENDED(_inp) ((_inp)->inp_rdata_mtx.mtx_lock & MTX_CONTESTED)

#define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) ((_inp)->inp_create_mtx.mtx_lock & MTX_CONTESTED)

#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \
	mtx_destroy(&(_inp)->inp_create_mtx)

#ifdef SCTP_LOCK_LOGGING
#define SCTP_INP_RLOCK(_inp)	do { 					\
	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\
        mtx_lock(&(_inp)->inp_mtx);                                     \
} while (0)

#define SCTP_INP_WLOCK(_inp)	do { 					\
	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_INP);\
        mtx_lock(&(_inp)->inp_mtx);                                     \
} while (0)

#else

#define SCTP_INP_RLOCK(_inp)	do { 					\
        mtx_lock(&(_inp)->inp_mtx);                                     \
} while (0)

#define SCTP_INP_WLOCK(_inp)	do { 					\
        mtx_lock(&(_inp)->inp_mtx);                                     \
} while (0)

#endif

#define SCTP_TCB_SEND_LOCK_INIT(_tcb) \
	mtx_init(&(_tcb)->tcb_send_mtx, "sctp-send-tcb", "tcbs", MTX_DEF | MTX_DUPOK)

#define SCTP_TCB_SEND_LOCK_DESTROY(_tcb) mtx_destroy(&(_tcb)->tcb_send_mtx)

#define SCTP_TCB_SEND_LOCK(_tcb)  do { \
	mtx_lock(&(_tcb)->tcb_send_mtx); \
} while (0)

#define SCTP_TCB_SEND_UNLOCK(_tcb) mtx_unlock(&(_tcb)->tcb_send_mtx)

#define SCTP_INP_INCR_REF(_inp) atomic_add_int(&((_inp)->refcount), 1)
#define SCTP_INP_DECR_REF(_inp) atomic_add_int(&((_inp)->refcount), -1)

#ifdef SCTP_LOCK_LOGGING
#define SCTP_ASOC_CREATE_LOCK(_inp) \
	do {								\
	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) sctp_log_lock(_inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_CREATE); \
		mtx_lock(&(_inp)->inp_create_mtx);			\
	} while (0)
#else

#define SCTP_ASOC_CREATE_LOCK(_inp) \
	do {								\
		mtx_lock(&(_inp)->inp_create_mtx);			\
	} while (0)
#endif

#define SCTP_INP_RUNLOCK(_inp)		mtx_unlock(&(_inp)->inp_mtx)
#define SCTP_INP_WUNLOCK(_inp)		mtx_unlock(&(_inp)->inp_mtx)
#define SCTP_ASOC_CREATE_UNLOCK(_inp)	mtx_unlock(&(_inp)->inp_create_mtx)

/*
 * For the majority of things (once we have found the association) we will
 * lock the actual association mutex. This will protect all the assoiciation
 * level queues and streams and such. We will need to lock the socket layer
 * when we stuff data up into the receiving sb_mb. I.e. we will need to do an
 * extra SOCKBUF_LOCK(&so->so_rcv) even though the association is locked.
 */

#define SCTP_TCB_LOCK_INIT(_tcb) \
	mtx_init(&(_tcb)->tcb_mtx, "sctp-tcb", "tcb", MTX_DEF | MTX_DUPOK)

#define SCTP_TCB_LOCK_DESTROY(_tcb)	mtx_destroy(&(_tcb)->tcb_mtx)

#ifdef SCTP_LOCK_LOGGING
#define SCTP_TCB_LOCK(_tcb)  do {					\
	if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE)  sctp_log_lock(_tcb->sctp_ep, _tcb, SCTP_LOG_LOCK_TCB);          \
	mtx_lock(&(_tcb)->tcb_mtx);                                     \
} while (0)

#else
#define SCTP_TCB_LOCK(_tcb)  do {					\
	mtx_lock(&(_tcb)->tcb_mtx);                                     \
} while (0)

#endif

#define SCTP_TCB_TRYLOCK(_tcb) 	mtx_trylock(&(_tcb)->tcb_mtx)

#define SCTP_TCB_UNLOCK(_tcb)		mtx_unlock(&(_tcb)->tcb_mtx)

#define SCTP_TCB_UNLOCK_IFOWNED(_tcb)	      do { \
                                                if (mtx_owned(&(_tcb)->tcb_mtx)) \
                                                     mtx_unlock(&(_tcb)->tcb_mtx); \
                                              } while (0)

#ifdef INVARIANTS
#define SCTP_TCB_LOCK_ASSERT(_tcb) do { \
                            if (mtx_owned(&(_tcb)->tcb_mtx) == 0) \
                                panic("Don't own TCB lock"); \
                            } while (0)
#else
#define SCTP_TCB_LOCK_ASSERT(_tcb)
#endif

#define SCTP_ITERATOR_LOCK_INIT() \
        mtx_init(&sctp_it_ctl.it_mtx, "sctp-it", "iterator", MTX_DEF)

#ifdef INVARIANTS
#define SCTP_ITERATOR_LOCK() \
	do {								\
		if (mtx_owned(&sctp_it_ctl.it_mtx))			\
			panic("Iterator Lock");				\
		mtx_lock(&sctp_it_ctl.it_mtx);				\
	} while (0)
#else
#define SCTP_ITERATOR_LOCK() \
	do {								\
		mtx_lock(&sctp_it_ctl.it_mtx);				\
	} while (0)

#endif

#define SCTP_ITERATOR_UNLOCK()	        mtx_unlock(&sctp_it_ctl.it_mtx)
#define SCTP_ITERATOR_LOCK_DESTROY()	mtx_destroy(&sctp_it_ctl.it_mtx)

#define SCTP_WQ_ADDR_INIT() do { \
        mtx_init(&SCTP_BASE_INFO(wq_addr_mtx), "sctp-addr-wq","sctp_addr_wq",MTX_DEF); \
 } while (0)

#define SCTP_WQ_ADDR_DESTROY() do  { \
        if(mtx_owned(&SCTP_BASE_INFO(wq_addr_mtx))) { \
             mtx_unlock(&SCTP_BASE_INFO(wq_addr_mtx)); \
        } \
	    mtx_destroy(&SCTP_BASE_INFO(wq_addr_mtx)); \
      }  while (0)

#define SCTP_WQ_ADDR_LOCK()	do { \
             mtx_lock(&SCTP_BASE_INFO(wq_addr_mtx));  \
} while (0)
#define SCTP_WQ_ADDR_UNLOCK() do { \
		mtx_unlock(&SCTP_BASE_INFO(wq_addr_mtx)); \
} while (0)

#define SCTP_INCR_EP_COUNT() \
                do { \
		       atomic_add_int(&SCTP_BASE_INFO(ipi_count_ep), 1); \
	        } while (0)

#define SCTP_DECR_EP_COUNT() \
                do { \
		       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_ep), 1); \
	        } while (0)

#define SCTP_INCR_ASOC_COUNT() \
                do { \
	               atomic_add_int(&SCTP_BASE_INFO(ipi_count_asoc), 1); \
	        } while (0)

#define SCTP_DECR_ASOC_COUNT() \
                do { \
	               atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_asoc), 1); \
	        } while (0)

#define SCTP_INCR_LADDR_COUNT() \
                do { \
	               atomic_add_int(&SCTP_BASE_INFO(ipi_count_laddr), 1); \
	        } while (0)

#define SCTP_DECR_LADDR_COUNT() \
                do { \
	               atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_laddr), 1); \
	        } while (0)

#define SCTP_INCR_RADDR_COUNT() \
                do { \
 	               atomic_add_int(&SCTP_BASE_INFO(ipi_count_raddr), 1); \
	        } while (0)

#define SCTP_DECR_RADDR_COUNT() \
                do { \
 	               atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_raddr),1); \
	        } while (0)

#define SCTP_INCR_CHK_COUNT() \
                do { \
  	               atomic_add_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
	        } while (0)
#ifdef INVARIANTS
#define SCTP_DECR_CHK_COUNT() \
                do { \
                       if(SCTP_BASE_INFO(ipi_count_chunk) == 0) \
                             panic("chunk count to 0?");    \
  	               atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
	        } while (0)
#else
#define SCTP_DECR_CHK_COUNT() \
                do { \
                       if(SCTP_BASE_INFO(ipi_count_chunk) != 0) \
  	               atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_chunk), 1); \
	        } while (0)
#endif
#define SCTP_INCR_READQ_COUNT() \
                do { \
		       atomic_add_int(&SCTP_BASE_INFO(ipi_count_readq),1); \
	        } while (0)

#define SCTP_DECR_READQ_COUNT() \
                do { \
		       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_readq), 1); \
	        } while (0)

#define SCTP_INCR_STRMOQ_COUNT() \
                do { \
		       atomic_add_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1); \
	        } while (0)

#define SCTP_DECR_STRMOQ_COUNT() \
                do { \
		       atomic_subtract_int(&SCTP_BASE_INFO(ipi_count_strmoq), 1); \
	        } while (0)

#if defined(SCTP_SO_LOCK_TESTING)
#define SCTP_INP_SO(sctpinp)	(sctpinp)->ip_inp.inp.inp_socket
#define SCTP_SOCKET_LOCK(so, refcnt)
#define SCTP_SOCKET_UNLOCK(so, refcnt)
#endif

#endif


code:
/*-
 * Copyright (c) 2006-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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 <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_os.h 218319 2011-02-05 12:12:51Z rrs $");
#ifndef __sctp_os_h__
#define __sctp_os_h__

/*
 * General kernel memory allocation:
 *  SCTP_MALLOC(element, type, size, name)
 *  SCTP_FREE(element)
 * Kernel memory allocation for "soname"- memory must be zeroed.
 *  SCTP_MALLOC_SONAME(name, type, size)
 *  SCTP_FREE_SONAME(name)
 */

/*
 * Zone(pool) allocation routines: MUST be defined for each OS.
 *  zone = zone/pool pointer.
 *  name = string name of the zone/pool.
 *  size = size of each zone/pool element.
 *  number = number of elements in zone/pool.
 *  type = structure type to allocate
 *
 * sctp_zone_t
 * SCTP_ZONE_INIT(zone, name, size, number)
 * SCTP_ZONE_GET(zone, type)
 * SCTP_ZONE_FREE(zone, element)
 * SCTP_ZONE_DESTROY(zone)
 */

#include <netinet/sctp_os_bsd.h>

/* All os's must implement this address gatherer. If
 * no VRF's exist, then vrf 0 is the only one and all
 * addresses and ifn's live here.
 */
#define SCTP_DEFAULT_VRF 0
void sctp_init_vrf_list(int vrfid);

#endif


code:
/*-
 * Copyright (c) 2006-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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 <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_os_bsd.h 221251 2011-04-30 11:22:30Z tuexen $");
#ifndef __sctp_os_bsd_h__
#define __sctp_os_bsd_h__
/*
 * includes
 */
#include "opt_ipsec.h"
#include "opt_compat.h"
#include "opt_inet6.h"
#include "opt_inet.h"
#include "opt_sctp.h"

#include <sys/param.h>
#include <sys/ktr.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/jail.h>
#include <sys/sysctl.h>
#include <sys/resourcevar.h>
#include <sys/uio.h>
#include <sys/lock.h>
#include <sys/rwlock.h>
#include <sys/kthread.h>
#include <sys/priv.h>
#include <sys/random.h>
#include <sys/limits.h>
#include <sys/queue.h>
#include <machine/cpu.h>

#include <net/if.h>
#include <net/if_types.h>
#include <net/if_var.h>
#include <net/route.h>
#include <net/vnet.h>

#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/in_var.h>
#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>

#ifdef IPSEC
#include <netipsec/ipsec.h>
#include <netipsec/key.h>
#endif				/* IPSEC */

#ifdef INET6
#include <sys/domain.h>
#ifdef IPSEC
#include <netipsec/ipsec6.h>
#endif
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_pcb.h>
#include <netinet/icmp6.h>
#include <netinet6/ip6protosw.h>
#include <netinet6/nd6.h>
#include <netinet6/scope6_var.h>
#endif				/* INET6 */

#include <netinet/ip_options.h>

#ifndef in6pcb
#define in6pcb		inpcb
#endif
/* Declare all the malloc names for all the various mallocs */
MALLOC_DECLARE(SCTP_M_MAP);
MALLOC_DECLARE(SCTP_M_STRMI);
MALLOC_DECLARE(SCTP_M_STRMO);
MALLOC_DECLARE(SCTP_M_ASC_ADDR);
MALLOC_DECLARE(SCTP_M_ASC_IT);
MALLOC_DECLARE(SCTP_M_AUTH_CL);
MALLOC_DECLARE(SCTP_M_AUTH_KY);
MALLOC_DECLARE(SCTP_M_AUTH_HL);
MALLOC_DECLARE(SCTP_M_AUTH_IF);
MALLOC_DECLARE(SCTP_M_STRESET);
MALLOC_DECLARE(SCTP_M_CMSG);
MALLOC_DECLARE(SCTP_M_COPYAL);
MALLOC_DECLARE(SCTP_M_VRF);
MALLOC_DECLARE(SCTP_M_IFA);
MALLOC_DECLARE(SCTP_M_IFN);
MALLOC_DECLARE(SCTP_M_TIMW);
MALLOC_DECLARE(SCTP_M_MVRF);
MALLOC_DECLARE(SCTP_M_ITER);
MALLOC_DECLARE(SCTP_M_SOCKOPT);
MALLOC_DECLARE(SCTP_M_MCORE);

#if defined(SCTP_LOCAL_TRACE_BUF)

#define SCTP_GET_CYCLECOUNT get_cyclecount()
#define SCTP_CTR6 sctp_log_trace

#else
#define SCTP_CTR6 CTR6
#endif

/*
 * Macros to expand out globals defined by various modules
 * to either a real global or a virtualized instance of one,
 * depending on whether VIMAGE is defined.
 */
/* then define the macro(s) that hook into the vimage macros */
#define MODULE_GLOBAL(__SYMBOL) V_##__SYMBOL

#define V_system_base_info VNET(system_base_info)
#define SCTP_BASE_INFO(__m) V_system_base_info.sctppcbinfo.__m
#define SCTP_BASE_STATS V_system_base_info.sctpstat
#define SCTP_BASE_STATS_SYSCTL VNET_NAME(system_base_info.sctpstat)
#define SCTP_BASE_STAT(__m)     V_system_base_info.sctpstat.__m
#define SCTP_BASE_SYSCTL(__m) VNET_NAME(system_base_info.sctpsysctl.__m)
#define SCTP_BASE_VAR(__m) V_system_base_info.__m

/*
 *
 */
#define USER_ADDR_NULL	(NULL)	/* FIX ME: temp */

#if defined(SCTP_DEBUG)
#define SCTPDBG(level, params...)					\
{									\
    do {								\
	if (SCTP_BASE_SYSCTL(sctp_debug_on) & level ) {			\
	    printf(params);						\
	}								\
    } while (0);							\
}
#define SCTPDBG_ADDR(level, addr)					\
{									\
    do {								\
	if (SCTP_BASE_SYSCTL(sctp_debug_on) & level ) {			\
	    sctp_print_address(addr);					\
	}								\
    } while (0);							\
}
#define SCTPDBG_PKT(level, iph, sh)					\
{									\
    do {								\
	    if (SCTP_BASE_SYSCTL(sctp_debug_on) & level) {		\
		    sctp_print_address_pkt(iph, sh);			\
	    }								\
    } while (0);							\
}
#else
#define SCTPDBG(level, params...)
#define SCTPDBG_ADDR(level, addr)
#define SCTPDBG_PKT(level, iph, sh)
#endif
#define SCTP_PRINTF(params...)	printf(params)

#ifdef SCTP_LTRACE_CHUNKS
#define SCTP_LTRACE_CHK(a, b, c, d) if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LTRACE_CHUNK_ENABLE) SCTP_CTR6(KTR_SUBSYS, "SCTP:%d[%d]:%x-%x-%x-%x", SCTP_LOG_CHUNK_PROC, 0, a, b, c, d)
#else
#define SCTP_LTRACE_CHK(a, b, c, d)
#endif

#ifdef SCTP_LTRACE_ERRORS
#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err) if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LTRACE_ERROR_ENABLE) \
                                                         printf("mbuf:%p inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \
								     m, inp, stcb, net, file, __LINE__, err);
#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err) if(SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LTRACE_ERROR_ENABLE) \
                                                          printf("inp:%p stcb:%p net:%p file:%x line:%d error:%d\n", \
								     inp, stcb, net, file, __LINE__, err);
#else
#define SCTP_LTRACE_ERR_RET_PKT(m, inp, stcb, net, file, err)
#define SCTP_LTRACE_ERR_RET(inp, stcb, net, file, err)
#endif

/*
 * Local address and interface list handling
 */
#define SCTP_MAX_VRF_ID		0
#define SCTP_SIZE_OF_VRF_HASH	3
#define SCTP_IFNAMSIZ		IFNAMSIZ
#define SCTP_DEFAULT_VRFID	0
#define SCTP_VRF_ADDR_HASH_SIZE	16
#define SCTP_VRF_IFN_HASH_SIZE	3
#define	SCTP_INIT_VRF_TABLEID(vrf)

#define SCTP_IFN_IS_IFT_LOOP(ifn) ((ifn)->ifn_type == IFT_LOOP)
#define SCTP_ROUTE_IS_REAL_LOOP(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifa && (ro)->ro_rt->rt_ifa->ifa_ifp && (ro)->ro_rt->rt_ifa->ifa_ifp->if_type == IFT_LOOP)

/*
 * Access to IFN's to help with src-addr-selection
 */
/* This could return VOID if the index works but for BSD we provide both. */
#define SCTP_GET_IFN_VOID_FROM_ROUTE(ro) (void *)ro->ro_rt->rt_ifp
#define SCTP_GET_IF_INDEX_FROM_ROUTE(ro) (ro)->ro_rt->rt_ifp->if_index
#define SCTP_ROUTE_HAS_VALID_IFN(ro) ((ro)->ro_rt && (ro)->ro_rt->rt_ifp)

/*
 * general memory allocation
 */
#define SCTP_MALLOC(var, type, size, name) \
    do { \
	var = (type)malloc(size, name, M_NOWAIT); \
    } while (0)

#define SCTP_FREE(var, type)	free(var, type)

#define SCTP_MALLOC_SONAME(var, type, size) \
    do { \
	var = (type)malloc(size, M_SONAME, M_WAITOK | M_ZERO); \
    } while (0)

#define SCTP_FREE_SONAME(var)	free(var, M_SONAME)

#define SCTP_PROCESS_STRUCT struct proc *

/*
 * zone allocation functions
 */
#include <vm/uma.h>

/* SCTP_ZONE_INIT: initialize the zone */
typedef struct uma_zone *sctp_zone_t;

#define SCTP_ZONE_INIT(zone, name, size, number) { \
	zone = uma_zcreate(name, size, NULL, NULL, NULL, NULL, UMA_ALIGN_PTR,\
		0); \
	uma_zone_set_max(zone, number); \
}

#define SCTP_ZONE_DESTROY(zone) uma_zdestroy(zone)

/* SCTP_ZONE_GET: allocate element from the zone */
#define SCTP_ZONE_GET(zone, type) \
	(type *)uma_zalloc(zone, M_NOWAIT);

/* SCTP_ZONE_FREE: free element from the zone */
#define SCTP_ZONE_FREE(zone, element) \
	uma_zfree(zone, element);

#define SCTP_HASH_INIT(size, hashmark) hashinit_flags(size, M_PCB, hashmark, HASH_NOWAIT)
#define SCTP_HASH_FREE(table, hashmark) hashdestroy(table, M_PCB, hashmark)

#define SCTP_M_COPYM	m_copym

/*
 * timers
 */
#include <sys/callout.h>
typedef struct callout sctp_os_timer_t;

#define SCTP_OS_TIMER_INIT(tmr)	callout_init(tmr, 1)
#define SCTP_OS_TIMER_START	callout_reset
#define SCTP_OS_TIMER_STOP	callout_stop
#define SCTP_OS_TIMER_STOP_DRAIN callout_drain
#define SCTP_OS_TIMER_PENDING	callout_pending
#define SCTP_OS_TIMER_ACTIVE	callout_active
#define SCTP_OS_TIMER_DEACTIVATE callout_deactivate

#define sctp_get_tick_count() (ticks)

#define SCTP_UNUSED __attribute__((unused))

/*
 * Functions
 */
/* Mbuf manipulation and access macros  */
#define SCTP_BUF_LEN(m) (m->m_len)
#define SCTP_BUF_NEXT(m) (m->m_next)
#define SCTP_BUF_NEXT_PKT(m) (m->m_nextpkt)
#define SCTP_BUF_RESV_UF(m, size) m->m_data += size
#define SCTP_BUF_AT(m, size) m->m_data + size
#define SCTP_BUF_IS_EXTENDED(m) (m->m_flags & M_EXT)
#define SCTP_BUF_EXTEND_SIZE(m) (m->m_ext.ext_size)
#define SCTP_BUF_TYPE(m) (m->m_type)
#define SCTP_BUF_RECVIF(m) (m->m_pkthdr.rcvif)
#define SCTP_BUF_PREPEND	M_PREPEND

#define SCTP_ALIGN_TO_END(m, len) if(m->m_flags & M_PKTHDR) { \
                                     MH_ALIGN(m, len); \
                                  } else if ((m->m_flags & M_EXT) == 0) { \
                                     M_ALIGN(m, len); \
                                  }

/* We make it so if you have up to 4 threads
 * writing based on the default size of
 * the packet log 65 k, that would be
 * 4 16k packets before we would hit
 * a problem.
 */
#define SCTP_PKTLOG_WRITERS_NEED_LOCK 3

/*************************/
/*      MTU              */
/*************************/
#define SCTP_GATHER_MTU_FROM_IFN_INFO(ifn, ifn_index, af) ((struct ifnet *)ifn)->if_mtu
#define SCTP_GATHER_MTU_FROM_ROUTE(sctp_ifa, sa, rt) ((rt != NULL) ? rt->rt_rmx.rmx_mtu : 0)
#define SCTP_GATHER_MTU_FROM_INTFC(sctp_ifn) ((sctp_ifn->ifn_p != NULL) ? ((struct ifnet *)(sctp_ifn->ifn_p))->if_mtu : 0)
#define SCTP_SET_MTU_OF_ROUTE(sa, rt, mtu) do { \
                                              if (rt != NULL) \
                                                 rt->rt_rmx.rmx_mtu = mtu; \
                                           } while(0)

/* (de-)register interface event notifications */
#define SCTP_REGISTER_INTERFACE(ifhandle, af)
#define SCTP_DEREGISTER_INTERFACE(ifhandle, af)

/*************************/
/* These are for logging */
/*************************/
/* return the base ext data pointer */
#define SCTP_BUF_EXTEND_BASE(m) (m->m_ext.ext_buf)
 /* return the refcnt of the data pointer */
#define SCTP_BUF_EXTEND_REFCNT(m) (*m->m_ext.ref_cnt)
/* return any buffer related flags, this is
 * used beyond logging for apple only.
 */
#define SCTP_BUF_GET_FLAGS(m) (m->m_flags)

/* For BSD this just accesses the M_PKTHDR length
 * so it operates on an mbuf with hdr flag. Other
 * O/S's may have separate packet header and mbuf
 * chain pointers.. thus the macro.
 */
#define SCTP_HEADER_TO_CHAIN(m) (m)
#define SCTP_DETACH_HEADER_FROM_CHAIN(m)
#define SCTP_HEADER_LEN(m) (m->m_pkthdr.len)
#define SCTP_GET_HEADER_FOR_OUTPUT(o_pak) 0
#define SCTP_RELEASE_HEADER(m)
#define SCTP_RELEASE_PKT(m)	sctp_m_freem(m)
#define SCTP_ENABLE_UDP_CSUM(m) do { \
					m->m_pkthdr.csum_flags = CSUM_UDP; \
					m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); \
				} while (0)

#define SCTP_GET_PKT_VRFID(m, vrf_id)  ((vrf_id = SCTP_DEFAULT_VRFID) != SCTP_DEFAULT_VRFID)

/* Attach the chain of data into the sendable packet. */
#define SCTP_ATTACH_CHAIN(pak, m, packet_length) do { \
                                                 pak = m; \
                                                 pak->m_pkthdr.len = packet_length; \
                         } while(0)

/* Other m_pkthdr type things */
#define SCTP_IS_IT_BROADCAST(dst, m) ((m->m_flags & M_PKTHDR) ? in_broadcast(dst, m->m_pkthdr.rcvif) : 0)
#define SCTP_IS_IT_LOOPBACK(m) ((m->m_flags & M_PKTHDR) && ((m->m_pkthdr.rcvif == NULL) || (m->m_pkthdr.rcvif->if_type == IFT_LOOP)))

/* This converts any input packet header
 * into the chain of data holders, for BSD
 * its a NOP.
 */

/* Macro's for getting length from V6/V4 header */
#define SCTP_GET_IPV4_LENGTH(iph) (iph->ip_len)
#define SCTP_GET_IPV6_LENGTH(ip6) (ntohs(ip6->ip6_plen))

/* get the v6 hop limit */
#define SCTP_GET_HLIM(inp, ro)	in6_selecthlim((struct in6pcb *)&inp->ip_inp.inp, (ro ? (ro->ro_rt ? (ro->ro_rt->rt_ifp) : (NULL)) : (NULL)));

/* is the endpoint v6only? */
#define SCTP_IPV6_V6ONLY(inp)	(((struct inpcb *)inp)->inp_flags & IN6P_IPV6_V6ONLY)
/* is the socket non-blocking? */
#define SCTP_SO_IS_NBIO(so)	((so)->so_state & SS_NBIO)
#define SCTP_SET_SO_NBIO(so)	((so)->so_state |= SS_NBIO)
#define SCTP_CLEAR_SO_NBIO(so)	((so)->so_state &= ~SS_NBIO)
/* get the socket type */
#define SCTP_SO_TYPE(so)	((so)->so_type)
/* reserve sb space for a socket */
#define SCTP_SORESERVE(so, send, recv)	soreserve(so, send, recv)
/* wakeup a socket */
#define SCTP_SOWAKEUP(so)	wakeup(&(so)->so_timeo)
/* clear the socket buffer state */
#define SCTP_SB_CLEAR(sb)	\
	(sb).sb_cc = 0;		\
	(sb).sb_mb = NULL;	\
	(sb).sb_mbcnt = 0;

#define SCTP_SB_LIMIT_RCV(so) so->so_rcv.sb_hiwat
#define SCTP_SB_LIMIT_SND(so) so->so_snd.sb_hiwat

/*
 * routes, output, etc.
 */
typedef struct route sctp_route_t;
typedef struct rtentry sctp_rtentry_t;

#define SCTP_RTALLOC(ro, vrf_id) rtalloc_ign((struct route *)ro, 0UL)

/* Future zero copy wakeup/send  function */
#define SCTP_ZERO_COPY_EVENT(inp, so)
/* This is re-pulse ourselves for sendbuf */
#define SCTP_ZERO_COPY_SENDQ_EVENT(inp, so)

/*
 * IP output routines
 */
#define SCTP_IP_OUTPUT(result, o_pak, ro, stcb, vrf_id) \
{ \
	int o_flgs = IP_RAWOUTPUT; \
	struct sctp_tcb *local_stcb = stcb; \
	if (local_stcb && \
	    local_stcb->sctp_ep && \
	    local_stcb->sctp_ep->sctp_socket) \
		o_flgs |= local_stcb->sctp_ep->sctp_socket->so_options & SO_DONTROUTE; \
	result = ip_output(o_pak, NULL, ro, o_flgs, 0, NULL); \
}

#define SCTP_IP6_OUTPUT(result, o_pak, ro, ifp, stcb, vrf_id) \
{ \
	struct sctp_tcb *local_stcb = stcb; \
	if (local_stcb && local_stcb->sctp_ep) \
		result = ip6_output(o_pak, \
				    ((struct in6pcb *)(local_stcb->sctp_ep))->in6p_outputopts, \
				    (ro), 0, 0, ifp, NULL); \
	else \
		result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \
}

struct mbuf *
sctp_get_mbuf_for_msg(unsigned int space_needed,
    int want_header, int how, int allonebuf, int type);

/*
 * SCTP AUTH
 */
#define HAVE_SHA2

#define SCTP_READ_RANDOM(buf, len)	read_random(buf, len)

#ifdef USE_SCTP_SHA1
#include <netinet/sctp_sha1.h>
#else
#include <crypto/sha1.h>
/* map standard crypto API names */
#define SHA1_Init	SHA1Init
#define SHA1_Update	SHA1Update
#define SHA1_Final(x,y)	SHA1Final((caddr_t)x, y)
#endif

#if defined(HAVE_SHA2)
#include <crypto/sha2/sha2.h>
#endif

#endif

#define SCTP_DECREMENT_AND_CHECK_REFCOUNT(addr) (atomic_fetchadd_int(addr, -1) == 1)
#if defined(INVARIANTS)
#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
{ \
	int32_t oldval; \
	oldval = atomic_fetchadd_int(addr, -val); \
	if (oldval < val) { \
		panic("Counter goes negative"); \
	} \
}
#else
#define SCTP_SAVE_ATOMIC_DECREMENT(addr, val) \
{ \
	int32_t oldval; \
	oldval = atomic_fetchadd_int(addr, -val); \
	if (oldval < val) { \
		*addr = 0; \
	} \
}
#endif


code:
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/* $KAME: sctp_output.h,v 1.14 2005/03/06 16:04:18 itojun Exp $	 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_output.h 224641 2011-08-03 20:21:00Z tuexen $");

#ifndef __sctp_output_h__
#define __sctp_output_h__

#include <netinet/sctp_header.h>

#if defined(_KERNEL) || defined(__Userspace__)

struct mbuf *
sctp_add_addresses_to_i_ia(struct sctp_inpcb *inp,
    struct sctp_tcb *stcb,
    struct sctp_scoping *scope,
    struct mbuf *m_at,
    int cnt_inits_to);

int sctp_is_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);

int
sctp_is_address_in_scope(struct sctp_ifa *ifa,
    int ipv4_addr_legal,
    int ipv6_addr_legal,
    int loopback_scope,
    int ipv4_local_scope,
    int local_scope,
    int site_scope,
    int do_update);
int
    sctp_is_addr_in_ep(struct sctp_inpcb *inp, struct sctp_ifa *ifa);

struct sctp_ifa *
sctp_source_address_selection(struct sctp_inpcb *inp,
    struct sctp_tcb *stcb,
    sctp_route_t * ro, struct sctp_nets *net,
    int non_asoc_addr_ok, uint32_t vrf_id);

int
    sctp_v6src_match_nexthop(struct sockaddr_in6 *src6, sctp_route_t * ro);
int
    sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t * ro);

void
sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
    SCTP_UNUSED
#endif
);

void
sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
    struct mbuf *, int, int, struct sctphdr *, struct sctp_init_chunk *,
    uint32_t, uint16_t, int);

struct mbuf *
sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
    struct sctp_chunkhdr *, int *);
void sctp_queue_op_err(struct sctp_tcb *, struct mbuf *);

int
sctp_send_cookie_echo(struct mbuf *, int, struct sctp_tcb *,
    struct sctp_nets *);

void sctp_send_cookie_ack(struct sctp_tcb *);

void
sctp_send_heartbeat_ack(struct sctp_tcb *, struct mbuf *, int, int,
    struct sctp_nets *);

void
sctp_remove_from_wheel(struct sctp_tcb *stcb,
    struct sctp_association *asoc,
    struct sctp_stream_out *strq, int holds_lock);

void sctp_send_shutdown(struct sctp_tcb *, struct sctp_nets *);

void sctp_send_shutdown_ack(struct sctp_tcb *, struct sctp_nets *);

void sctp_send_shutdown_complete(struct sctp_tcb *, struct sctp_nets *, int);

void
sctp_send_shutdown_complete2(struct mbuf *, int, struct sctphdr *,
    uint32_t, uint16_t);

void sctp_send_asconf(struct sctp_tcb *, struct sctp_nets *, int addr_locked);

void sctp_send_asconf_ack(struct sctp_tcb *);

int sctp_get_frag_point(struct sctp_tcb *, struct sctp_association *);

void sctp_toss_old_cookies(struct sctp_tcb *, struct sctp_association *);

void sctp_toss_old_asconf(struct sctp_tcb *);

void sctp_fix_ecn_echo(struct sctp_association *);

void sctp_move_chunks_from_net(struct sctp_tcb *stcb, struct sctp_nets *net);

int
sctp_output(struct sctp_inpcb *, struct mbuf *, struct sockaddr *,
    struct mbuf *, struct thread *, int);

void
sctp_chunk_output(struct sctp_inpcb *, struct sctp_tcb *, int, int
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
    SCTP_UNUSED
#endif
);
void
sctp_send_abort_tcb(struct sctp_tcb *, struct mbuf *, int
#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
    SCTP_UNUSED
#endif
);

void send_forward_tsn(struct sctp_tcb *, struct sctp_association *);

void sctp_send_sack(struct sctp_tcb *, int);

void sctp_send_hb(struct sctp_tcb *, struct sctp_nets *, int);

void sctp_send_ecn_echo(struct sctp_tcb *, struct sctp_nets *, uint32_t);

void
sctp_send_packet_dropped(struct sctp_tcb *, struct sctp_nets *, struct mbuf *,
    int, int);

void sctp_send_cwr(struct sctp_tcb *, struct sctp_nets *, uint32_t, uint8_t);

void
sctp_add_stream_reset_out(struct sctp_tmit_chunk *chk,
    int number_entries, uint16_t * list,
    uint32_t seq, uint32_t resp_seq, uint32_t last_sent);

void
sctp_add_stream_reset_in(struct sctp_tmit_chunk *chk,
    int number_entries, uint16_t * list,
    uint32_t seq);

void
sctp_add_stream_reset_tsn(struct sctp_tmit_chunk *chk,
    uint32_t seq);

void
sctp_add_stream_reset_result(struct sctp_tmit_chunk *chk,
    uint32_t resp_seq, uint32_t result);

void
sctp_add_stream_reset_result_tsn(struct sctp_tmit_chunk *chk,
    uint32_t resp_seq, uint32_t result,
    uint32_t send_una, uint32_t recv_next);

int
sctp_send_str_reset_req(struct sctp_tcb *stcb,
    int number_entries,
    uint16_t * list,
    uint8_t send_out_req,
    uint32_t resp_seq,
    uint8_t send_in_req,
    uint8_t send_tsn_req,
    uint8_t add_str,
    uint16_t adding);

void
sctp_send_abort(struct mbuf *, int, struct sctphdr *, uint32_t,
    struct mbuf *, uint32_t, uint16_t);

void sctp_send_operr_to(struct mbuf *, int, struct mbuf *, uint32_t, uint32_t, uint16_t);

#endif				/* _KERNEL || __Userspace__ */

#if defined(_KERNEL) || defined (__Userspace__)
int
sctp_sosend(struct socket *so,
    struct sockaddr *addr,
    struct uio *uio,
    struct mbuf *top,
    struct mbuf *control,
    int flags,
    struct thread *p
);

#endif
#endif


code:
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/* $KAME: sctp_pcb.h,v 1.21 2005/07/16 01:18:47 suz Exp $	 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_pcb.h 225549 2011-09-14 08:15:21Z tuexen $");

#ifndef __sctp_pcb_h__
#define __sctp_pcb_h__

#include <netinet/sctp_os.h>
#include <netinet/sctp.h>
#include <netinet/sctp_constants.h>
#include <netinet/sctp_sysctl.h>

LIST_HEAD(sctppcbhead, sctp_inpcb);
LIST_HEAD(sctpasochead, sctp_tcb);
LIST_HEAD(sctpladdr, sctp_laddr);
LIST_HEAD(sctpvtaghead, sctp_tagblock);
LIST_HEAD(sctp_vrflist, sctp_vrf);
LIST_HEAD(sctp_ifnlist, sctp_ifn);
LIST_HEAD(sctp_ifalist, sctp_ifa);
TAILQ_HEAD(sctp_readhead, sctp_queued_to_read);
TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending);

#include <netinet/sctp_structs.h>
#include <netinet/sctp_auth.h>

#define SCTP_PCBHASH_ALLADDR(port, mask) (port & mask)
#define SCTP_PCBHASH_ASOC(tag, mask) (tag & mask)

struct sctp_vrf {
	LIST_ENTRY(sctp_vrf) next_vrf;
	struct sctp_ifalist *vrf_addr_hash;
	struct sctp_ifnlist ifnlist;
	uint32_t vrf_id;
	uint32_t tbl_id_v4;	/* default v4 table id */
	uint32_t tbl_id_v6;	/* default v6 table id */
	uint32_t total_ifa_count;
	u_long vrf_addr_hashmark;
	uint32_t refcount;
};

struct sctp_ifn {
	struct sctp_ifalist ifalist;
	struct sctp_vrf *vrf;
	         LIST_ENTRY(sctp_ifn) next_ifn;
	         LIST_ENTRY(sctp_ifn) next_bucket;
	void *ifn_p;		/* never access without appropriate lock */
	uint32_t ifn_mtu;
	uint32_t ifn_type;
	uint32_t ifn_index;	/* shorthand way to look at ifn for reference */
	uint32_t refcount;	/* number of reference held should be >=
				 * ifa_count */
	uint32_t ifa_count;	/* IFA's we hold (in our list - ifalist) */
	uint32_t num_v6;	/* number of v6 addresses */
	uint32_t num_v4;	/* number of v4 addresses */
	uint32_t registered_af;	/* registered address family for i/f events */
	char ifn_name[SCTP_IFNAMSIZ];
};

/* SCTP local IFA flags */
#define SCTP_ADDR_VALID         0x00000001	/* its up and active */
#define SCTP_BEING_DELETED      0x00000002	/* being deleted, when
						 * refcount = 0. Note that it
						 * is pulled from the ifn list
						 * and ifa_p is nulled right
						 * away but it cannot be freed
						 * until the last *net
						 * pointing to it is deleted. */
#define SCTP_ADDR_DEFER_USE     0x00000004	/* Hold off using this one */
#define SCTP_ADDR_IFA_UNUSEABLE 0x00000008

struct sctp_ifa {
	LIST_ENTRY(sctp_ifa) next_ifa;
	LIST_ENTRY(sctp_ifa) next_bucket;
	struct sctp_ifn *ifn_p;	/* back pointer to parent ifn */
	void *ifa;		/* pointer to ifa, needed for flag update for
				 * that we MUST lock appropriate locks. This
				 * is for V6. */
	union sctp_sockstore address;
	uint32_t refcount;	/* number of folks refering to this */
	uint32_t flags;
	uint32_t localifa_flags;
	uint32_t vrf_id;	/* vrf_id of this addr (for deleting) */
	uint8_t src_is_loop;
	uint8_t src_is_priv;
	uint8_t src_is_glob;
	uint8_t resv;
};

struct sctp_laddr {
	LIST_ENTRY(sctp_laddr) sctp_nxt_addr;	/* next in list */
	struct sctp_ifa *ifa;
	uint32_t action;	/* Used during asconf and adding if no-zero
				 * src-addr selection will not consider this
				 * address. */
	struct timeval start_time;	/* time when this address was created */
};

struct sctp_block_entry {
	int error;
};

struct sctp_timewait {
	uint32_t tv_sec_at_expire;	/* the seconds from boot to expire */
	uint32_t v_tag;		/* the vtag that can not be reused */
	uint16_t lport;		/* the local port used in vtag */
	uint16_t rport;		/* the remote port used in vtag */
};

struct sctp_tagblock {
	LIST_ENTRY(sctp_tagblock) sctp_nxt_tagblock;
	struct sctp_timewait vtag_block[SCTP_NUMBER_IN_VTAG_BLOCK];
};

struct sctp_epinfo {
	struct socket *udp_tun_socket;
	struct sctpasochead *sctp_asochash;
	u_long hashasocmark;

	struct sctppcbhead *sctp_ephash;
	u_long hashmark;

	/*-
	 * The TCP model represents a substantial overhead in that we get an
	 * additional hash table to keep explicit connections in. The
	 * listening TCP endpoint will exist in the usual ephash above and
	 * accept only INIT's. It will be incapable of sending off an INIT.
	 * When a dg arrives we must look in the normal ephash. If we find a
	 * TCP endpoint that will tell us to go to the specific endpoint
	 * hash and re-hash to find the right assoc/socket. If we find a UDP
	 * model socket we then must complete the lookup. If this fails,
	 * i.e. no association can be found then we must continue to see if
	 * a sctp_peeloff()'d socket is in the tcpephash (a spun off socket
	 * acts like a TCP model connected socket).
	 */
	struct sctppcbhead *sctp_tcpephash;
	u_long hashtcpmark;
	uint32_t hashtblsize;

	struct sctp_vrflist *sctp_vrfhash;
	u_long hashvrfmark;

	struct sctp_ifnlist *vrf_ifn_hash;
	u_long vrf_ifn_hashmark;

	struct sctppcbhead listhead;
	struct sctpladdr addr_wq;

	/* ep zone info */
	sctp_zone_t ipi_zone_ep;
	sctp_zone_t ipi_zone_asoc;
	sctp_zone_t ipi_zone_laddr;
	sctp_zone_t ipi_zone_net;
	sctp_zone_t ipi_zone_chunk;
	sctp_zone_t ipi_zone_readq;
	sctp_zone_t ipi_zone_strmoq;
	sctp_zone_t ipi_zone_asconf;
	sctp_zone_t ipi_zone_asconf_ack;

	struct rwlock ipi_ep_mtx;
	struct mtx ipi_iterator_wq_mtx;
	struct rwlock ipi_addr_mtx;
	struct mtx ipi_pktlog_mtx;
	struct mtx wq_addr_mtx;
	uint32_t ipi_count_ep;

	/* assoc/tcb zone info */
	uint32_t ipi_count_asoc;

	/* local addrlist zone info */
	uint32_t ipi_count_laddr;

	/* remote addrlist zone info */
	uint32_t ipi_count_raddr;

	/* chunk structure list for output */
	uint32_t ipi_count_chunk;

	/* socket queue zone info */
	uint32_t ipi_count_readq;

	/* socket queue zone info */
	uint32_t ipi_count_strmoq;

	/* Number of vrfs */
	uint32_t ipi_count_vrfs;

	/* Number of ifns */
	uint32_t ipi_count_ifns;

	/* Number of ifas */
	uint32_t ipi_count_ifas;

	/* system wide number of free chunks hanging around */
	uint32_t ipi_free_chunks;
	uint32_t ipi_free_strmoq;

	struct sctpvtaghead vtag_timewait[SCTP_STACK_VTAG_HASH_SIZE];

	/* address work queue handling */
	struct sctp_timer addr_wq_timer;

};

struct sctp_base_info {
	/*
	 * All static structures that anchor the system must be here.
	 */
	struct sctp_epinfo sctppcbinfo;
#if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT)
	struct sctpstat *sctpstat;
#else
	struct sctpstat sctpstat;
#endif
	struct sctp_sysctl sctpsysctl;
	uint8_t first_time;
	char sctp_pcb_initialized;
#if defined(SCTP_PACKET_LOGGING)
	int packet_log_writers;
	int packet_log_end;
	uint8_t packet_log_buffer[SCTP_PACKET_LOG_SIZE];
#endif
};

/*-
 * Here we have all the relevant information for each SCTP entity created. We
 * will need to modify this as approprate. We also need to figure out how to
 * access /dev/random.
 */
struct sctp_pcb {
	unsigned int time_of_secret_change;	/* number of seconds from
						 * timeval.tv_sec */
	uint32_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_NUMBER_OF_SECRETS];
	unsigned int size_of_a_cookie;

	unsigned int sctp_timeoutticks[SCTP_NUM_TMRS];
	unsigned int sctp_minrto;
	unsigned int sctp_maxrto;
	unsigned int initial_rto;
	int initial_init_rto_max;

	unsigned int sctp_sack_freq;
	uint32_t sctp_sws_sender;
	uint32_t sctp_sws_receiver;

	uint32_t sctp_default_cc_module;
	uint32_t sctp_default_ss_module;
	/* authentication related fields */
	struct sctp_keyhead shared_keys;
	sctp_auth_chklist_t *local_auth_chunks;
	sctp_hmaclist_t *local_hmacs;
	uint16_t default_keyid;

	/* various thresholds */
	/* Max times I will init at a guy */
	uint16_t max_init_times;

	/* Max times I will send before we consider someone dead */
	uint16_t max_send_times;

	uint16_t def_net_failure;

	uint16_t def_net_pf_threshold;

	/* number of streams to pre-open on a association */
	uint16_t pre_open_stream_count;
	uint16_t max_open_streams_intome;

	/* random number generator */
	uint32_t random_counter;
	uint8_t random_numbers[SCTP_SIGNATURE_ALOC_SIZE];
	uint8_t random_store[SCTP_SIGNATURE_ALOC_SIZE];

	/*
	 * This timer is kept running per endpoint.  When it fires it will
	 * change the secret key.  The default is once a hour
	 */
	struct sctp_timer signature_change;

	/* Zero copy full buffer timer */
	struct sctp_timer zero_copy_timer;
	/* Zero copy app to transport (sendq) read repulse timer */
	struct sctp_timer zero_copy_sendq_timer;
	uint32_t def_cookie_life;
	/* defaults to 0 */
	int auto_close_time;
	uint32_t initial_sequence_debug;
	uint32_t adaptation_layer_indicator;
	uint32_t store_at;
	uint32_t max_burst;
	uint32_t fr_max_burst;
#ifdef INET6
	uint32_t default_flowlabel;
#endif
	uint8_t default_dscp;
	char current_secret_number;
	char last_secret_number;
};

#ifndef SCTP_ALIGNMENT
#define SCTP_ALIGNMENT 32
#endif

#ifndef SCTP_ALIGNM1
#define SCTP_ALIGNM1 (SCTP_ALIGNMENT-1)
#endif

#define sctp_lport ip_inp.inp.inp_lport

struct sctp_pcbtsn_rlog {
	uint32_t vtag;
	uint16_t strm;
	uint16_t seq;
	uint16_t sz;
	uint16_t flgs;
};

#define SCTP_READ_LOG_SIZE 135	/* we choose the number to make a pcb a page */

struct sctp_inpcb {
	/*-
	 * put an inpcb in front of it all, kind of a waste but we need to
	 * for compatability with all the other stuff.
	 */
	union {
		struct inpcb inp;
		char align[(sizeof(struct in6pcb) + SCTP_ALIGNM1) &
		        ~SCTP_ALIGNM1];
	}     ip_inp;

	/* Socket buffer lock protects read_queue and of course sb_cc */
	struct sctp_readhead read_queue;

	              LIST_ENTRY(sctp_inpcb) sctp_list;	/* lists all endpoints */
	/* hash of all endpoints for model */
	              LIST_ENTRY(sctp_inpcb) sctp_hash;
	/* count of local addresses bound, 0 if bound all */
	int laddr_count;

	/* list of addrs in use by the EP, NULL if bound-all */
	struct sctpladdr sctp_addr_list;
	/*
	 * used for source address selection rotation when we are subset
	 * bound
	 */
	struct sctp_laddr *next_addr_touse;

	/* back pointer to our socket */
	struct socket *sctp_socket;
	uint32_t sctp_flags;	/* INP state flag set */
	uint32_t sctp_features;	/* Feature flags */
	uint32_t sctp_mobility_features;	/* Mobility  Feature flags */
	struct sctp_pcb sctp_ep;/* SCTP ep data */
	/* head of the hash of all associations */
	struct sctpasochead *sctp_tcbhash;
	u_long sctp_hashmark;
	/* head of the list of all associations */
	struct sctpasochead sctp_asoc_list;
#ifdef SCTP_TRACK_FREED_ASOCS
	struct sctpasochead sctp_asoc_free_list;
#endif
	struct sctp_iterator *inp_starting_point_for_iterator;
	uint32_t sctp_frag_point;
	uint32_t partial_delivery_point;
	uint32_t sctp_context;
	uint32_t sctp_cmt_on_off;
	uint32_t sctp_ecn_enable;
	struct sctp_nonpad_sndrcvinfo def_send;
	/*-
	 * These three are here for the sosend_dgram
	 * (pkt, pkt_last and control).
	 * routine. However, I don't think anyone in
	 * the current FreeBSD kernel calls this. So
	 * they are candidates with sctp_sendm for
	 * de-supporting.
	 */
	struct mbuf *pkt, *pkt_last;
	struct mbuf *control;
	struct mtx inp_mtx;
	struct mtx inp_create_mtx;
	struct mtx inp_rdata_mtx;
	int32_t refcount;
	uint32_t def_vrf_id;
	uint32_t total_sends;
	uint32_t total_recvs;
	uint32_t last_abort_code;
	uint32_t total_nospaces;
	struct sctpasochead *sctp_asocidhash;
	u_long hashasocidmark;
	uint32_t sctp_associd_counter;

#ifdef SCTP_ASOCLOG_OF_TSNS
	struct sctp_pcbtsn_rlog readlog[SCTP_READ_LOG_SIZE];
	uint32_t readlog_index;
#endif
};

struct sctp_tcb {
	struct socket *sctp_socket;	/* back pointer to socket */
	struct sctp_inpcb *sctp_ep;	/* back pointer to ep */
	           LIST_ENTRY(sctp_tcb) sctp_tcbhash;	/* next link in hash
							 * table */
	           LIST_ENTRY(sctp_tcb) sctp_tcblist;	/* list of all of the
							 * TCB's */
	           LIST_ENTRY(sctp_tcb) sctp_tcbasocidhash;	/* next link in asocid
								 * hash table */
	           LIST_ENTRY(sctp_tcb) sctp_asocs;	/* vtag hash list */
	struct sctp_block_entry *block_entry;	/* pointer locked by  socket
						 * send buffer */
	struct sctp_association asoc;
	/*-
	 * freed_by_sorcv_sincelast is protected by the sockbuf_lock NOT the
	 * tcb_lock. Its special in this way to help avoid extra mutex calls
	 * in the reading of data.
	 */
	uint32_t freed_by_sorcv_sincelast;
	uint32_t total_sends;
	uint32_t total_recvs;
	int freed_from_where;
	uint16_t rport;		/* remote port in network format */
	uint16_t resv;
	struct mtx tcb_mtx;
	struct mtx tcb_send_mtx;
};

#include <netinet/sctp_lock_bsd.h>

/* TODO where to put non-_KERNEL things for __Userspace__? */
#if defined(_KERNEL) || defined(__Userspace__)

/* Attention Julian, this is the extern that
 * goes with the base info. sctp_pcb.c has
 * the real definition.
 */
VNET_DECLARE(struct sctp_base_info, system_base_info);

#ifdef INET6
int SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b);

#endif

void sctp_fill_pcbinfo(struct sctp_pcbinfo *);

struct sctp_ifn *
         sctp_find_ifn(void *ifn, uint32_t ifn_index);

struct sctp_vrf *sctp_allocate_vrf(int vrfid);
struct sctp_vrf *sctp_find_vrf(uint32_t vrfid);
void sctp_free_vrf(struct sctp_vrf *vrf);

/*-
 * Change address state, can be used if
 * O/S supports telling transports about
 * changes to IFA/IFN's (link layer triggers).
 * If a ifn goes down, we will do src-addr-selection
 * and NOT use that, as a source address. This does
 * not stop the routing system from routing out
 * that interface, but we won't put it as a source.
 */
void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index);
void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index);

struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrfid,
    void *ifn, uint32_t ifn_index, uint32_t ifn_type,
    const char *if_name,
    void *ifa, struct sockaddr *addr, uint32_t ifa_flags,
    int dynamic_add);

void sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu);

void sctp_free_ifn(struct sctp_ifn *sctp_ifnp);
void sctp_free_ifa(struct sctp_ifa *sctp_ifap);

void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
    uint32_t ifn_index, const char *if_name);

struct sctp_nets *sctp_findnet(struct sctp_tcb *, struct sockaddr *);

struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, int, uint32_t);

int
sctp_inpcb_bind(struct socket *, struct sockaddr *,
    struct sctp_ifa *, struct thread *);

struct sctp_tcb *
sctp_findassociation_addr(struct mbuf *, int, int,
    struct sctphdr *, struct sctp_chunkhdr *, struct sctp_inpcb **,
    struct sctp_nets **, uint32_t vrf_id);

struct sctp_tcb *
sctp_findassociation_addr_sa(struct sockaddr *,
    struct sockaddr *, struct sctp_inpcb **, struct sctp_nets **, int, uint32_t);

void
sctp_move_pcb_and_assoc(struct sctp_inpcb *, struct sctp_inpcb *,
    struct sctp_tcb *);

/*-
 * For this call ep_addr, the to is the destination endpoint address of the
 * peer (relative to outbound). The from field is only used if the TCP model
 * is enabled and helps distingush amongst the subset bound (non-boundall).
 * The TCP model MAY change the actual ep field, this is why it is passed.
 */
struct sctp_tcb *
sctp_findassociation_ep_addr(struct sctp_inpcb **,
    struct sockaddr *, struct sctp_nets **, struct sockaddr *,
    struct sctp_tcb *);

struct sctp_tcb *
         sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock);

struct sctp_tcb *
sctp_findassociation_ep_asocid(struct sctp_inpcb *,
    sctp_assoc_t, int);

struct sctp_tcb *
sctp_findassociation_ep_asconf(struct mbuf *, int, int,
    struct sctphdr *, struct sctp_inpcb **, struct sctp_nets **, uint32_t vrf_id);

int sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id);

int sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id);

void sctp_inpcb_free(struct sctp_inpcb *, int, int);

struct sctp_tcb *
sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
    int *, uint32_t, uint32_t, struct thread *);

int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int);

void sctp_delete_from_timewait(uint32_t, uint16_t, uint16_t);

int sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport);

void
     sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport);

void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t);

int sctp_insert_laddr(struct sctpladdr *, struct sctp_ifa *, uint32_t);

void sctp_remove_laddr(struct sctp_laddr *);

void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *);

int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int);

void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *);

int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *);

void sctp_pcb_init(void);

void sctp_pcb_finish(void);

void sctp_add_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);
void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *);

int
sctp_load_addresses_from_init(struct sctp_tcb *, struct mbuf *, int, int,
    int, struct sctphdr *, struct sockaddr *);

int
sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *,
    struct sctp_nets *);

int sctp_is_vtag_good(struct sctp_inpcb *, uint32_t, uint16_t lport, uint16_t rport, struct timeval *, int);

/* void sctp_drain(void); */

int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *);

int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp);

/*-
 * Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg
 * indicates run on ONLY assoc's of the specified endpoint.
 */
int
sctp_initiate_iterator(inp_func inpf,
    asoc_func af,
    inp_func inpe,
    uint32_t, uint32_t,
    uint32_t, void *,
    uint32_t,
    end_func ef,
    struct sctp_inpcb *,
    uint8_t co_off);

#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
void
     sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use);

#endif

#ifdef INVARIANTS
void
     sctp_validate_no_locks(struct sctp_inpcb *inp);

#endif

#endif				/* _KERNEL */
#endif				/* !__sctp_pcb_h__ */


code:
/*-
 * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
 * Copyright (c) 2008-2011, by Randall Stewart. All rights reserved.
 * Copyright (c) 2008-2011, 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.
 */

/* $KAME: sctp_peeloff.h,v 1.6 2005/03/06 16:04:18 itojun Exp $	 */

#include <sys/cdefs.h>
__FBSDID("$FreeBSD: release/9.0.0/sys/netinet/sctp_peeloff.h 218319 2011-02-05 12:12:51Z rrs $");

#ifndef __sctp_peeloff_h__
#define __sctp_peeloff_h__

#if defined(_KERNEL)

int sctp_can_peel_off(struct socket *, sctp_assoc_t);
int sctp_do_peeloff(struct socket *, struct socket *, sctp_assoc_t);
struct socket *sctp_get_peeloff(struct socket *, sctp_assoc_t, int *);

#endif				/* _KERNEL */

#endif