michael@0: /*- michael@0: * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. michael@0: * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. michael@0: * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. michael@0: * michael@0: * Redistribution and use in source and binary forms, with or without michael@0: * modification, are permitted provided that the following conditions are met: michael@0: * michael@0: * a) Redistributions of source code must retain the above copyright notice, michael@0: * this list of conditions and the following disclaimer. michael@0: * michael@0: * b) Redistributions in binary form must reproduce the above copyright michael@0: * notice, this list of conditions and the following disclaimer in michael@0: * the documentation and/or other materials provided with the distribution. michael@0: * michael@0: * c) Neither the name of Cisco Systems, Inc. nor the names of its michael@0: * contributors may be used to endorse or promote products derived michael@0: * from this software without specific prior written permission. michael@0: * michael@0: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, michael@0: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE michael@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE michael@0: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR michael@0: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF michael@0: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS michael@0: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN michael@0: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) michael@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF michael@0: * THE POSSIBILITY OF SUCH DAMAGE. michael@0: */ michael@0: michael@0: #ifdef __FreeBSD__ michael@0: #include michael@0: __FBSDID("$FreeBSD: head/sys/netinet/sctp_pcb.h 254248 2013-08-12 13:52:15Z tuexen $"); michael@0: #endif michael@0: michael@0: #ifndef _NETINET_SCTP_PCB_H_ michael@0: #define _NETINET_SCTP_PCB_H_ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: LIST_HEAD(sctppcbhead, sctp_inpcb); michael@0: LIST_HEAD(sctpasochead, sctp_tcb); michael@0: LIST_HEAD(sctpladdr, sctp_laddr); michael@0: LIST_HEAD(sctpvtaghead, sctp_tagblock); michael@0: LIST_HEAD(sctp_vrflist, sctp_vrf); michael@0: LIST_HEAD(sctp_ifnlist, sctp_ifn); michael@0: LIST_HEAD(sctp_ifalist, sctp_ifa); michael@0: TAILQ_HEAD(sctp_readhead, sctp_queued_to_read); michael@0: TAILQ_HEAD(sctp_streamhead, sctp_stream_queue_pending); michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #define SCTP_PCBHASH_ALLADDR(port, mask) (port & mask) michael@0: #define SCTP_PCBHASH_ASOC(tag, mask) (tag & mask) michael@0: michael@0: struct sctp_vrf { michael@0: LIST_ENTRY (sctp_vrf) next_vrf; michael@0: struct sctp_ifalist *vrf_addr_hash; michael@0: struct sctp_ifnlist ifnlist; michael@0: uint32_t vrf_id; michael@0: uint32_t tbl_id_v4; /* default v4 table id */ michael@0: uint32_t tbl_id_v6; /* default v6 table id */ michael@0: uint32_t total_ifa_count; michael@0: u_long vrf_addr_hashmark; michael@0: uint32_t refcount; michael@0: }; michael@0: michael@0: struct sctp_ifn { michael@0: struct sctp_ifalist ifalist; michael@0: struct sctp_vrf *vrf; michael@0: LIST_ENTRY(sctp_ifn) next_ifn; michael@0: LIST_ENTRY(sctp_ifn) next_bucket; michael@0: void *ifn_p; /* never access without appropriate lock */ michael@0: uint32_t ifn_mtu; michael@0: uint32_t ifn_type; michael@0: uint32_t ifn_index; /* shorthand way to look at ifn for reference */ michael@0: uint32_t refcount; /* number of reference held should be >= ifa_count */ michael@0: uint32_t ifa_count; /* IFA's we hold (in our list - ifalist)*/ michael@0: uint32_t num_v6; /* number of v6 addresses */ michael@0: uint32_t num_v4; /* number of v4 addresses */ michael@0: uint32_t registered_af; /* registered address family for i/f events */ michael@0: char ifn_name[SCTP_IFNAMSIZ]; michael@0: }; michael@0: michael@0: /* SCTP local IFA flags */ michael@0: #define SCTP_ADDR_VALID 0x00000001 /* its up and active */ michael@0: #define SCTP_BEING_DELETED 0x00000002 /* being deleted, michael@0: * when refcount = 0. Note michael@0: * that it is pulled from the ifn list michael@0: * and ifa_p is nulled right away but michael@0: * it cannot be freed until the last *net michael@0: * pointing to it is deleted. michael@0: */ michael@0: #define SCTP_ADDR_DEFER_USE 0x00000004 /* Hold off using this one */ michael@0: #define SCTP_ADDR_IFA_UNUSEABLE 0x00000008 michael@0: michael@0: struct sctp_ifa { michael@0: LIST_ENTRY(sctp_ifa) next_ifa; michael@0: LIST_ENTRY(sctp_ifa) next_bucket; michael@0: struct sctp_ifn *ifn_p; /* back pointer to parent ifn */ michael@0: void *ifa; /* pointer to ifa, needed for flag michael@0: * update for that we MUST lock michael@0: * appropriate locks. This is for V6. michael@0: */ michael@0: union sctp_sockstore address; michael@0: uint32_t refcount; /* number of folks refering to this */ michael@0: uint32_t flags; michael@0: uint32_t localifa_flags; michael@0: uint32_t vrf_id; /* vrf_id of this addr (for deleting) */ michael@0: uint8_t src_is_loop; michael@0: uint8_t src_is_priv; michael@0: uint8_t src_is_glob; michael@0: uint8_t resv; michael@0: }; michael@0: michael@0: struct sctp_laddr { michael@0: LIST_ENTRY(sctp_laddr) sctp_nxt_addr; /* next in list */ michael@0: struct sctp_ifa *ifa; michael@0: uint32_t action; /* Used during asconf and adding michael@0: * if no-zero src-addr selection will michael@0: * not consider this address. michael@0: */ michael@0: struct timeval start_time; /* time when this address was created */ michael@0: }; michael@0: michael@0: struct sctp_block_entry { michael@0: int error; michael@0: }; michael@0: michael@0: struct sctp_timewait { michael@0: uint32_t tv_sec_at_expire; /* the seconds from boot to expire */ michael@0: uint32_t v_tag; /* the vtag that can not be reused */ michael@0: uint16_t lport; /* the local port used in vtag */ michael@0: uint16_t rport; /* the remote port used in vtag */ michael@0: }; michael@0: michael@0: struct sctp_tagblock { michael@0: LIST_ENTRY(sctp_tagblock) sctp_nxt_tagblock; michael@0: struct sctp_timewait vtag_block[SCTP_NUMBER_IN_VTAG_BLOCK]; michael@0: }; michael@0: michael@0: michael@0: struct sctp_epinfo { michael@0: #if defined(__FreeBSD__) michael@0: #ifdef INET michael@0: struct socket *udp4_tun_socket; michael@0: #endif michael@0: #ifdef INET6 michael@0: struct socket *udp6_tun_socket; michael@0: #endif michael@0: #endif michael@0: struct sctpasochead *sctp_asochash; michael@0: u_long hashasocmark; michael@0: michael@0: struct sctppcbhead *sctp_ephash; michael@0: u_long hashmark; michael@0: michael@0: /*- michael@0: * The TCP model represents a substantial overhead in that we get an michael@0: * additional hash table to keep explicit connections in. The michael@0: * listening TCP endpoint will exist in the usual ephash above and michael@0: * accept only INIT's. It will be incapable of sending off an INIT. michael@0: * When a dg arrives we must look in the normal ephash. If we find a michael@0: * TCP endpoint that will tell us to go to the specific endpoint michael@0: * hash and re-hash to find the right assoc/socket. If we find a UDP michael@0: * model socket we then must complete the lookup. If this fails, michael@0: * i.e. no association can be found then we must continue to see if michael@0: * a sctp_peeloff()'d socket is in the tcpephash (a spun off socket michael@0: * acts like a TCP model connected socket). michael@0: */ michael@0: struct sctppcbhead *sctp_tcpephash; michael@0: u_long hashtcpmark; michael@0: uint32_t hashtblsize; michael@0: michael@0: struct sctp_vrflist *sctp_vrfhash; michael@0: u_long hashvrfmark; michael@0: michael@0: struct sctp_ifnlist *vrf_ifn_hash; michael@0: u_long vrf_ifn_hashmark; michael@0: michael@0: struct sctppcbhead listhead; michael@0: struct sctpladdr addr_wq; michael@0: michael@0: #if defined(__APPLE__) michael@0: struct inpcbhead inplisthead; michael@0: struct inpcbinfo sctbinfo; michael@0: #endif michael@0: /* ep zone info */ michael@0: sctp_zone_t ipi_zone_ep; michael@0: sctp_zone_t ipi_zone_asoc; michael@0: sctp_zone_t ipi_zone_laddr; michael@0: sctp_zone_t ipi_zone_net; michael@0: sctp_zone_t ipi_zone_chunk; michael@0: sctp_zone_t ipi_zone_readq; michael@0: sctp_zone_t ipi_zone_strmoq; michael@0: sctp_zone_t ipi_zone_asconf; michael@0: sctp_zone_t ipi_zone_asconf_ack; michael@0: michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 503000 michael@0: #if __FreeBSD_version <= 602000 michael@0: struct mtx ipi_ep_mtx; michael@0: #else michael@0: struct rwlock ipi_ep_mtx; michael@0: #endif michael@0: struct mtx ipi_iterator_wq_mtx; michael@0: #if __FreeBSD_version <= 602000 michael@0: struct mtx ipi_addr_mtx; michael@0: #else michael@0: struct rwlock ipi_addr_mtx; michael@0: #endif michael@0: struct mtx ipi_pktlog_mtx; michael@0: struct mtx wq_addr_mtx; michael@0: #elif defined(SCTP_PROCESS_LEVEL_LOCKS) michael@0: userland_mutex_t ipi_ep_mtx; michael@0: userland_mutex_t ipi_addr_mtx; michael@0: userland_mutex_t ipi_count_mtx; michael@0: userland_mutex_t ipi_pktlog_mtx; michael@0: userland_mutex_t wq_addr_mtx; michael@0: #elif defined(__APPLE__) michael@0: #ifdef _KERN_LOCKS_H_ michael@0: lck_mtx_t *ipi_addr_mtx; michael@0: lck_mtx_t *ipi_count_mtx; michael@0: lck_mtx_t *ipi_pktlog_mtx; michael@0: lck_mtx_t *logging_mtx; michael@0: lck_mtx_t *wq_addr_mtx; michael@0: #else michael@0: void *ipi_count_mtx; michael@0: void *logging_mtx; michael@0: #endif /* _KERN_LOCKS_H_ */ michael@0: #elif defined(__Windows__) michael@0: struct rwlock ipi_ep_lock; michael@0: struct rwlock ipi_addr_lock; michael@0: struct spinlock ipi_pktlog_mtx; michael@0: struct rwlock wq_addr_mtx; michael@0: #elif defined(__Userspace__) michael@0: /* TODO decide on __Userspace__ locks */ michael@0: #endif michael@0: uint32_t ipi_count_ep; michael@0: michael@0: /* assoc/tcb zone info */ michael@0: uint32_t ipi_count_asoc; michael@0: michael@0: /* local addrlist zone info */ michael@0: uint32_t ipi_count_laddr; michael@0: michael@0: /* remote addrlist zone info */ michael@0: uint32_t ipi_count_raddr; michael@0: michael@0: /* chunk structure list for output */ michael@0: uint32_t ipi_count_chunk; michael@0: michael@0: /* socket queue zone info */ michael@0: uint32_t ipi_count_readq; michael@0: michael@0: /* socket queue zone info */ michael@0: uint32_t ipi_count_strmoq; michael@0: michael@0: /* Number of vrfs */ michael@0: uint32_t ipi_count_vrfs; michael@0: michael@0: /* Number of ifns */ michael@0: uint32_t ipi_count_ifns; michael@0: michael@0: /* Number of ifas */ michael@0: uint32_t ipi_count_ifas; michael@0: michael@0: /* system wide number of free chunks hanging around */ michael@0: uint32_t ipi_free_chunks; michael@0: uint32_t ipi_free_strmoq; michael@0: michael@0: struct sctpvtaghead vtag_timewait[SCTP_STACK_VTAG_HASH_SIZE]; michael@0: michael@0: /* address work queue handling */ michael@0: struct sctp_timer addr_wq_timer; michael@0: michael@0: #if defined(_SCTP_NEEDS_CALLOUT_) || defined(_USER_SCTP_NEEDS_CALLOUT_) michael@0: struct calloutlist callqueue; michael@0: #endif michael@0: }; michael@0: michael@0: michael@0: struct sctp_base_info { michael@0: /* All static structures that michael@0: * anchor the system must be here. michael@0: */ michael@0: struct sctp_epinfo sctppcbinfo; michael@0: #if defined(__FreeBSD__) && defined(SMP) && defined(SCTP_USE_PERCPU_STAT) michael@0: struct sctpstat *sctpstat; michael@0: #else michael@0: struct sctpstat sctpstat; michael@0: #endif michael@0: struct sctp_sysctl sctpsysctl; michael@0: uint8_t first_time; michael@0: char sctp_pcb_initialized; michael@0: #if defined(SCTP_PACKET_LOGGING) michael@0: int packet_log_writers; michael@0: int packet_log_end; michael@0: uint8_t packet_log_buffer[SCTP_PACKET_LOG_SIZE]; michael@0: #endif michael@0: #if defined(__APPLE__) michael@0: int sctp_main_timer_ticks; michael@0: #endif michael@0: #if defined(__Userspace__) michael@0: userland_mutex_t timer_mtx; michael@0: userland_thread_t timer_thread; michael@0: uint8_t timer_thread_should_exit; michael@0: #if !defined(__Userspace_os_Windows) michael@0: #if defined(INET) || defined(INET6) michael@0: int userspace_route; michael@0: userland_thread_t recvthreadroute; michael@0: #endif michael@0: #endif michael@0: #ifdef INET michael@0: int userspace_rawsctp; michael@0: int userspace_udpsctp; michael@0: userland_thread_t recvthreadraw; michael@0: userland_thread_t recvthreadudp; michael@0: #endif michael@0: #ifdef INET6 michael@0: int userspace_rawsctp6; michael@0: int userspace_udpsctp6; michael@0: userland_thread_t recvthreadraw6; michael@0: userland_thread_t recvthreadudp6; michael@0: #endif michael@0: int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df); michael@0: void (*debug_printf)(const char *format, ...); michael@0: #endif michael@0: }; michael@0: michael@0: /*- michael@0: * Here we have all the relevant information for each SCTP entity created. We michael@0: * will need to modify this as approprate. We also need to figure out how to michael@0: * access /dev/random. michael@0: */ michael@0: struct sctp_pcb { michael@0: unsigned int time_of_secret_change; /* number of seconds from michael@0: * timeval.tv_sec */ michael@0: uint32_t secret_key[SCTP_HOW_MANY_SECRETS][SCTP_NUMBER_OF_SECRETS]; michael@0: unsigned int size_of_a_cookie; michael@0: michael@0: unsigned int sctp_timeoutticks[SCTP_NUM_TMRS]; michael@0: unsigned int sctp_minrto; michael@0: unsigned int sctp_maxrto; michael@0: unsigned int initial_rto; michael@0: int initial_init_rto_max; michael@0: michael@0: unsigned int sctp_sack_freq; michael@0: uint32_t sctp_sws_sender; michael@0: uint32_t sctp_sws_receiver; michael@0: michael@0: uint32_t sctp_default_cc_module; michael@0: uint32_t sctp_default_ss_module; michael@0: /* authentication related fields */ michael@0: struct sctp_keyhead shared_keys; michael@0: sctp_auth_chklist_t *local_auth_chunks; michael@0: sctp_hmaclist_t *local_hmacs; michael@0: uint16_t default_keyid; michael@0: michael@0: /* various thresholds */ michael@0: /* Max times I will init at a guy */ michael@0: uint16_t max_init_times; michael@0: michael@0: /* Max times I will send before we consider someone dead */ michael@0: uint16_t max_send_times; michael@0: michael@0: uint16_t def_net_failure; michael@0: michael@0: uint16_t def_net_pf_threshold; michael@0: michael@0: /* number of streams to pre-open on a association */ michael@0: uint16_t pre_open_stream_count; michael@0: uint16_t max_open_streams_intome; michael@0: michael@0: /* random number generator */ michael@0: uint32_t random_counter; michael@0: uint8_t random_numbers[SCTP_SIGNATURE_ALOC_SIZE]; michael@0: uint8_t random_store[SCTP_SIGNATURE_ALOC_SIZE]; michael@0: michael@0: /* michael@0: * This timer is kept running per endpoint. When it fires it will michael@0: * change the secret key. The default is once a hour michael@0: */ michael@0: struct sctp_timer signature_change; michael@0: michael@0: /* Zero copy full buffer timer */ michael@0: struct sctp_timer zero_copy_timer; michael@0: /* Zero copy app to transport (sendq) read repulse timer */ michael@0: struct sctp_timer zero_copy_sendq_timer; michael@0: uint32_t def_cookie_life; michael@0: /* defaults to 0 */ michael@0: int auto_close_time; michael@0: uint32_t initial_sequence_debug; michael@0: uint32_t adaptation_layer_indicator; michael@0: uint8_t adaptation_layer_indicator_provided; michael@0: uint32_t store_at; michael@0: uint32_t max_burst; michael@0: uint32_t fr_max_burst; michael@0: #ifdef INET6 michael@0: uint32_t default_flowlabel; michael@0: #endif michael@0: uint8_t default_dscp; michael@0: char current_secret_number; michael@0: char last_secret_number; michael@0: uint16_t port; /* remote UDP encapsulation port */ michael@0: }; michael@0: michael@0: #ifndef SCTP_ALIGNMENT michael@0: #define SCTP_ALIGNMENT 32 michael@0: #endif michael@0: michael@0: #ifndef SCTP_ALIGNM1 michael@0: #define SCTP_ALIGNM1 (SCTP_ALIGNMENT-1) michael@0: #endif michael@0: michael@0: #define sctp_lport ip_inp.inp.inp_lport michael@0: michael@0: struct sctp_pcbtsn_rlog { michael@0: uint32_t vtag; michael@0: uint16_t strm; michael@0: uint16_t seq; michael@0: uint16_t sz; michael@0: uint16_t flgs; michael@0: }; michael@0: #define SCTP_READ_LOG_SIZE 135 /* we choose the number to make a pcb a page */ michael@0: michael@0: michael@0: struct sctp_inpcb { michael@0: /*- michael@0: * put an inpcb in front of it all, kind of a waste but we need to michael@0: * for compatability with all the other stuff. michael@0: */ michael@0: union { michael@0: struct inpcb inp; michael@0: char align[(sizeof(struct in6pcb) + SCTP_ALIGNM1) & michael@0: ~SCTP_ALIGNM1]; michael@0: } ip_inp; michael@0: michael@0: #if defined(__APPLE__) michael@0: /* leave some space in case i386 inpcb is bigger than ppc */ michael@0: uint8_t padding[128]; michael@0: #endif michael@0: michael@0: /* Socket buffer lock protects read_queue and of course sb_cc */ michael@0: struct sctp_readhead read_queue; michael@0: michael@0: LIST_ENTRY(sctp_inpcb) sctp_list; /* lists all endpoints */ michael@0: /* hash of all endpoints for model */ michael@0: LIST_ENTRY(sctp_inpcb) sctp_hash; michael@0: /* count of local addresses bound, 0 if bound all */ michael@0: int laddr_count; michael@0: michael@0: /* list of addrs in use by the EP, NULL if bound-all */ michael@0: struct sctpladdr sctp_addr_list; michael@0: /* used for source address selection rotation when we are subset bound */ michael@0: struct sctp_laddr *next_addr_touse; michael@0: michael@0: /* back pointer to our socket */ michael@0: struct socket *sctp_socket; michael@0: uint64_t sctp_features; /* Feature flags */ michael@0: uint32_t sctp_flags; /* INP state flag set */ michael@0: uint32_t sctp_mobility_features; /* Mobility Feature flags */ michael@0: struct sctp_pcb sctp_ep;/* SCTP ep data */ michael@0: /* head of the hash of all associations */ michael@0: struct sctpasochead *sctp_tcbhash; michael@0: u_long sctp_hashmark; michael@0: /* head of the list of all associations */ michael@0: struct sctpasochead sctp_asoc_list; michael@0: #ifdef SCTP_TRACK_FREED_ASOCS michael@0: struct sctpasochead sctp_asoc_free_list; michael@0: #endif michael@0: struct sctp_iterator *inp_starting_point_for_iterator; michael@0: uint32_t sctp_frag_point; michael@0: uint32_t partial_delivery_point; michael@0: uint32_t sctp_context; michael@0: uint8_t local_strreset_support; michael@0: uint32_t sctp_cmt_on_off; michael@0: uint32_t sctp_ecn_enable; michael@0: struct sctp_nonpad_sndrcvinfo def_send; michael@0: /*- michael@0: * These three are here for the sosend_dgram michael@0: * (pkt, pkt_last and control). michael@0: * routine. However, I don't think anyone in michael@0: * the current FreeBSD kernel calls this. So michael@0: * they are candidates with sctp_sendm for michael@0: * de-supporting. michael@0: */ michael@0: #ifdef __Panda__ michael@0: pakhandle_type pak_to_read; michael@0: pakhandle_type pak_to_read_sendq; michael@0: #endif michael@0: struct mbuf *pkt, *pkt_last; michael@0: struct mbuf *control; michael@0: #if !(defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__)) michael@0: #ifndef INP_IPV6 michael@0: #define INP_IPV6 0x1 michael@0: #endif michael@0: #ifndef INP_IPV4 michael@0: #define INP_IPV4 0x2 michael@0: #endif michael@0: uint8_t inp_vflag; michael@0: /* TODO __Userspace__ where is our inp_vlag going to be? */ michael@0: uint8_t inp_ip_ttl; michael@0: uint8_t inp_ip_tos; /* defined as macro in user_inpcb.h */ michael@0: uint8_t inp_ip_resv; michael@0: #endif michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 503000 michael@0: struct mtx inp_mtx; michael@0: struct mtx inp_create_mtx; michael@0: struct mtx inp_rdata_mtx; michael@0: int32_t refcount; michael@0: #elif defined(SCTP_PROCESS_LEVEL_LOCKS) michael@0: userland_mutex_t inp_mtx; michael@0: userland_mutex_t inp_create_mtx; michael@0: userland_mutex_t inp_rdata_mtx; michael@0: int32_t refcount; michael@0: #elif defined(__APPLE__) michael@0: #if defined(SCTP_APPLE_RWLOCK) michael@0: lck_rw_t *inp_mtx; michael@0: #else michael@0: lck_mtx_t *inp_mtx; michael@0: #endif michael@0: lck_mtx_t *inp_create_mtx; michael@0: lck_mtx_t *inp_rdata_mtx; michael@0: #elif defined(__Windows__) michael@0: struct rwlock inp_lock; michael@0: struct spinlock inp_create_lock; michael@0: struct spinlock inp_rdata_lock; michael@0: int32_t refcount; michael@0: #elif defined(__Userspace__) michael@0: /* TODO decide on __Userspace__ locks */ michael@0: int32_t refcount; michael@0: #endif michael@0: #if defined(__APPLE__) michael@0: int32_t refcount; michael@0: michael@0: uint32_t lock_caller1; michael@0: uint32_t lock_caller2; michael@0: uint32_t lock_caller3; michael@0: uint32_t unlock_caller1; michael@0: uint32_t unlock_caller2; michael@0: uint32_t unlock_caller3; michael@0: uint32_t getlock_caller1; michael@0: uint32_t getlock_caller2; michael@0: uint32_t getlock_caller3; michael@0: uint32_t gen_count; michael@0: uint32_t lock_gen_count; michael@0: uint32_t unlock_gen_count; michael@0: uint32_t getlock_gen_count; michael@0: michael@0: uint32_t i_am_here_file; michael@0: uint32_t i_am_here_line; michael@0: #endif michael@0: uint32_t def_vrf_id; michael@0: #ifdef SCTP_MVRF michael@0: uint32_t *m_vrf_ids; michael@0: uint32_t num_vrfs; michael@0: uint32_t vrf_size; michael@0: #endif michael@0: uint32_t total_sends; michael@0: uint32_t total_recvs; michael@0: uint32_t last_abort_code; michael@0: uint32_t total_nospaces; michael@0: struct sctpasochead *sctp_asocidhash; michael@0: u_long hashasocidmark; michael@0: uint32_t sctp_associd_counter; michael@0: michael@0: #ifdef SCTP_ASOCLOG_OF_TSNS michael@0: struct sctp_pcbtsn_rlog readlog[SCTP_READ_LOG_SIZE]; michael@0: uint32_t readlog_index; michael@0: #endif michael@0: #if defined(__Userspace__) michael@0: void *ulp_info; michael@0: int (*recv_callback)(struct socket *, union sctp_sockstore, void *, size_t, michael@0: struct sctp_rcvinfo, int, void *); michael@0: uint32_t send_sb_threshold; michael@0: int (*send_callback)(struct socket *, uint32_t); michael@0: #endif michael@0: }; michael@0: michael@0: #if defined(__Userspace__) michael@0: int register_recv_cb (struct socket *, michael@0: int (*)(struct socket *, union sctp_sockstore, void *, size_t, michael@0: struct sctp_rcvinfo, int, void *)); michael@0: int register_send_cb (struct socket *, uint32_t, int (*)(struct socket *, uint32_t)); michael@0: int register_ulp_info (struct socket *, void *); michael@0: michael@0: #endif michael@0: struct sctp_tcb { michael@0: struct socket *sctp_socket; /* back pointer to socket */ michael@0: struct sctp_inpcb *sctp_ep; /* back pointer to ep */ michael@0: LIST_ENTRY(sctp_tcb) sctp_tcbhash; /* next link in hash michael@0: * table */ michael@0: LIST_ENTRY(sctp_tcb) sctp_tcblist; /* list of all of the michael@0: * TCB's */ michael@0: LIST_ENTRY(sctp_tcb) sctp_tcbasocidhash; /* next link in asocid michael@0: * hash table michael@0: */ michael@0: LIST_ENTRY(sctp_tcb) sctp_asocs; /* vtag hash list */ michael@0: struct sctp_block_entry *block_entry; /* pointer locked by socket michael@0: * send buffer */ michael@0: struct sctp_association asoc; michael@0: /*- michael@0: * freed_by_sorcv_sincelast is protected by the sockbuf_lock NOT the michael@0: * tcb_lock. Its special in this way to help avoid extra mutex calls michael@0: * in the reading of data. michael@0: */ michael@0: uint32_t freed_by_sorcv_sincelast; michael@0: uint32_t total_sends; michael@0: uint32_t total_recvs; michael@0: int freed_from_where; michael@0: uint16_t rport; /* remote port in network format */ michael@0: uint16_t resv; michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 503000 michael@0: struct mtx tcb_mtx; michael@0: struct mtx tcb_send_mtx; michael@0: #elif defined(SCTP_PROCESS_LEVEL_LOCKS) michael@0: userland_mutex_t tcb_mtx; michael@0: userland_mutex_t tcb_send_mtx; michael@0: #elif defined(__APPLE__) michael@0: lck_mtx_t* tcb_mtx; michael@0: lck_mtx_t* tcb_send_mtx; michael@0: #elif defined(__Windows__) michael@0: struct spinlock tcb_lock; michael@0: struct spinlock tcb_send_lock; michael@0: #elif defined(__Userspace__) michael@0: /* TODO decide on __Userspace__ locks */ michael@0: #endif michael@0: #if defined(__APPLE__) michael@0: uint32_t caller1; michael@0: uint32_t caller2; michael@0: uint32_t caller3; michael@0: #endif michael@0: }; michael@0: michael@0: michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 503000 michael@0: michael@0: #include michael@0: michael@0: #elif defined(__APPLE__) michael@0: /* michael@0: * Apple MacOS X 10.4 "Tiger" michael@0: */ michael@0: michael@0: #include michael@0: michael@0: #elif defined(SCTP_PROCESS_LEVEL_LOCKS) michael@0: michael@0: #include michael@0: michael@0: #elif defined(__Windows__) michael@0: michael@0: #include michael@0: michael@0: #elif defined(__Userspace__) michael@0: michael@0: #include michael@0: michael@0: #else michael@0: /* michael@0: * Pre-5.x FreeBSD, and others. michael@0: */ michael@0: #include michael@0: #endif michael@0: michael@0: /* TODO where to put non-_KERNEL things for __Userspace__? */ michael@0: #if defined(_KERNEL) || defined(__Userspace__) michael@0: michael@0: /* Attention Julian, this is the extern that michael@0: * goes with the base info. sctp_pcb.c has michael@0: * the real definition. michael@0: */ michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 801000 michael@0: VNET_DECLARE(struct sctp_base_info, system_base_info) ; michael@0: #else michael@0: extern struct sctp_base_info system_base_info; michael@0: #endif michael@0: michael@0: #ifdef INET6 michael@0: int SCTP6_ARE_ADDR_EQUAL(struct sockaddr_in6 *a, struct sockaddr_in6 *b); michael@0: #endif michael@0: michael@0: void sctp_fill_pcbinfo(struct sctp_pcbinfo *); michael@0: michael@0: struct sctp_ifn * michael@0: sctp_find_ifn(void *ifn, uint32_t ifn_index); michael@0: michael@0: struct sctp_vrf *sctp_allocate_vrf(int vrfid); michael@0: struct sctp_vrf *sctp_find_vrf(uint32_t vrfid); michael@0: void sctp_free_vrf(struct sctp_vrf *vrf); michael@0: michael@0: /*- michael@0: * Change address state, can be used if michael@0: * O/S supports telling transports about michael@0: * changes to IFA/IFN's (link layer triggers). michael@0: * If a ifn goes down, we will do src-addr-selection michael@0: * and NOT use that, as a source address. This does michael@0: * not stop the routing system from routing out michael@0: * that interface, but we won't put it as a source. michael@0: */ michael@0: void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); michael@0: void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index); michael@0: michael@0: struct sctp_ifa * michael@0: sctp_add_addr_to_vrf(uint32_t vrfid, michael@0: void *ifn, uint32_t ifn_index, uint32_t ifn_type, michael@0: const char *if_name, michael@0: void *ifa, struct sockaddr *addr, uint32_t ifa_flags, michael@0: int dynamic_add); michael@0: michael@0: void sctp_update_ifn_mtu(uint32_t ifn_index, uint32_t mtu); michael@0: michael@0: void sctp_free_ifn(struct sctp_ifn *sctp_ifnp); michael@0: void sctp_free_ifa(struct sctp_ifa *sctp_ifap); michael@0: michael@0: michael@0: void sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr, michael@0: uint32_t ifn_index, const char *if_name); michael@0: michael@0: michael@0: michael@0: struct sctp_nets *sctp_findnet(struct sctp_tcb *, struct sockaddr *); michael@0: michael@0: struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int, int, uint32_t); michael@0: michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 michael@0: int sctp_inpcb_bind(struct socket *, struct sockaddr *, michael@0: struct sctp_ifa *,struct thread *); michael@0: #elif defined(__Windows__) michael@0: int sctp_inpcb_bind(struct socket *, struct sockaddr *, michael@0: struct sctp_ifa *,PKTHREAD); michael@0: #else michael@0: /* struct proc is a dummy for __Userspace__ */ michael@0: int sctp_inpcb_bind(struct socket *, struct sockaddr *, michael@0: struct sctp_ifa *, struct proc *); michael@0: #endif michael@0: michael@0: struct sctp_tcb * michael@0: sctp_findassociation_addr(struct mbuf *, int, michael@0: struct sockaddr *, struct sockaddr *, michael@0: struct sctphdr *, struct sctp_chunkhdr *, struct sctp_inpcb **, michael@0: struct sctp_nets **, uint32_t vrf_id); michael@0: michael@0: struct sctp_tcb * michael@0: sctp_findassociation_addr_sa(struct sockaddr *, michael@0: struct sockaddr *, struct sctp_inpcb **, struct sctp_nets **, int, uint32_t); michael@0: michael@0: void michael@0: sctp_move_pcb_and_assoc(struct sctp_inpcb *, struct sctp_inpcb *, michael@0: struct sctp_tcb *); michael@0: michael@0: /*- michael@0: * For this call ep_addr, the to is the destination endpoint address of the michael@0: * peer (relative to outbound). The from field is only used if the TCP model michael@0: * is enabled and helps distingush amongst the subset bound (non-boundall). michael@0: * The TCP model MAY change the actual ep field, this is why it is passed. michael@0: */ michael@0: struct sctp_tcb * michael@0: sctp_findassociation_ep_addr(struct sctp_inpcb **, michael@0: struct sockaddr *, struct sctp_nets **, struct sockaddr *, michael@0: struct sctp_tcb *); michael@0: michael@0: struct sctp_tcb * michael@0: sctp_findasoc_ep_asocid_locked(struct sctp_inpcb *inp, sctp_assoc_t asoc_id, int want_lock); michael@0: michael@0: struct sctp_tcb * michael@0: sctp_findassociation_ep_asocid(struct sctp_inpcb *, michael@0: sctp_assoc_t, int); michael@0: michael@0: struct sctp_tcb * michael@0: sctp_findassociation_ep_asconf(struct mbuf *, int, struct sockaddr *, michael@0: struct sctphdr *, struct sctp_inpcb **, struct sctp_nets **, uint32_t vrf_id); michael@0: michael@0: int sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id); michael@0: michael@0: int sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id); michael@0: michael@0: void sctp_inpcb_free(struct sctp_inpcb *, int, int); michael@0: michael@0: #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 michael@0: struct sctp_tcb * michael@0: sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, michael@0: int *, uint32_t, uint32_t, struct thread *); michael@0: #elif defined(__Windows__) michael@0: struct sctp_tcb * michael@0: sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, michael@0: int *, uint32_t, uint32_t, PKTHREAD); michael@0: #else michael@0: /* proc will be NULL for __Userspace__ */ michael@0: struct sctp_tcb * michael@0: sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *, michael@0: int *, uint32_t, uint32_t, struct proc *); michael@0: #endif michael@0: michael@0: int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int); michael@0: michael@0: michael@0: void sctp_delete_from_timewait(uint32_t, uint16_t, uint16_t); michael@0: michael@0: int sctp_is_in_timewait(uint32_t tag, uint16_t lport, uint16_t rport); michael@0: michael@0: void michael@0: sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t rport); michael@0: michael@0: void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t); michael@0: michael@0: int sctp_insert_laddr(struct sctpladdr *, struct sctp_ifa *, uint32_t); michael@0: michael@0: void sctp_remove_laddr(struct sctp_laddr *); michael@0: michael@0: void sctp_del_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *); michael@0: michael@0: int sctp_add_remote_addr(struct sctp_tcb *, struct sockaddr *, struct sctp_nets **, int, int); michael@0: michael@0: void sctp_remove_net(struct sctp_tcb *, struct sctp_nets *); michael@0: michael@0: int sctp_del_remote_addr(struct sctp_tcb *, struct sockaddr *); michael@0: michael@0: void sctp_pcb_init(void); michael@0: michael@0: void sctp_pcb_finish(void); michael@0: michael@0: void sctp_add_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); michael@0: void sctp_del_local_addr_restricted(struct sctp_tcb *, struct sctp_ifa *); michael@0: michael@0: int michael@0: sctp_load_addresses_from_init(struct sctp_tcb *, struct mbuf *, int, int, michael@0: struct sockaddr *, struct sockaddr *, struct sockaddr *); michael@0: michael@0: int michael@0: sctp_set_primary_addr(struct sctp_tcb *, struct sockaddr *, michael@0: struct sctp_nets *); michael@0: michael@0: int sctp_is_vtag_good(uint32_t, uint16_t lport, uint16_t rport, struct timeval *); michael@0: michael@0: /* void sctp_drain(void); */ michael@0: michael@0: int sctp_destination_is_reachable(struct sctp_tcb *, struct sockaddr *); michael@0: michael@0: int sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp); michael@0: michael@0: /*- michael@0: * Null in last arg inpcb indicate run on ALL ep's. Specific inp in last arg michael@0: * indicates run on ONLY assoc's of the specified endpoint. michael@0: */ michael@0: int michael@0: sctp_initiate_iterator(inp_func inpf, michael@0: asoc_func af, michael@0: inp_func inpe, michael@0: uint32_t, uint32_t, michael@0: uint32_t, void *, michael@0: uint32_t, michael@0: end_func ef, michael@0: struct sctp_inpcb *, michael@0: uint8_t co_off); michael@0: #if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP) michael@0: void michael@0: sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use); michael@0: michael@0: #endif michael@0: michael@0: #ifdef INVARIANTS michael@0: void michael@0: sctp_validate_no_locks(struct sctp_inpcb *inp); michael@0: #endif michael@0: michael@0: #endif /* _KERNEL */ michael@0: #endif /* !__sctp_pcb_h__ */