/* ipsctp_h.h - IPNET SCTP header template file */ /* * Copyright (c) 2007 Wind River Systems, Inc. * * The right to copy, distribute or otherwise make use of this software * may be licensed only pursuant to the terms of an applicable Wind River * license agreement. No license to Wind River intellectual property rights * is granted herein. All rights not licensed by Wind River are reserved * by Wind River. */ /* modification history -------------------- */ #ifndef IPSCTP_H_H #define IPSCTP_H_H /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* IPSCTP private definitions */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipsctp_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPNET #include #include #endif #ifdef _WRS_KERNEL #include #endif #ifdef IPCOM_USE_BITARRAY #include #endif #include #include #include #include #include "ipsctp_pkt.h" #include "ipsctp_hash.h" #ifdef IPMCRYPTO #include #else #include #endif #ifdef __cplusplus extern "C" { #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #ifdef IPCOM_SYSLOG_PRIORITY #undef IPCOM_SYSLOG_PRIORITY #endif #define IPCOM_SYSLOG_PRIORITY IPSCTP_SYSLOG_PRIORITY #ifdef IPCOM_SYSLOG_FACILITY #undef IPCOM_SYSLOG_FACILITY #endif #define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPSCTP /* *=========================================================================== * DEBUG/ASSERT *=========================================================================== */ #ifdef IPSCTP_DEBUG #define IPSCTP_DEBUG_LINE(x) x #else #define IPSCTP_DEBUG_LINE(x) IP_NOOP #endif /* IPSCTP_DEBUG */ #define IPSCTP_DBG_STATE 0x00000001 #define IPSCTP_DBG_TIMER 0x00000002 #define IPSCTP_DBG_INPUT 0x00000004 #define IPSCTP_DBG_OUTPUT 0x00000008 #define IPSCTP_DBG_SOCK 0x00000010 #define IPSCTP_DBG_PKT 0x00000020 #define IPSCTP_DBG_CC 0x00000040 #define IPSCTP_DBG_RWND 0x00000080 #define IPSCTP_DBG_PATH 0x00000100 #define IPSCTP_DBG_MTU 0x00000200 #define IPSCTP_DBG_BUF 0x00000400 #define IPSCTP_DBG_ALL 0xFFFFFFFF #ifdef IPSCTP_DEBUG extern IP_PUBLIC Ip_u32 ipsctp_debug_flags; #define IPSCTP_DBG0(flag, fm) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG0(DEBUG, fm); \ } \ } while(0) #define IPSCTP_DBG1(flag, fm, a) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG1(DEBUG, (fm), (a)); \ } \ } while(0) #define IPSCTP_DBG2(flag, fm, a, b) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG2(DEBUG, fm, a, b); \ } \ } while(0) #define IPSCTP_DBG3(flag, fm, a, b, c) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG3(DEBUG, fm, a, b, c); \ } \ } while(0) #define IPSCTP_DBG4(flag, fm, a, b, c, d) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG4(DEBUG, fm, a, b, c, d); \ } \ } while(0) #define IPSCTP_DBG5(flag, fm, a, b, c, d, e) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG5(DEBUG, fm, a, b, c, d, e); \ } \ } while(0) #define IPSCTP_DBG6(flag, fm, a, b, c, d, e, f) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG6(DEBUG, fm, a, b, c, d, e, f); \ } \ } while(0) #define IPSCTP_DBG7(flag, fm, a, b, c, d, e, f, g) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG7(DEBUG, fm, a, b, c, d, e, f, g); \ } \ } while(0) #define IPSCTP_DBG8(flag, fm, a, b, c, d, e, f, g, h) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG8(DEBUG, fm, a, b, c, d, e, f, g, h); \ } \ } while(0) #define IPSCTP_DBG9(flag, fm, a, b, c, d, e, f, g, h, i) \ do \ { \ if ((ipsctp_debug_flags & flag) == flag) \ { \ IPCOM_LOG9(DEBUG, fm, a, b, c, d, e, f, g, h, i); \ } \ } while(0) #else /* !IPSCTP_DEBUG */ #define IPSCTP_DBG0(flag, fm) IP_NOOP #define IPSCTP_DBG1(flag, fm, a) IP_NOOP #define IPSCTP_DBG2(flag, fm, a, b) IP_NOOP #define IPSCTP_DBG3(flag, fm, a, b, c) IP_NOOP #define IPSCTP_DBG4(flag, fm, a, b, c, d) IP_NOOP #define IPSCTP_DBG5(flag, fm, a, b, c, d, e) IP_NOOP #define IPSCTP_DBG6(flag, fm, a, b, c, d, e, f) IP_NOOP #define IPSCTP_DBG7(flag, fm, a, b, c, d, e, f, g) IP_NOOP #define IPSCTP_DBG8(flag, fm, a, b, c, d, e, f, g, h) IP_NOOP #define IPSCTP_DBG9(flag, fm, a, b, c, d, e, f, g, h, i ) IP_NOOP #endif /* Stack specific types */ #ifdef IPNET #ifndef IP_STACK #define IP_STACK(x) ipnet_ ## x #endif #ifndef IP_STACK_CONST #define IP_STACK_CONST(x) IPNET_ ## x #endif #ifndef ipstack #define ipstack ipnet #endif #elif defined(IPLITE) #ifndef IP_STACK #define IP_STACK(x) iplite_ ## x #endif #ifndef IP_STACK_CONST #define IP_STACK_CONST(x) IPLITE_ ## x #endif #ifndef ipstack #define ipstack (&iplite) #endif #ifndef iplite_conf_max_sockets #define iplite_conf_max_sockets IPLITE_CONF_MAX_SOCKETS #endif #else #error "IPNET or IPLITE must be defined" #endif /* NOTE : Ipcom_list next pointer must be the first place in your structure */ #define ipsctp_list_for_each(head, cur, TYPE) \ for ((cur) = (TYPE *)ipcom_list_first(head); \ IP_NULL != (cur); \ (cur) = (TYPE *)ipcom_list_next((Ipcom_list *)(cur))) /* differ with Ipsctp_list_for_each for you can delete element in this loop */ #define ipsctp_list_for_each_safe(head, cur, tmp, TYPE) \ for ((cur) = (TYPE *)ipcom_list_first(head), ((cur) ? (tmp) = (TYPE *)ipcom_list_next((Ipcom_list *)(cur)) : IP_NULL); \ IP_NULL != (cur); \ (cur) = (tmp), ((cur) ? (tmp) = (TYPE *)ipcom_list_next((Ipcom_list *)(cur)) : IP_NULL)) /* differ with Ipsctp_list_for_each for you can delete element in this loop */ #define ipsctp_list_for_current_each_safe(cur, tmp, TYPE) \ for (((cur) ? (tmp) = (TYPE *)ipcom_list_next((Ipcom_list *)(cur)) : IP_NULL); \ IP_NULL != (cur); \ (cur) = (tmp), ((cur) ? (tmp) = (TYPE *)ipcom_list_next((Ipcom_list *)(cur)) : IP_NULL)) #define Ipsctp_vtag Ip_u32 /* SCTP constants */ /* End-of-file marker */ /*#define IPSCTP_EOF (-1)*/ #define IPSCTP_MAX_STREAMS 2048 #define IPSCTP_MAX_DUP_TSNS 20 #define IPSCTP_LARGEST_INIT_ACCEPTED (65535 - 2048) #define IPSCTP_INITIAL_TSN_BITMAP_SIZE 16 #define IPSCTP_MINIMAL_RWND 4960 #define IPSCTP_MIN_RWND 1500 #define IPSCTP_MAX_TSN 0xffffffff #define IPSCTP_ADDR_IS_CONFIRMED 1 #define IPSCTP_INITIAL_CWND 4380 #define IPSCTP_MAX_TSN_BITMAP_SIZE 512 #define IPSCTP_TSN_BITMAP_INCR 32 #define IPSCTP_GET_TSN_BITMAP_SIZE_NEXT(oldsize, gap) \ ((oldsize)*2 > ((gap + 7)/8 + IPSCTP_TSN_BITMAP_INCR))?((oldsize)*2):((gap + 7)/8 + IPSCTP_TSN_BITMAP_INCR) /* silly window syndrome */ #define IPSCTP_SWS_SENDER_DEF 1420 #define IPSCTP_SWS_RECEIVER_DEF 3000 #define ipsctp_memzero(buf, size) (void)ipcom_memset((void *)(buf), 0 , (size)) typedef enum Ipsctp_notify_type_enum { SCTP_NOTIFY_NONE = 0, SCTP_NOTIFY_ASSOC_UP = 1, SCTP_NOTIFY_ASSOC_DOWN = 2, SCTP_NOTIFY_INTERFACE_DOWN = 3, SCTP_NOTIFY_INTERFACE_UP = 4, SCTP_NOTIFY_SEND_FAIL = 5, SCTP_NOTIFY_ASSOC_ABORTED = 6, SCTP_NOTIFY_ASSOC_RESTART = 7, SCTP_NOTIFY_PEER_SHUTDOWN = 8, SCTP_NOTIFY_INTERFACE_CONFIRMED = 9, SCTP_NOTIFY_REMOTE_ERROR = 10, SCTP_NOTIFY_MAX = 11 } Ipsctp_notify_type; #define IPSCTP_INVALID_NOTIFY_ERR 0xffffffff #define IPSCTP_INVALID_LINGER_TIME 0xffffffff #define ipsctp_sock_state(sock, state) \ IP_BIT_ISSET(sock->sctp_inst->inst_flags, IPSCTP_SOCKET_##state) #define ipsctp_list_size(list_head) ((list_head)->head->size) #define ipsctp_check_hdr_len(stru, ch_hdr) (sizeof(stru) != ip_ntohs((ch_hdr)->length)) #define IPSCTP_GET_ASSOCID(tcb) ((tcb)->my_vtag) /* Socket Event Options for sctp_event_subscribe */ #define IPSCTP_EVNT_FLAGS_DATA_IO (1u << 1) #define IPSCTP_EVNT_FLAGS_ASSOCIATION (1u << 2) #define IPSCTP_EVNT_FLAGS_ADDRESS (1u << 3) #define IPSCTP_EVNT_FLAGS_SEND_FAILURE (1u << 4) #define IPSCTP_EVNT_FLAGS_PEER_ERROR (1u << 5) #define IPSCTP_EVNT_FLAGS_SHUTDOWN (1u << 6) #define IPSCTP_EVNT_FLAGS_PARTIAL_DELIVERY (1u << 7) #define IPSCTP_EVNT_FLAGS_ADAPTATION_LAYER (1u << 8) #define IPSCTP_EVNT_FLAGS_AUTHENTICATION (1u << 9) #define IPSCTP_INST_FLAG_HB_DISABLED (1u << 10) #define IPSCTP_INST_FLAG_EXPLICIT_EOR (1u << 11) #define IPSCTP_INST_FLAG_FRAG_INTERLEAVE (1u << 12) #define IPSCTP_INST_FLAG_INTERLEAVE_STRMS (1u << 13) #define IPSCTP_INST_FLAG_EXT_RCVINFO (1u << 14) #define IPSCTP_INST_FLAG_WANT_MAPPED_V4 (1u << 15) #define IPSCTP_INST_FLAGS_NO_FRAGMENT (1u << 16) #define IPSCTP_INST_FLAGS_NODELAY (1u << 17) /* Socket stack specific defines */ #ifdef IPNET #define IPSCTP_STACK_BIND(s, n, l, r) (s)->ops->bind(s, n, l, r) #define IPSCTP_SOCK_VR(s) ((s)->vr_index) #define IPSCTP_SOCK_TYPE(sk) ((sk)->ipcom.type) #define IPSCTP_SOCK_DOMAIN(sk) ((sk)->ipcom.domain) #define IPSCTP_IS_SOCK_TYPE(sk, type) (type == ((sk)->ipcom.type)) #else /* IPLITE */ #define IPSCTP_STACK_BIND(s, n, l, r) iplite_do_bind(s, n, l, r) #define IPSCTP_SOCK_VR(s) 0 #endif /* socket other MACROS */ #define IPSCTP_SIZE_LADDR_ENTRY (sizeof(Ipsctp_laddr_entry)) #define IPSCTP_SIZE_TCB_ENTRY (sizeof(Ipsctp_tcb)) #define IPSCTP_SIZE_LADDR (sizeof(Ipsctp_addr)) #define IPSCTP_SIZE_TCB (sizeof(Ipsctp_tcb)) #define IPSCTP_SIZE_SNDRCVINFO (sizeof(Ipsctp_sctp_sndrcvinfo)) /* SCTP tcb control flags */ #define IPSCTP_TCBC_FLAG_ASSOC_UP_SENT (1 << 0) /* */ #define IPSCTP_TCBC_FLAG_ASSOC_RESTART (1 << 1) /* */ #define IPSCTP_TCBC_FLAG_SAW_GAP_SACK (1 << 2) /* Is previous ack gap? used to revoke the sack */ #define IPSCTP_TCBC_FLAG_HAD_ENOBUF (1 << 3) #define IPSCTP_TCBC_FLAG_DELAY_CONNECT (1 << 4) /* delayed connection flag */ #define IPSCTP_TCBC_FLAG_HB_DISABLED (1 << 5) /* heartbeat disabled */ #define IPSCTP_TCBC_FLAG_NEED_SEND_ACK (1 << 6) /* whether it is in partial delivery? */ #define IPSCTP_TCBC_FLAG_LISTEN (1 << 7) /* This is a dummy TCB for listening socket */ #define IPSCTP_TCBC_FLAG_DACK_PENDING (1 << 8) /* delay ack timer is running */ #define IPSCTP_TCBC_FLAG_HB_PENDING (1 << 9) /* heartbeat timer is running */ #define IPSCTP_TCBC_FLAG_FAST_RECOVERY (1 << 10) /* RFC2582 fast recovery */ #define IPSCTP_TCBC_FLAG_SAT_T3_LOSS_RECOVERY (1 << 11) /* set this flag in t3 timer */ #define IPSCTP_TCBC_FLAG_IPV4_ALLOW (1 << 12) /* allow bound ipv4 address */ #define IPSCTP_TCBC_FLAG_IPV6_ALLOW (1 << 13) /* allow bound ipv6 address */ #define IPSCTP_TCBC_FLAG_SCOPE_V6LOCAL (1 << 14) /* ipv6 local address */ #define IPSCTP_TCBC_FLAG_SCOPE_V6SITE (1 << 15) /* ipv6 site address */ #define IPSCTP_TCBC_FLAG_SCOPE_V4LOCAL (1 << 16) /* ipv4 private address */ #define IPSCTP_TCBC_FLAG_SCOPE_V4LOOPBACK (1 << 17) /* ipv4 loopback address */ #define IPSCTP_TCBC_FLAG_CONNECTING (1 << 18) /* TCB is connecting */ #define IPSCTP_TCBC_FLAG_CONNECTED (1 << 19) /* TCB is connected */ #define IPSCTP_TCBC_FLAG_ABORT (1 << 20) /* TCB has aborted */ #define IPSCTP_IS_LISTEN_INSTANCE(inst) (IP_BIT_ISSET((inst)->inst_flags, IPSCTP_SOCKET_LISTENING)) #define IPSCTP_IS_LISTEN_TCB(tcb) (IP_BIT_ISSET((tcb)->tcb_flags, IPSCTP_TCBC_FLAG_LISTEN)) #define IPSCTP_GET_STATE(tcb) (tcb)->state #define IPSCTP_SET_STATE(tcb, tcb_state) (tcb)->state = tcb_state #if 0 #define IPSCTP_ZERO_SUB(a,b) (((a) > (b)) ? ((a) - (b)) : 0) #else #define IPSCTP_UNSIGNED_SUB(a,b) (((a) > (b)) ? ((a) - (b)) : 0) #define IPSCTP_ZERO_SUB(a,b) (((a) >= (b)) ? ((a) - (b))\ : (ipsctp_log3int(IPCOM_LOG_ERR, 0, "FILE "__FILE__" LINE %d IPSCTP_ZERO_SUB abnormal a %u b %u\n",\ __LINE__, a, b)\ ,0)) #endif #if 0 #define IPSCTP_ATOMIC_ZERO_SUB(a,b)\ ((ipcom_atomic_get((Ipcom_atomic_t *)&a) > (b)) ? \ ipcom_atomic_sub((Ipcom_atomic_t *)&a,(b))\ : ipcom_atomic_set((Ipcom_atomic_t *)&a, 0)) #else #define IPSCTP_ATOMIC_ZERO_SUB(a,b)\ ((ipcom_atomic_get((Ipcom_atomic_t *)&a) >= (b)) ? \ ipcom_atomic_sub((Ipcom_atomic_t *)&a,(b))\ : ((void)ipsctp_log3int(IPCOM_LOG_ERR, 0, "FILE "__FILE__" LINE %d IPSCTP_ATOMIC_ZERO_SUB abnormal a %d b %d\n",\ __LINE__, ipcom_atomic_get((Ipcom_atomic_t *)&a),b)\ ,ipcom_atomic_set((Ipcom_atomic_t *)&a, 0))) #endif #if 0 #define IPSCTP_ZERO_SUB_ASSIGN(a,b) ((a) = (((a) > (b)) ? ((a) - (b)) : 0)) #else #define IPSCTP_ZERO_SUB_ASSIGN(a,b) ((a) = (((a) >= (b)) ? ((a) - (b))\ : (ipsctp_log3int(IPCOM_LOG_ERR, 0, "FILE "__FILE__" LINE %d IPSCTP_ZERO_SUB_ASSIGN abnormal a %d b %d\n",\ __LINE__, a, b)\ ,0))) #define IPSCTP_UNSIGNED_SUB_ASSIGN(a,b) ((a) = (((a) >= (b)) ? ((a) - (b)) : 0)) #endif #define IPSCTP_TSN_SUB(a, b) (((a) > (b)) ? ((a) - (b)) : (IPSCTP_MAX_TSN - (b) + (a) + 1)) #define IPSCTP_IS_GT_16(s1, s2) ((Ip_s16) ((s1) - (s2)) > 0) #define IPSCTP_IS_GEQ_16(s1, s2) ((Ip_s16) ((s1) - (s2)) >= 0) #define IPSCTP_IS_LT_16(s1, s2) ((Ip_s16) ((s1) - (s2)) < 0) #define IPSCTP_IS_LEQ_16(s1, s2) ((Ip_s16) ((s1) - (s2)) <= 0) #define ipsctp_copy_to_user(sock,s1,s2,n) ( IPCOM_UNUSED_ARG(sock), ipcom_copy_to_user(s1,s2,n) ) #define ipsctp_copy_from_user(sock,s1,s2,n) ( IPCOM_UNUSED_ARG(sock), ipcom_copy_from_user(s1,s2,n) ) #define IPSCTP_DATA_LEN_ALIGN(len) (((len) + 3) & ~0x3) /* SCTP tcb peer control flags */ #define IPSCTP_TCBC_FLAG_SUPPORT_PKT_DROP (1 << 0) /* support packet drop draft */ #define IPSCTP_TCBC_FLAG_SUPPORT_STREAM_RESET (1 << 0) /* support stream reset draft */ #define IPSCTP_TCBC_FLAG_SUPPORT_AUTH (1 << 0) /* support auth rfc */ #define IPSCTP_TCBC_FLAG_SUPPORT_PRSCTP (1 << 0) /* support prsctp */ #define IPSCTP_TCBC_FLAG_SUPPORT_ASCONF (1 << 0) /* support acconf */ /* SCTP chunk control flag, for receive or send status of chunks */ /* the lower 4 bits store the chunk send state, like IPSCTP_CHUNK_FLAG_SEND_STATE_XXX */ #define IPSCTP_CHUNK_FLAG_SEND_STATE_UNSENT 0 #define IPSCTP_CHUNK_FLAG_SEND_STATE_SENT 1 #define IPSCTP_CHUNK_FLAG_SEND_STATE_RESEND 4 #define IPSCTP_CHUNK_FLAG_SEND_STATE_ACKED 5 /* has been acked */ #define IPSCTP_CHUNK_FLAG_SEND_STATE_MARKED 6 /* SACKED by SACK GAP in current SACK chunk */ #define IPSCTP_CHUNK_FLAG_GET_SEND_STATE(flag) ((flag) & 0x000f) #define IPSCTP_CHUNK_FLAG_SET_SEND_STATE(flag, state) ((flag) = ((flag) & 0xfff0) | ((state) & 0x0f)) #define IPSCTP_CHUNK_FLAG_INC_SEND_STATE(flag) ((flag) = ((flag) & 0xfff0) | ((((flag) & 0x0f) + 1) & 0x0f)) #define IPSCTP_CHUNK_FLAG_SEND (1 << 4) /* chunks in receive queue */ #define IPSCTP_CHUNK_FLAG_SEND_REVOKED (1 << 5) /* this chunk was revoked */ #define IPSCTP_CHUNK_FLAG_SEND_DO_RTT (1 << 6) /* this chunk will do rtt */ #define IPSCTP_CHUNK_FLAG_SEND_DO_FR (1 << 7) /* this chunk is doing fast retransmitting */ #define IPSCTP_CHUNK_FLAG_SEND_END (1 << 8) /* The (E)nding fragment bit, if set, indicates the last fragment of a user message.*/ #define IPSCTP_CHUNK_FLAG_SEND_BEGIN (1 << 9) /* The (B)eginning fragment bit, if set, indicates the first fragment of a user message. */ #define IPSCTP_CHUNK_FLAG_SEND_WIN_PROBE (1 << 10) /* this chunk is doing window probe */ #define IPSCTP_CHUNK_FLAG_SEND_ND_ADJUST (1 << 11) /* The Start and End position should be adjust * for retransmission. */ #define IPSCTP_CHUNK_FLAG_RECV (1 << 4) /* chunks in send queue */ #define IPSCTP_CHUNK_FLAG_RECV_FRAGMENT (1 << 5) /* the fragment flag in socket receive buffer * or input stream queue */ #define IPSCTP_CHUNK_FLAG_USR_RECV_IN (1 << 6) /* in the process of user receiving */ #define IPSCTP_CHUNK_FLAG_RECV_FIN (1 << 7) /* the whole chunk has been delivered to * socket receive buffer or input stream queue completely. * For fragmented chunk, this flag means all chunk fragments * are received; for unfragmented chunk, this flag is not * applicable. */ #define IPSCTP_CHUNK_FLAG_RECV_NOTIFICATION (1 << 8) #define IPSCTP_IS_FIRST_FRAGMENT(chunk) \ ((((chunk)->sndrcv_info.sinfo_flags >> 8) & IPSCTP_FLAG_DATA_FRAG_MASK) == IPSCTP_FLAG_DATA_FIRST_FRAG) #define IPSCTP_IS_MIDDLE_FRAGMENT(chunk) \ ((((chunk)->sndrcv_info.sinfo_flags >> 8) & IPSCTP_FLAG_DATA_FRAG_MASK) == IPSCTP_FLAG_DATA_MIDDLE_FRAG) #define IPSCTP_IS_LAST_FRAGMENT(chunk) \ ((((chunk)->sndrcv_info.sinfo_flags >> 8) & IPSCTP_FLAG_DATA_FRAG_MASK) == IPSCTP_FLAG_DATA_LAST_FRAG) #if 0 /* defined in ipsctp_pkt.h*/ /* * SCTP error cause, RFC4960 */ #define IPSCTP_CAUSE_NO_ERROR 0x0000 #define IPSCTP_CAUSE_INVALID_STREAM 0x0001 #define IPSCTP_CAUSE_MISSING_PARAM 0x0002 #define IPSCTP_CAUSE_STALE_COOKIE 0x0003 #define IPSCTP_CAUSE_OUT_OF_RESC 0x0004 #define IPSCTP_CAUSE_UNRESOLVABLE_ADDR 0x0005 #define IPSCTP_CAUSE_UNRECOG_CHUNK 0x0006 #define IPSCTP_CAUSE_INVALID_PARAM 0x0007 #define IPSCTP_CAUSE_UNRECOG_PARAM 0x0008 #define IPSCTP_CAUSE_NO_USER_DATA 0x0009 #define IPSCTP_CAUSE_COOKIE_IN_SHUTDOWN 0x000a #define IPSCTP_CAUSE_RESTART_W_NEWADDR 0x000b #define IPSCTP_CAUSE_USER_INITIATED_ABT 0x000c #define IPSCTP_CAUSE_PROTOCOL_VIOLATION 0x000d #define IPSCTP_CAUSE_SET(flag, cause) IP_BIT_SET(flag, (1 << cause) ) #endif /*The action when returning from input processing */ #define IPSCTP_ACTION_SEND_ABORT (1 << 0) #define IPSCTP_ACTION_SEND_COOKIE_ECHO (1 << 1) #ifdef IPNET_STATISTICS #define IPSCTP_STATISTICS #endif #define IPSCTP_INPUT_DONE 0 #define IPSCTP_INPUT_STOP_PROCESSING 1 /* Drop the packet, no internal state must change */ #define IPSCTP_INPUT_IN_ORDER_SUCCESS 2 /* Packet delivered successfully */ #define IPSCTP_INPUT_CONT 3 #define IPSCTP_INPUT_IGNORE_CHUNK 4 #define IPSCTP_INPUT_NOTIFY_USER_READ 5 /* hmac definition */ #define IPSCTP_SIG_MAX_SIZE MD5_LBLOCK #define IPSCTP_BLK_MAX_SIZE MD5_CBLOCK /* *=========================================================================== * IPSCTP code lock *=========================================================================== */ #ifdef IPNET # define IPSCTP_CODE_LOCK_READ() IPNET_CODE_LOCK_READ() # define IPSCTP_CODE_LOCK_WRITE() IPNET_CODE_LOCK_WRITE() # define IPSCTP_CODE_LOCK() IPSCTP_CODE_LOCK_WRITE() # define IPSCTP_CODE_UNLOCK() IPNET_CODE_UNLOCK() #ifdef IPCOM_FORWARDER_NAE #define IPSCTP_DATA_TCBLOCK(sl) do {} while(0) #define IPSCTP_DATA_TCBUNLOCK(sl) do {} while(0) #define IPSCTP_DATA_LOCK(sl) ipcom_enter_critical_region() #define IPSCTP_DATA_UNLOCK(sl) ipcom_exit_critical_region() #else #define IPSCTP_DATA_TCBLOCK(sl) IPNET_DATA_LOCK(sl) #define IPSCTP_DATA_TCBUNLOCK(sl) IPNET_DATA_UNLOCK(sl) #define IPSCTP_DATA_LOCK(sl) IPNET_DATA_LOCK(sl) #define IPSCTP_DATA_UNLOCK(sl) IPNET_DATA_UNLOCK(sl) #endif # define IPSCTP_DATA_ISLOCKED(sl) IPNET_DATA_ISLOCKED(sl) # define IPSCTP_DATA_ISLOCKED_ASSERT(sl) IPNET_DATA_ISLOCKED_ASSERT(sl) # ifdef IPNET_SMP_OPTIMIZED # define IPSCTP_SMP_OPTIMIZED # endif #else /* IPLITE */ # define IPSCTP_CODE_LOCK_READ() IPLITE_CODE_LOCK() # define IPSCTP_CODE_LOCK_WRITE() IPLITE_CODE_LOCK() # define IPSCTP_CODE_LOCK() IPSCTP_CODE_LOCK_WRITE() # define IPSCTP_CODE_UNLOCK() IPLITE_CODE_UNLOCK() # define IPSCTP_DATA_LOCK(x) IP_NOOP # define IPSCTP_DATA_UNLOCK(x) IP_NOOP # define IPSCTP_DATA_ISLOCKED(x) IP_FALSE # define IPSCTP_DATA_ISLOCKED_ASSERT(sl) IP_NOOP #endif /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* *=========================================================================== * IPSCTP association states *=========================================================================== * Current state information for an association. */ typedef enum { IPSCTP_STATE_LISTEN = 0, IPSCTP_STATE_CLOSED = 1, IPSCTP_STATE_COOKIE_WAIT, IPSCTP_STATE_COOKIE_ECHOED, IPSCTP_STATE_ESTABLISHED, IPSCTP_STATE_SHUTDOWN_PENDING, IPSCTP_STATE_SHUTDOWN_RECEIVED, IPSCTP_STATE_SHUTDOWN_SENT, IPSCTP_STATE_SHUTDOWN_ACK_SENT, IPSCTP_STATE_MAX } Ipsctp_state; /* SCTP reachability state for each remote address */ #define IPSCTP_ADDR_REACHABLE 0x001 #define IPSCTP_ADDR_NOHB 0x004 #define IPSCTP_ADDR_BEING_DELETED 0x008 #define IPSCTP_ADDR_NOT_IN_ASSOC 0x010 #define IPSCTP_ADDR_USER_PRIMARY 0x040 /* specified as primary by user, \ * or as primary during connection establishment. \ */ #define IPSCTP_ADDR_OUT_OF_SCOPE 0x080 #define IPSCTP_ADDR_DOUBLE_SWITCH 0x100 #define IPSCTP_ADDR_UNCONFIRMED 0x200 #define IPSCTP_ADDR_REQ_PRIMARY 0x400 /* request for being primary,but now maybe UNCONFIRMED */ #define IPSCTP_ADDR_RXT_PENDING 0x800 /* T3 timer running */ #define IPSCTP_ADDR_FR_PENDING 0x1000 /* FR timer running */ #define IPSCTP_ADDR_FLAG_NO_SMDE 0x2000 /* No Smooth mean deviation estimator calculated yet */ #define IPSCTP_ADDR_FLAG_RTT 0x4000 /* Flag to track if one of the DATA chunks * sent to this address is currently being * used to compute an RTT. If this flag is 0, * the next DATA chunk sent to this * destination should be used to compute an * RTT and this flag should be set. Every * time the RTT calculation completes (i.e., * the DATA chunk is SACK'd), the flag is * cleared. */ #define IPSCTP_ADDR_SRC_SELECTED 0x8000 /* selected source address for peer */ #define IPSCTP_ADDR_WINDOW_PROBE 0x10000 /* doing a window probe */ #define IPSCTP_ADDR_DATA_SENT 0x20000 /* some data sent during heartbeat interval. * Set when data is sent and clear in heartbeat timer */ #define IPSCTP_ADDR_NOT_IN_RT 0x40000 /* the selected source address doesn't belong to rt_entry */ #define IPSCTP_ADDR_EVER_SELECTED 0x80000 /* this transport has ever been selected */ /* *=========================================================================== * IPSCTP local address parameters *=========================================================================== * This union are defined for handling SCTP socket address. */ typedef union Ip_sockaddr_union Ipsctp_addr; /*#define Ipsctp_addr Ip_sockaddr_union*/ #if 0 #define IPSCTP_ADDR_SET_PORT(sctp_addr, port) #define IPSCTP_GET_PORT_FROM_SCTP_ADDR(addr) (((addr)->sa.sa_family == IP_AF_INET)?\ ((addr)->sin.sin_port):((addr)->sin6.sin6_port) #define IPSCTP_SET_PORT_FOR_SOADDRESS(soaddr, port) (((soaddr)->sa_family == IP_AF_INET)?\ (((Ip_sockaddr_in *)(soaddr))->sin_port = (port)):(((Ip_sockaddr_in6 *)(soaddr))->sin6_port = (port)) #endif typedef struct Ipsctp_af_ops_struct { Ipcom_list list; /* compare two sctp addresses */ Ip_bool (*cmp_addr)(const Ipsctp_addr *addr1, const Ipsctp_addr *addr2); /* compare lookup key with sctp address*/ Ip_bool (*cmp_addr_key)(IP_CONST Ipsctp_addr *addr, IP_CONST union Ip_in_addr_union *key, Ip_u16 domain); /* get internet address from input buffer */ void (*load_in_addr)(IP_CONST void *addr, union Ip_in_addr_union * in_address); /* get in_addr from sctp address */ void * (*get_in_addr)(IP_CONST Ipsctp_addr *addr); Ip_u32 (*get_scope_id)(IP_CONST Ipsctp_addr *addr); void (*ip_transmit)(IP_CONST void *dst, IP_CONST void *src, Ipcom_pkt *pkt); void (*load_soaddr)(IP_CONST void *addr, IP_CONST Ip_u16 port, Ipsctp_addr *sock_addr); void (*get_mtu_and_mss)(struct Ipsctp_tcb_struct *tcb,\ struct Ipsctp_transport_struct *transport,\ Ipnet_route_entry **rt_ret); void (*addr_set_port)(Ipsctp_addr *sctp_addr, IP_CONST Ip_u16 port); int (*src_addr_selection)(struct Ipsctp_tcb_struct *tcb, Ipnet_route_entry *rt,\ Ip_u16 lport, struct Ipsctp_transport_struct *transport); void (*rotate_src_addr)(struct Ipsctp_tcb_struct *tcb, struct Ipsctp_transport_struct *transport); void (*set_addr_for_socket)(struct Ipsctp_transport_struct *transport, Ipsctp_socket *sock); Ip_sa_family_t sa_family; }Ipsctp_af_ops; typedef enum Ipsctp_laddr_state_enum { IPSCTP_LADDR_NORMAL = 1 /* normal state local IP address */ /* need to extend... */ } Ipsctp_laddr_state; /* *=========================================================================== * IPSCTP local address entry parameters *=========================================================================== * The structure are defined for the entry of list(laddrs_list) in structure * Ipsctp_instance_struct. */ typedef struct Ipsctp_laddrs_entry_struct { Ipcom_list next; /* Keep list entry first */ Ipsctp_addr laddr; /* Local sctp bind address */ Ipsctp_laddr_state state; /* Local IP address state */ Ip_u32 start_time; /* sctpAssocLocalAddrStartTime, mib*/ } Ipsctp_laddr_entry; #ifdef IPSCTP_MIB #define IPSCTP_MIB_STATS(xvar) ipsctp->mib_stats.xvar #define IPSCTP_MIB_STAT_LINE(xline) xline #else /* No SCTP mib stats */ #define IPSCTP_MIB_STATS(xvar) IP_NOOP #define IPSCTP_MIB_STAT_LINE(xline) IP_NOOP #endif /* ifdef IPSCTP_MIB */ #if defined(IPSCTP_DEBUG) || defined(IPSCTP_STATISTICS) typedef struct Ipsctp_stats_struct { /* Other Statistics */ Ip_u32 sctp_input; Ip_u32 sctp_input_hdr_trunc; Ip_u32 sctp_input_tcb_nomatch; Ip_u32 sctp_input_tcb_match; Ip_u32 sctp_input_bad_vtag; Ip_u32 sctp_input_dup_chunks; Ip_u32 sctp_tsn_bitmap_expand; Ip_u32 sctp_input_drop_chunks_bitmap; Ip_u32 sctp_input_drop_chunks_invalid_sid; Ip_u32 sctp_input_drop_chunks_no_buf; Ip_u32 sctp_input_chunks_express; Ip_u32 sctp_input_chunks_express_pd; Ip_u32 sctp_input_chunks_queue2buf; Ip_u32 sctp_input_chunks_queue2pd; Ip_u32 sctp_input_chunks_pd; Ip_u32 sctp_input_chunks_fragment; Ip_u32 sctp_input_chunks_queued_fragment; Ip_u32 sctp_input_chunks_not_fragment; /* all input non-fragment chunks*/ Ip_u32 sctp_input_chunks_queued_not_fragment; /* all input non-fragment chunks * queued in input stream queue. */ Ip_u32 sctp_input_msgs_reasm_queued; Ip_u32 sctp_input_chunks_buf2user; Ip_u32 sctp_input_chunks_fragment2user; Ip_u32 sctp_input_msgs_reasm_2user; Ip_u32 sctp_output_window_update; Ip_u32 sctp_read_peeks; Ip_u32 sctp_output_data; /* number of usr send data times(all) */ Ip_u32 sctp_output_data_err; /* number of usr send data times(failure) */ Ip_u32 sctp_output_data_chunk; /* number of the output data chunks(all) */ Ip_u32 sctp_output_data_chunk_err; /* number of the output data chunks(failure) */ Ip_u32 sctp_output_data_chunk_retr; /* number of the retransmit data chunks(all) */ Ip_u32 sctp_output_data_chunk_retr_err; /* number of the retransmit data chunks(failure) */ Ip_u32 sctp_output_ctrl_chunk; /* number of the output control chunks(all) */ Ip_u32 sctp_output_ctrl_chunk_err; /* number of the output control chunks(failure) */ Ip_u32 sctp_output_pkt; /* number of output sctp packets(all) */ Ip_u32 sctp_output_pkt_err; /* number of output sctp packets(failure) */ Ip_u32 sctp_output_data_chunk_cwnd; /* number of output new data not allowed by cwnd */ Ip_u32 sctp_output_data_chunk_cwnd_retr; /* number of output retransmit data not allowed by cwnd */ Ip_u32 sctp_output_data_chunk_nagle; /* number of output retransmit data not allowed by Nagle */ Ip_u32 sctp_output_data_chunk_mult_owner; /* number of output retransmit data not allowed by Multi_owner */ } Ipsctp_stats; #define IPSCTP_STATS(xvar) ipsctp->stats.xvar #define IPSCTP_STAT_LINE(xline) xline #else /* No SCTP stats */ #define IPSCTP_STATS(xvar) IP_NOOP #define IPSCTP_STAT_LINE(xline) IP_NOOP #endif /* defined(IPSCTP_DEBUG) || defined(IPSCTP_STATISTICS) */ /* *=========================================================================== * IPSCTP DATA CONTROL (IPSCTP DATA) *=========================================================================== */ typedef struct Ipsctp_data_struct { Ipcom_list address_families; /* address families list*/ Ipcom_list free_chunk_list; /* List of free SCTP chunk structures */ Ip_u32 msec_last_sock_create; /* The time a socket was last created */ Ipsctp_hash *tcb_hashtable; /* indexed by vtag * All sctp assocation in hash table * size hidden in Ipsctp_hash * hash key(v-tag) */ Ipsctp_hash *tcb_hashtable_port; /* indexed by local port and remote port * All sctp assocation in hash table * size hidden in Ipsctp_hash * hash key(local port and remote port) */ Ipsctp_hash *vtag_timewait; Ipcom_list vtag_timers; Ip_u32 cnt_tcb; /* Current count of TCB */ #ifndef IPCOM_FORWARDER_NAE /* * List of active socket instances. All of the sockets in this list must be * checked for timeouts each tick. */ Ipcom_list active_head; #endif #if defined(IPSCTP_DEBUG) || defined(IPSCTP_STATISTICS) Ipsctp_stats stats; /* Statistics */ #endif #ifdef IPSCTP_MIB Ipsctp_mib_stats mib_stats; /* Statistics */ #endif int opt_tcb_lookup; /* optimize tcb lookup */ Ip_u32 max_chunks_on_queue; /* max chunks on queue per association */ #ifdef IPSCTP_FAST_RETRANSMITE Ip_bool early_fr; /* early fast retransmission */ #endif } Ipsctp_data; IP_EXTERN Ipsctp_data *ipsctp; IP_EXTERN Ipcom_pkt *ipsctp_tx_list; /* List of SCTP finished segments that are waiting to be transmitted. This list points to the last SCTP segment to be sent */ #define IPSCTP_RTO_ALPHA (3) #define IPSCTP_RTO_BETA (2) #define IPSCTP_CLOCK_GRANULARITY (1) /* *=========================================================================== * IPSCTP peer transport parameters *=========================================================================== * One instance of this structure exists for each destination transport * address in the sctp association's address list derived from the INIT * or INIT ACK chunk. * TODO: Considerations for alignment * Whether or not to have more seperate timers or only one handler? * rto_pending not clear yet? pmtu_timer(mtu increase periodically?) need more investigation fr_timer need more investigation hb_timer per association or per transport? what is heartbeat random? */ typedef struct Ipsctp_transport_struct { Ipcom_list trans_next; /* next transport in list */ Ipsctp_addr paddr; /* the address to which this info belongs */ Ipsctp_addr saddr; /* the selected source address */ #ifdef IPCOM_FORWARDER_NAE Ip_sa_family_t address_family; /* just save the address family */ #else Ipsctp_af_ops *af_ops; /* address family specific operations*/ #endif int ops_handle; /* handle to socket family specific operations*/ /* Following is from rfc 13.3. Per Transport Address Data */ Ip_u32 err_cnt; /* The current error count for this destination */ Ip_u32 err_thresh; /* Current error threshold for this destination, i.e., * what value marks the destination down if error count * reaches this value. sctpAssocRemAddrMaxPathRtx */ Ip_u32 cwnd; /* The current congestion window */ Ip_u32 ssthresh; /* The current ssthresh value */ Ip_u32 rto; /* The current retransmission timeout value */ Ip_u32 srtt; /* The current smoothed round-trip time */ Ip_u32 rttvar; /* The current RTT variation */ Ip_u32 pt_bytes_acked; /* The tracking method for increase of cwnd when in * bytes acked : congestion avoidance mode (see Section 7.2.2).*/ Ip_u32 flight_size; /* bytes of sent and not acked chunks */ Ip_u32 net_ack; /* The total byte count acked */ Ip_u32 net_ack2; /* track the total bytes acked that are unambiguous and were never retransmitted*/ Ip_u32 state; /* The current state of this destination, i.e., DOWN, UP, * ALLOW-HB, NO-HEARTBEAT, etc. See IPSCTP_ADDR_XXX */ Ip_u32 pmtu; /* The current known path MTU */ Ip_u32 mss; /* The current known mss, incluing chunk header */ Ipsctp_timer rxt_timer; /* Timer used by each destination */ Ip_u32 tos_flowlabel; struct Ip_timeval last_sent_time; /* The time to which this destination was last sent. * This can be to determine if a HEARTBEAT is needed. */ Ip_u32 hbinterval; /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to * the destination address every heartbeat interval.*/ /* Remote Address Statistic in RFC3873. */ Ip_u32 start_time; /* sctpAssocRemAddrStartTime. * The value of sysUpTime at the time that this row was * created. */ #ifdef IPSCTP_MIB Ip_u32 marked_retrans; /* sctpAssocRemAddrRtx. * Number of DATA chunks retransmissions to this specific IP * address. When T3-rtx expires, the DATA chunk that triggered * the T3 timer will be re-sent according to the retransmissions * rules. Every DATA chunk that is included in a SCTP packet and * was transmitted to this specific IP address before, will be * included in this counter */ #endif Ip_u32 cur_marked_retrans_bytes; /* Bytes of DATA chunk marked for retransmission now to this * specific IP address, 4B-aligned including data chunk hdr */ Ip_u32 unsent_bytes; /* all the 4B-aligned unsent data including data chunk hdr to this transport(bytes) */ Ip_u8 hb_responded; /* check if need backoff */ Ipsctp_timer hb_timer; /* HB timer */ Ipsctp_timer fr_timer; /* FR timer */ Ip_u32 random_v1; /* random value1 number used for heartbeat */ Ip_u32 random_v2; /* random value1 number used for heartbeat */ } Ipsctp_transport; #ifdef IPSCTP_USE_SLAB_MEMORY #else /* get the data chunk length including payload and data chunk hdr */ #define IPSCTP_GET_DATA_CHUNK_TRANS_LEN(chunk_send)\ ((chunk_send)->length + sizeof(Ipsctp_data_chunk_hdr)) /* get the data chunk length including payload and data chunk hdr (4B-aligned) */ #define IPSCTP_GET_DATA_CHUNK_TRANS_ALIGN_LEN(chunk_send)\ (IP_ROUNDUP(IPSCTP_GET_DATA_CHUNK_TRANS_LEN(chunk_send),4)) /* get the chunk length for cc window related calculation(only payload) */ #define IPSCTP_GET_DATA_CHUNK_WIND_LEN(chunk_send) (chunk_send)->length /* get the control chunk length */ #define IPSCTP_GET_CRTL_CHUNK_TRANS_LEN(chunk_send) (chunk_send)->length /* get the control chunk length (4B-aligned) */ #define IPSCTP_GET_CRTL_CHUNK_TRANS_ALIGN_LEN(chunk_send)\ (IP_ROUNDUP(IPSCTP_GET_CRTL_CHUNK_TRANS_LEN(chunk_send),4)) #ifdef IPCOM_FORWARDER_NAE #define IPSCTP_GET_SEND_CHUNK ipcom_shm_malloc(sizeof(Ipsctp_chunk_send)) #define IPSCTP_FREE_SEND_CHUNK(chunk_send) \ do {\ if(chunk_send->chunk.pkt)\ ipcom_pkt_free(chunk_send->chunk.pkt);\ ipcom_shm_free(chunk_send);\ }while(0) #define IPSCTP_GET_RECV_CHUNK ipcom_shm_malloc(sizeof(Ipsctp_chunk_recv)) #define IPSCTP_FREE_RECV_CHUNK(recv_chunk) \ do {\ if(recv_chunk->chunk.pkt)\ ipcom_pkt_free(recv_chunk->chunk.pkt);\ ipcom_shm_free(recv_chunk);\ }while(0) #else /* !IPCOM_FORWARDER_NAE */ #define IPSCTP_GET_SEND_CHUNK ipcom_malloc(sizeof(Ipsctp_chunk_send)) #define IPSCTP_FREE_SEND_CHUNK(chunk_send) \ do {\ if(chunk_send->chunk.pkt)\ ipcom_pkt_free(chunk_send->chunk.pkt);\ ipcom_free(chunk_send);\ }while(0) #define IPSCTP_GET_RECV_CHUNK ipcom_malloc(sizeof(Ipsctp_chunk_recv)) #if 0 #define IPSCTP_FREE_RECV_CHUNK(recv_chunk) \ do {\ Ipsctp_chunk_recv *cur_frag, *next_frag;\ next_frag = recv_chunk->next_fragment;\ while(next_frag)\ {\ cur_frag = next_frag;\ next_frag = cur_frag->next_fragment;\ if(cur_frag->chunk.pkt)\ ipcom_pkt_free(cur_frag->chunk.pkt);\ ipcom_free(cur_frag);\ }\ if(recv_chunk->chunk.pkt)\ ipcom_pkt_free(recv_chunk->chunk.pkt);\ ipcom_free(recv_chunk);\ }while(0) #else #define IPSCTP_FREE_RECV_CHUNK(recv_chunk) \ do {\ if(recv_chunk->chunk.pkt)\ ipcom_pkt_free(recv_chunk->chunk.pkt);\ ipcom_free(recv_chunk);\ }while(0) #endif #endif /* end IPCOM_FORWARDER_NAE */ #endif /* IPSCTP_USE_SLAB_MEMORY*/ #define IPSCTP_INIT_RECV_CHUNK(tcb1, transport1, pkt1, chunk_type1, chunk_start1, length1,\ sid, ssn, chunk_flags, ppid, tsn, chunk_recv) \ do {\ ip_assert(IP_NULL != chunk_recv); \ chunk_recv->chunk.pkt = pkt1;\ chunk_recv->chunk.tcb = tcb1;\ chunk_recv->chunk.transport = transport1;\ chunk_recv->chunk.flag = 0;\ IP_BIT_SET(chunk_recv->chunk.flag, IPSCTP_CHUNK_FLAG_RECV);\ chunk_recv->chunk.chunk_type = chunk_type1;\ chunk_recv->chunk.chunk_start = chunk_start1;\ chunk_recv->chunk.chunk_end = (chunk_start1 + length1);\ /*chunk_recv->next_fragment = NULL;*/\ chunk_recv->length = length1;\ /*chunk_recv->chunk_cnt = 1;*/\ chunk_recv->sndrcv_info.sinfo_context = tcb1->context;\ chunk_recv->sndrcv_info.sinfo_cumtsn = tcb1->cumulative_tsn; /* ? */\ chunk_recv->sndrcv_info.sinfo_flags = chunk_flags;\ chunk_recv->sndrcv_info.sinfo_ppid = ppid;\ chunk_recv->sndrcv_info.sinfo_pr_policy = 0;\ chunk_recv->sndrcv_info.sinfo_pr_value = 0;\ chunk_recv->sndrcv_info.sinfo_ssn = ssn;\ chunk_recv->sndrcv_info.sinfo_stream = sid;\ chunk_recv->sndrcv_info.sinfo_tsn = tsn;\ chunk_recv->sndrcv_info.sinfo_assoc_id = tcb1->my_vtag;\ chunk_recv->from_addr = transport1->paddr;\ }while(0) /* *=========================================================================== * IPSCTP Transmission Chunk (IPSCTP CHUNK for send) *=========================================================================== Ipsctp_chunk is the list element in stream queue, control queue, transmitted queue. TODO: we can use next_fragment in Ipcom_pkt? statistics should be added */ typedef struct Ipsctp_chunk_struct { Ipcom_list chunk_next; /* Chunk entry in list*/ Ipcom_pkt *pkt; /* Pkt in this list ,transform * The buffer in pkt to each type of chunk per chunk_type */ int chunk_start; /* The start location of this chunk's data ,specially for receive */ int chunk_end; /* The end location of this chunk's data , specially for receive */ Ip_u16 chunk_type; /* Chunk Type */ struct Ipsctp_tcb_struct *tcb; /* Which association does this belong to */ Ipsctp_transport *transport; /* The destination this chunk sent to, or received from */ Ip_u16 flag; /* The send status, or receive control flag, see IPSCTP_CHUNK_FLAG_XXX. * the lower 4 bits of send staus refer to IPSCTP_CHUNK_FLAG_SEND_STATE_XX */ } Ipsctp_chunk; /* *=========================================================================== * Ipsctp_chunk_recv *=========================================================================== * Ipsctp_chunk_recv is the list element in recv queue. */ typedef struct Ipsctp_chunk_recv_struct { Ipsctp_chunk chunk; struct Ipsctp_sndrcvinfo sndrcv_info; Ipsctp_addr from_addr; #if 0 struct Ipsctp_chunk_recv_struct *next_fragment; /* next fragment of the chunk */ Ip_u32 chunk_cnt; /* the count of all chunk frgments */ #endif Ip_u32 length; /* length of all chunk fragments */ } Ipsctp_chunk_recv; /* *=========================================================================== * Ipsctp_chunk_send *=========================================================================== * Ipsctp_chunk_snd is the list element in send queue. */ typedef struct Ipsctp_chunk_send_struct { Ipsctp_chunk chunk; struct Ipsctp_sndrcvinfo sndrcv_info; Ip_u16 snd_count; /* number of times sent */ Ip_u32 fr_tsn; /* sending tsn at the time of FR */ struct Ip_timeval snd_time; Ip_u32 length; /* for DATA type: actual payload length(no alignment) excluding data chunk header * for CONTROL type: chunk length(no alignment) including Ipsctp_chunk_hdr. */ } Ipsctp_chunk_send; /* *=========================================================================== * IPSCTP INPUT PARA (IPSCTP INPUT PARAMETER) *=========================================================================== */ #define IPSCTP_STREAM_IN_FLAG_DELIVERY_STARTED (1 << 0) /* Set when in the process of delivering a record with socket */ #if 0 #define IPSCTP_STREAM_IN_FLAG_INIT (1 << 1) /* Set when this stream receives first chunk */ #endif typedef struct Ipsctp_stream_in_struct { Ip_u16 stream_number; Ip_u16 last_ssn_delivered; /* used for re-order; * for unordered chunk, don't update last_ssn_delivered */ Ip_u32 last_tsn_delivered; /* last tsn delivered to socket buffer; * for unordered chunk, don't update last_tsn_delivered */ Ipcom_list queue_chunks; /* Chunks received to be re-order or reassemble */ #if 0 Ip_u8 delivery_started; #endif Ip_u8 flag; /* see IPSCTP_STREAM_IN_FLAG_XXX */ #ifdef IPSCTP_USE_PARTIAL_DELIVERY Ipsctp_chunk_recv *chunk_pd_first; /* partial delivery chunk */ Ipsctp_chunk_recv *chunk_pd_end; /* latest fragment of partial delivery chunk */ #endif } Ipsctp_stream_in; /* *=========================================================================== * IPSCTP Transmission Stream (IPSCTP STREAM) *=========================================================================== */ typedef struct Ipsctp_stream_out_struct { Ipcom_list stream_next; /* stream entry in list */ Ipcom_list chunk_list; /* chunk queue head */ Ip_u16 stream_number; /* stream number */ Ip_u16 next_ssn_sent; /* next one I expect to send out */ Ip_u8 last_msg_incomplete; /* last msg in this stream is incomplete. * if the following part of this msg arrives, * complete this msg. * may have to fragment if the whole msg too big */ Ipsctp_chunk *selected_chunk; /* by now the selected chunk to send in this stream */ } Ipsctp_stream_out; /* Congestion control modules for pluggable * congestion control. * By now only IPSCTP_CC_RFC2581 is supported. */ typedef enum Ipsctp_cc_module_enum { IPSCTP_CC_RFC2581 = 0 , /* Standard TCP Congestion Control */ IPSCTP_CC_HSTCP, /* High Speed TCP Congestion Control (Floyd) */ IPSCTP_CC_HTCP, /* HTCP Congestion Control */ IPSCTP_CC_MAX }Ipsctp_cc_module; typedef struct Ipsctp_cc_functions_struct { void (*init)(struct Ipsctp_tcb_struct *tcb, Ipsctp_transport *transport); void (*cwnd_update_sack)(struct Ipsctp_tcb_struct *tcb, Ip_bool cum_ack_moved, Ip_bool will_exit_fast_recovery); void (*cwnd_update_fr)(struct Ipsctp_tcb_struct *tcb); void (*cwnd_update_tmo)(struct Ipsctp_tcb_struct *tcb, Ipsctp_transport *transport); void (*cwnd_update_output)(struct Ipsctp_tcb_struct *tcb, Ipsctp_transport *transport); #if 0 void (*sctp_cwnd_update_after_ecn_echo) (struct Ipsctp_tcb_struct *stcb, Ipsctp_transport *transport); void (*sctp_cwnd_update_after_packet_dropped) (struct Ipsctp_tcb_struct *stcb, Ipsctp_transport *transport, struct sctp_pktdrop_chunk *cp, uint32_t * bottle_bw, uint32_t * on_queue); void (*sctp_cwnd_update_after_fr_timer) (struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sctp_nets *net); #endif }Ipsctp_cc_functions; /* sock->ipcom.rcv_bytes: bytes of all TCBs' chunks in the socket */ #ifdef IPSCTP_USE_MULTIBUF #define IPSCTP_RECVBUF_MAX(tcb) tcb->sock->recv_max_bytes /*tcb->recv_max_bytes*/ #define IPSCTP_RECVBUF_LEN(tcb) tcb->recv_bytes #define IPSCTP_RECVBUF_LEN_ADD(tcb, len) \ do {\ tcb->recv_bytes += (len);\ tcb->sock->ipcom.rcv_bytes += (len);\ }while(0) #define IPSCTP_RECVBUF_LEN_SUB(sock, tcb, len) \ do {\ if (tcb)\ {\ tcb->recv_bytes -= (len);\ tcb->sock->ipcom.rcv_bytes -= (len);\ }\ }while(0) #define IPSCTP_RECVBUF_CNT(sock, tcb) tcb->recv_chunks_cnt #define IPSCTP_RECVBUF_CNT_SUB(sock, tcb, len) \ do {\ if (tcb)\ tcb->recv_chunks_cnt -= (len);\ }while(0) #define IPSCTP_RECVBUF_QUEUE_LEN(tcb) tcb->size_on_in_queue #define IPSCTP_RECVBUF_QUEUE_CNT(tcb) tcb->cnt_on_in_queue #define IPSCTP_SENDBUF_LEN(tcb) tcb->sock->snd_bytes /*tcb->send_bytes*/ #define IPSCTP_SENDBUF_MAX(tcb) tcb->sock->send_max_bytes #define IPSCTP_SENDBUF_CNT(tcb) tcb->send_chunks_cnt #else #define IPSCTP_RECVBUF_MAX(tcb) tcb->sock->recv_max_bytes #define IPSCTP_RECVBUF_LEN(tcb) tcb->sock->ipcom.rcv_bytes #define IPSCTP_RECVBUF_LEN_ADD(tcb, len) tcb->sock->ipcom.rcv_bytes += (len) \ , ipsctp_log3int(IPCOM_LOG_DEBUG, IPSCTP_DBG_BUF, "FILE "__FILE__" LINE %d BufSize: %d, add: %d\n",\ __LINE__, tcb->sock->ipcom.rcv_bytes, len) #define IPSCTP_RECVBUF_LEN_SUB(sock, tcb, len) sock->ipcom.rcv_bytes -= (len)\ , ipsctp_log3int(IPCOM_LOG_DEBUG, IPSCTP_DBG_BUF, "FILE "__FILE__" LINE %d BufSize: %d, sub: %d\n",\ __LINE__, sock->ipcom.rcv_bytes, len) #define IPSCTP_RECVBUF_CNT(sock, tcb) sock->sctp_inst->recv_chunks_cnt #define IPSCTP_RECVBUF_CNT_SUB(sock, tcb, len) sock->sctp_inst->recv_chunks_cnt -= (len) #define IPSCTP_RECVBUF_QUEUE_LEN(tcb) tcb->instance->size_on_in_queue #define IPSCTP_RECVBUF_QUEUE_CNT(tcb) tcb->instance->cnt_on_in_queue #define IPSCTP_SENDBUF_LEN(tcb) tcb->sock->snd_bytes /* only user data length */ #define IPSCTP_SENDBUF_MAX(tcb) tcb->sock->send_max_bytes #define IPSCTP_SENDBUF_CNT(tcb) tcb->instance->send_chunks_cnt #endif #ifdef IPCOM_FORWARDER_NAE #define IPSCTP_APPEND_RECV_CHUNK(tcb, chunk_recv) ipsctp_append_recv_chunk(tcb,chunk_recv) IP_INLINE int ipsctp_append_recv_chunk( struct Ipsctp_tcb_struct * tcb,Ipsctp_chunk_recv* chunk_recv); #define IPSCTP_INSERT_RECV_CHUNK(tcb, chunk_recv_pre, chunk_recv) \ do {\ Ipcom_socket_eventcb event_cb = tcb->sock->ipcom.event_cb;\ /* add the chunk to socket receive buffer */\ IPSCTP_DATA_LOCK(tcb->sock->rcv_lock);\ ipcom_list_insert_after(&chunk_recv_pre->chunk.chunk_next, &chunk_recv->chunk.chunk_next);\ IPSCTP_RECVBUF_CNT(tcb->sock, tcb)++;\ IPSCTP_RECVBUF_LEN_ADD(tcb, chunk_recv->length);\ IPSCTP_DATA_UNLOCK(tcb->sock->rcv_lock);\ if (event_cb != IP_NULL)\ {\ (void)event_cb(&tcb->sock->ipcom, (Ipcom_pkt *)chunk_recv, IP_SOEVENT_CB_INPKT);\ }\ }while(0) #else #define IPSCTP_APPEND_RECV_CHUNK(tcb, chunk_recv)\ do {\ Ipcom_socket_eventcb event_cb = tcb->sock->ipcom.event_cb;\ /* add the chunk to socket receive buffer */\ IPSCTP_DATA_LOCK(tcb->sock->rcv_lock);\ ipcom_list_insert_last(&tcb->instance->recv_list, &chunk_recv->chunk.chunk_next);\ IPSCTP_RECVBUF_CNT(tcb->sock, tcb)++;\ IPSCTP_RECVBUF_LEN_ADD(tcb, chunk_recv->length);\ IPSCTP_DATA_UNLOCK(tcb->sock->rcv_lock);\ if (event_cb != IP_NULL)\ {\ (void)event_cb(&tcb->sock->ipcom, (Ipcom_pkt *)chunk_recv, IP_SOEVENT_CB_INPKT);\ }\ }while(0) #define IPSCTP_INSERT_RECV_CHUNK(tcb, chunk_recv_pre, chunk_recv) \ do {\ Ipcom_socket_eventcb event_cb = tcb->sock->ipcom.event_cb;\ /* add the chunk to socket receive buffer */\ IPSCTP_DATA_LOCK(tcb->sock->rcv_lock);\ ipcom_list_insert_after(&chunk_recv_pre->chunk.chunk_next, &chunk_recv->chunk.chunk_next);\ IPSCTP_RECVBUF_CNT(tcb->sock, tcb)++;\ IPSCTP_RECVBUF_LEN_ADD(tcb, chunk_recv->length);\ IPSCTP_DATA_UNLOCK(tcb->sock->rcv_lock);\ if (event_cb != IP_NULL)\ {\ (void)event_cb(&tcb->sock->ipcom, (Ipcom_pkt *)chunk_recv, IP_SOEVENT_CB_INPKT);\ }\ }while(0) #endif #define IPSCTP_FREE_PKT_LIST(pkt_list)\ do {\ Ipcom_pkt *free_pkt = IP_NULL;\ Ipcom_pkt *free_pkt_next = IP_NULL;\ free_pkt = pkt_list;\ while (IP_NULL != free_pkt)\ {\ free_pkt_next = free_pkt->next;\ ipcom_pkt_free(free_pkt);\ free_pkt = free_pkt_next;\ }\ } while(0) /* *=========================================================================== * IPSCTP Transmission Control Block (IPSCTP TCB) *=========================================================================== * The members of this structure are defined partially per recommendation in * Section 13 of RFC4960 and partially per Iptcp_tcb definitions. * Notes: sctpAssocPrimProcess in RFC3873 is not supported, should be zero. */ typedef struct Ipsctp_tcb_struct { Ipcom_list next; /* next pointer in the same instance */ Ipsctp_instance *instance; /* points back to the IPSCTP instance owning this TCB */ Ipsctp_socket *sock; /* Points to the socket this TCb is bound to */ Ip_u32 tcb_flags; /* IPSCTP_TCBC_FLAG_XXX*/ Ip_u32 tcb_peer_flags; /* IPSCTP_TCBC_FLAG_XXX*/ int tcb_errno; /* Socket errno (IP_ERRNO_xxx) */ Ipsctp_vtag peer_vtag; /* peer verification tag value (transmitted in all * packets, recieved from INIT/INIT ACK chunks. */ Ipsctp_vtag my_vtag; /* verification tag value (expected in all recieved * packets and trnasmitted in INIT/INIT ACK chunks. * Also as association id, sctpAssocId. */ Ip_u32 my_vtag_nonce; Ip_u32 peer_vtag_nonce; /* Configurable variable */ Ip_u16 max_init_times; Ip_u16 max_send_times; /* Mib: sctpAssocMaxRetr */ Ip_u16 max_transport_retrans; /* max retransmissions */ Ip_u32 initial_init_rto_max; /* initial RTO for INIT's */ Ip_u32 initial_rto; /* initial send RTO */ Ip_u32 min_rto; /* per assoc RTO-MIN */ Ip_u32 max_rto; /* per assoc RTO-MAX */ #ifdef IPCOM_USE_INET6 Ip_u32 ipv6_flowlabel; /* flow label */ #endif #ifdef IPCOM_USE_INET Ip_u8 ipv4_tos; #endif Ip_u32 context; /* Set or get by SCTP_CONTEXT */ Ipsctp_state state; /* association state: assumes all state values except * IPSCTP_STATE_CLOSED as there is no TCB in IPSCTP_STATE_CLOSED state */ Ipcom_list transport_list; /* peer addresses and parameters struct list*/ Ipsctp_transport *primary_transport; /* points to the primary path info */ Ipsctp_transport *last_ctrl_from; Ipsctp_transport *last_data_from; Ip_u32 pmtu; /* smallest PMTU discovered for all of peer addresses. */ Ip_u32 mss; Ip_u32 frag_point; /* size to do fragments */ Ip_u16 rport; /* remote port, in host order */ Ipsctp_sctp_sndrcvinfo def_send; /* default send info */ Ip_u32 oa_err_cnt; /* overall error count on this association*/ Ip_u32 total_flight; /* amount of data (bytes) currently in flight (on all destinations) * Total book size in flight, excluding any acked(cumulative and gap) data */ Ip_u32 max_burst; /* maximum burst of packets * that can be emitted by this association */ #if 0 /* we can get this value from transmitted_chunk_list's size */ Ip_u32 total_flight_count; /* count of chunks used with book total */ Ip_u32 send_max_bytes; Ip_u32 recv_max_bytes; /* max receive buffer size for this association */ #endif Ip_u32 sent_queue_retran_cnt; /* Number on sent queue that are marked for retran until this value * is 0 we only send one packet of retran'ed data. ??*/ #ifdef IPSCTP_USE_MULTIBUF Ipcom_atomic_t send_bytes; /* all the data bytes in send queue,including all unsent and unacked. */ Ip_u32 send_chunks_cnt; Ip_u32 recv_bytes; /* chunks bytes in receive buffer, = size_on_in_queue? */ Ip_u32 recv_chunks_cnt; /* chunks count in receive buffer */ Ip_u32 size_on_in_queue; /* chunk bytes in input stream's chunk queue, haven't been delivered to socket receive buffer.*/ Ip_u32 cnt_on_in_queue; /* chunk count in input stream's chunk queue, haven't been delivered to socket receive buffer.*/ #endif #if 0 Ip_u32 size_on_reasm_queue; Ip_u32 cnt_on_reasm_queue; #endif /* window state information */ Ip_u32 peers_rwnd; Ip_u32 my_last_reported_rwnd; Ipsctp_cc_functions cc_functions; /* value to store the currently loaded congestion control module */ Ip_u32 congestion_control_module; Ipcom_bitarray *recv_tsn_bitmap; /* array of bits indicating which out-of-order * TSNs have been received */ Ip_u16 recv_tsn_bitmap_size; Ip_u32 recv_tsn_bitmap_base; /* Used to track the tsn bitmap and its offset bits. This MAY be * lower then cumulative_tsn.*/ Ip_u32 cumulative_tsn; /* The highest consequetive TSN at the bottom of the mapping array * (for his sends).*/ Ip_u32 highest_tsn_inside_map; /* used to track highest TSN we have received * and is listed in the mapping array.*/ Ip_u32 numduptsns; Ip_u32 dup_tsns[IPSCTP_MAX_DUP_TSNS]; /* Duplicated TSN packets received */ Ip_u32 tsn_last_delivered; /* need it? */ Ip_u32 init_tsn_number; /* Original tsn number I used */ Ip_u32 tsn_next; /* next TSN number to be assigned to a * new DATA chunk. Sent in INIT/INIT ACK * chunk to peer and incremented each time * DATA chunk is assigned a TSN. */ Ip_u32 fast_recovery_tsn; /* set when fast retransmit */ Ip_u32 sat_t3_recovery_tsn; /* set in t3 timer */ Ip_u32 this_sack_highest_gap; /* Special hook for Fast retransmit, allows us to track the highest * TSN that is NEW in this SACK if gap ack blocks are present.*/ Ip_u32 last_acked_tsn; /* The highest consecutive TSN that has been acked by peer on my sends */ #if 0 Ipsctp_chunk_recv *chunk_pd; /* chunk in partial delivery */ Ip_u16 ssn_pd; /* stream sequence number for partial delivery */ Ip_u16 sid_pd; /* stream id for partial delivery */ Ip_u32 tsn_pd; /* tsn of partial delivery chunk */ Ip_u16 fragment_flags; #endif Ip_u32 sack_freq; /*to control the sack*/ Ip_u32 data_pkts_seen; /*to control the sack, if data_pkts_seen > sack_freq, send sack*/ Ipsctp_stream_in *streams_in; /* tracks inbound streams */ Ipsctp_stream_out *streams_out; /* Out stream queue head,list all streams */ Ipcom_list streams_out_sched_list; /* Out sched for stream schedule, * e.g. for Round-robin the list link all streams who have packets */ Ipcom_list control_chunk_list; /* Control chunk queue list head */ Ipcom_list transmitted_chunk_list; /* Transmitted chunk queue */ Ip_u16 streamincnt; /* sctpAssocInStreams */ Ip_u16 streamoutcnt; /* sctpAssocOutStreams */ Ip_u16 max_inbound_streams; /* How many streams I support coming into me */ Ip_u16 pre_open_streams; /* how many preopen streams we have */ Ip_u32 total_sends; Ip_u32 total_recvs; struct Ip_timeval time_entered; /* time we entered state */ struct Ip_timeval time_last_rcvd; struct Ip_timeval time_last_sent; Ip_u32 start_time; /* time we start the association*/ Ip_u32 discontinuity_time; /* sctpAssocDiscontinuityTime */ Ip_u32 hb_interval; /* Heart Beat interval in MSEC, sctpAssocHeartBeatInterval*/ Ip_u32 autoclose_time; /* autoclose time, im MSEC */ Ip_u32 delayed_ack; /*time of delay ack timer */ /* timer */ Ipsctp_timer dack_timer; /* Delayed ack timer */ Ipsctp_timer asconf_timer; /* asconf */ Ipsctp_timer shut_guard_timer; /* shutdown guard */ Ipsctp_timer autoclose_timer; /* automatic close timer */ Ipsctp_timer delayed_event_timer; /* timer for delayed events */ Ipsctp_timer delete_prim_timer; /* deleting primary dst */ Ip_u32 cookie_life; Ip_u8 cookie_how[8]; /*record different accasions in cookie_existing,yjg*/ Ip_u16 stale_cookie_count; Ip_u32 cookie_preserve_req; /*required cookie time*/ /* Mib in RFC3872 */ #ifdef IPSCTP_MIB Ip_u32 marked_retrans; /* sctpAssocRtxChunks */ Ip_u32 cnt_timo_init; /* sctpAssocT1expireds = cnt_timo_init + cnt_timo_cookie */ Ip_u32 cnt_timo_cookie; Ip_u32 cnt_timo_shutdown; /* sctpAssocT2expireds = cnt_timo_shutdown+ cnt_timo_shutdownack */ Ip_u32 cnt_timo_shutdownack; #endif } Ipsctp_tcb; /* *=========================================================================== * Ipsctp_tcb_lookup_key *=========================================================================== */ typedef struct Ipsctp_tcb_lookup_key_struct { Ip_u32 vr; /* The virtual router */ Ip_u16 domain; /* The domain */ Ip_u16 strict_match; /* Whether match port and address or not */ Ip_u16 local_port; /* The local port */ Ip_u16 peer_port; /* The peer port */ union Ip_in_addr_union local_addr; /* The local address */ union Ip_in_addr_union peer_addr; /* The peer address */ Ip_u32 vtag; /* if zero, lookup using ports and addresses, if non-zero, lookup using vtag */ Ipsctp_transport **transport; /* return matching transport */ Ipsctp_af_ops *af_ops; /* address family related operations */ } Ipsctp_tcb_lookup_key; /* *=========================================================================== * Ipsctp_tag_timewait *=========================================================================== */ typedef struct Ipsctp_vtag_timewait_struct { Ip_u32 vtag; Ipsctp_timer timer; } Ipsctp_vtag_timewait; /* *=========================================================================== * IPSCTP INPUT PARA (IPSCTP INPUT PARAMETER) *=========================================================================== */ #define IPSCTP_MAX_CHUNK_IN_ONE_PKT 256 /*IPSCTP_MAX_BUNDLING*/ /* Parameters used when processing incoming SCTP packets */ typedef struct Ipsctp_input_param_struct { Ipcom_pkt *pkt; Ipsctp_tcb *tcb; Ipsctp_transport *transport; /* points to the path info of this packet */ Ipsctp_af_ops *af_ops; /* address family related operations */ Ip_u16 pkt_len; Ip_u16 remain_len; Ip_u8 *error_cause; Ip_u32 error_cause_len; /* actual error data length in error_cause */ Ip_u32 error_data_len; /* total buffer length of error_cause */ Ip_u32 error_code; /* error code notified to ULP */ Ip_u32 action; /* the action when return from input processing, * see IPSCTP_ACTION_SEND_ABORT */ IP_CONST void * dst_addr; IP_CONST void * src_addr; Ip_u16 src_port; /* Source (peer) TCP port */ Ip_u16 dst_port; /* Destination (local) TCP port */ Ip_bool free_packet; /* IP_TRUE if the packet should be freed */ #ifdef IPCOM_FORWARDER_NAE Ipcom_pkt *nae_rx_pkt[IPSCTP_MAX_CHUNK_IN_ONE_PKT]; /* [IPSCTP_MAX_BUNDLING]; */ /* Packet that should be delivered to the action/notifier */ int chunk_start[IPSCTP_MAX_CHUNK_IN_ONE_PKT]; int chunk_end[IPSCTP_MAX_CHUNK_IN_ONE_PKT]; int position; #endif } Ipsctp_input_param; #ifdef IPSCTP_DBGSTAT /* NOTE : please add string in ipsctp_dbgstat_ctl_str */ enum Ipsctp_debug_statistics_enmu { IPSCTP_DBGSTAT_BASE = 0, /* NOTE : please add string in ipsctp_dbgstat_ctl_str */ IPSCTP_DBGSTAT_SYS_SEND_INIT, IPSCTP_DBGSTAT_RESTART_AND_OPEN, IPSCTP_DBGSTAT_SEND_INIT_PIPE, IPSCTP_DBGSTAT_COOKIE_TIMER, IPSCTP_DBGSTAT_SEND_INIT_ERR, IPSCTP_DBGSTAT_RECV_INIT, IPSCTP_DBGSTAT_SEND_INIT_ACK, IPSCTP_DBGSTAT_RECV_INIT_ACK, IPSCTP_DBGSTAT_SEND_COOKIE_ECHO, IPSCTP_DBGSTAT_RECV_COOKIE_ECHO, IPSCTP_DBGSTAT_SEND_COOKIE_ACK, IPSCTP_DBGSTAT_RECV_COOKIE_ACK, IPSCTP_DBGSTAT_MAX /* NOTE : please add string in ipsctp_dbgstat_ctl_str */ }; IP_EXTERN IP_PUBLIC Ip_u32 ipsctp_debug_statistics[IPSCTP_DBGSTAT_MAX]; /* NOTE : no valid paremeter check. */ #define IPSCTP_DBGSTAT_INIT(enum_num) (ipsctp_debug_statistics[(Ip_u32)enum_num] = 0) #define IPSCTP_DBGSTAT_INC(enum_num) (ipsctp_debug_statistics[(Ip_u32)enum_num]++) #define IPSCTP_DBGSTAT_DEC(enum_num) (ipsctp_debug_statistics[(Ip_u32)enum_num]--) #define IPSCTP_DBGSTAT_GET(enum_num) (ipsctp_debug_statistics[(Ip_u32)enum_num]) #else #define IPSCTP_DBGSTAT_INIT(enum_num) IP_NOOP #define IPSCTP_DBGSTAT_INC(enum_num) IP_NOOP #define IPSCTP_DBGSTAT_DEC(enum_num) IP_NOOP #define IPSCTP_DBGSTAT_GET(enum_num) IP_NOOP #endif typedef struct Ipsctp_init_para_val_struct { Ip_u32 cookie_lifetime_inc; } Ipsctp_init_para_val; /* **************************************************************************** * 6 PUBLIC FUNCTIONS **************************************************************************** */ IP_PUBLIC unsigned ipsctp_tcb_obj_hash(Ipsctp_tcb *tcb); IP_PUBLIC unsigned ipsctp_tcb_key_hash(Ipsctp_tcb_lookup_key *key); IP_PUBLIC Ip_bool ipsctp_tcb_hash_cmp(Ipsctp_tcb *tcb, Ipsctp_tcb_lookup_key *key); IP_PUBLIC unsigned ipsctp_tcb_port_obj_hash(Ipsctp_tcb *tcb); IP_PUBLIC unsigned ipsctp_tcb_port_key_hash(Ipsctp_tcb_lookup_key *key); IP_PUBLIC Ip_bool ipsctp_tcb_port_hash_cmp(Ipsctp_tcb *tcb, Ipsctp_tcb_lookup_key *key); IP_PUBLIC unsigned ipsctp_vtag_timewait_obj_hash(Ipsctp_vtag_timewait *vtag_timewait); IP_PUBLIC unsigned ipsctp_vtag_timewait_key_hash(Ip_u32* vtag); IP_PUBLIC Ip_bool ipsctp_vtag_timewait_hash_cmp(Ipsctp_vtag_timewait *vtag_timewait, Ip_u32* vtag); /* *=========================================================================== * ipsctp_tcb_lookup *=========================================================================== * Description: Look up SCTP TCB based on given criteria. If vtag is non-zero, * search the hash table using vtag, and also check the local&peer * ports and addresses if necessary (TCB lookup optimization is off). * If vtag is zero, search the hash table using local&peer ports and * addresses. * Parameters: * Returns: Matched SCTP TCB and transport if existing, or NULL. * */ IP_PUBLIC Ipsctp_tcb * ipsctp_tcb_lookup( Ip_u32 vtag, /* local's verification tag */ Ip_u16 vr, /* the using virtual router */ int proto, /* protocol type */ IP_CONST void *local_addr, /* The local IPv4 address in network order, IP_NULL for any address */ Ip_u16 local_port, /* port in host order, 0 for any port.*/ IP_CONST void *peer_addr, /* The peer IPv4 address in network order, IP_NULL for any address */ Ip_u16 peer_port, /* port in host order, 0 for any port.*/ Ipsctp_af_ops *af_ops, /* Address Family related operations. */ Ipsctp_transport **transport /* transport matching the peer address, don't return transport if NULL */ ); IP_PUBLIC Ip_bool ipsctp_address_equal(IP_CONST Ipsctp_addr *addr1, IP_CONST Ipsctp_addr *addr2); IP_PUBLIC Ip_u32 ipsctp_select_tag(Ipsctp_tcb *tcb, Ip_u32 save_timewait); IP_PUBLIC Ip_s32 ipsctp_add_remote_addr(Ipsctp_tcb *tcb, IP_CONST Ipsctp_addr *addr, Ip_u32 addr_state, Ipsctp_transport **newtransport); IP_PUBLIC Ipsctp_param_hdr * ipsctp_get_next_param(Ip_u8 **inputbuf,Ip_u16 *remain_len); IP_PUBLIC Ipsctp_af_ops *ipsctp_get_af_ops(Ip_sa_family_t family); IP_PUBLIC int ipsctp_src_addr_selection(Ipsctp_tcb *tcb, Ipsctp_addr *dstaddr, Ipnet_route_entry *rt, Ip_u16 lport, Ipsctp_addr *srcaddr); IP_PUBLIC Ip_u32 ipsctp_addr_match_len(void *addr1, void *addr2, Ip_u32 lenofint); #ifdef IPSCTP_DEBUG IP_GLOBAL IP_CONST char * ipsctp_timer_to_str(Ipsctp_timo type); IP_GLOBAL IP_CONST char * ipsctp_notification_to_str(Ipsctp_notify_type type); #endif IP_PUBLIC void ipsctp_send_init_ack(Ipsctp_input_param *param, Ipsctp_chunk_hdr *init, Ipsctp_sctp_hdr *sctp_hdr_init); IP_PUBLIC void ipsctp_send_err(Ipsctp_input_param *param, Ip_u32 error_type, Ip_u8 *error_cause, Ip_u32 error_cause_len); IP_PUBLIC void ipsctp_notify_ulp(Ipsctp_notify_type type, Ipsctp_tcb *tcb, Ip_u32 err, void *cookie); IP_PUBLIC void ipsctp_init_para_processing(Ipsctp_input_param *param, Ip_u32 chunk_type, Ipsctp_init_chunk_hdr *init_chunk, Ipsctp_init_para_val *pval); IP_PUBLIC Ip_s32 ipsctp_send_cookie_echo(Ipsctp_tcb *stcb, Ipsctp_state_cookie *state_cookie, Ip_u32 state_cookie_len, Ipsctp_transport *transport); IP_PUBLIC Ip_s32 ipsctp_hmac(Ip_u16 mac_type, Ip_u8 *key, Ip_u16 key_size, void *data, Ip_u32 data_size, void *signature); IP_PUBLIC Ip_s32 ipsctp_hmac_get_sig_size(Ip_u16 mac_id); IP_PUBLIC Ip_s32 ipsctp_hmac_get_blk_size(Ip_u16 mac_id); IP_PUBLIC Ipsctp_socket * ipsctp_server_socket_new(Ipsctp_socket *listen_sock, IP_CONST void *local_addr, Ip_u16 local_port, IP_CONST void *peer_addr, Ip_u16 peer_port, Ipsctp_netif *netif, Ip_u16 vr, Ip_sa_family_t sa_family); IP_PUBLIC int ipsctp_set_primary_addr(Ipsctp_tcb *tcb, Ipsctp_addr *addr, Ipsctp_transport *transport, Ip_bool if_user, Ip_bool if_init); IP_PUBLIC int ipsctp_alloc_tcb(Ipsctp_instance* instance, /* pointer to instance */ Ipsctp_addr * addr, /* add this address to new created tcb */ Ip_u32 tag, /* choose a tag if 0, and use specified tag for non-0*/ Ipsctp_tcb **newtcb, /* TCB of the new created association */ Ipsctp_transport **newtransport /* the new created transport */ ); IP_PUBLIC void ipsctp_report_all_outbound(Ipsctp_tcb *tcb); IP_PUBLIC int ipsctp_free_tcb(Ipsctp_tcb *tcb /* TCB to be freed */ ); IP_PUBLIC Ipsctp_tcb * ipsctp_tcb_lookup_by_instance( Ipsctp_instance* instance, /* pointer to instance */ Ip_u32 vtag, /* local's verification tag, 0 for unspecified */ IP_CONST Ipsctp_addr *peer_soaddr,/* The peer socket address, IP_NULL for unspecified */ Ipsctp_transport **transport_ret /* transport matching the peer address, don't return transport if NULL */ ); IP_PUBLIC Ipsctp_chunk * ipsctp_alloc_chunk(Ipsctp_tcb *tcb, Ip_u32 len); IP_PUBLIC void ipsctp_set_error(Ipsctp_input_param *param, Ip_u16 error_type, void *error_info); IP_PUBLIC int ipsctp_send_abort(Ipcom_pkt *pkt_in, Ipsctp_sctp_hdr *hdr, Ipsctp_vtag vtag, Ip_u8 *error_cause, Ip_u32 error_cause_len); IP_PUBLIC int ipsctp_send_OOTB_shutcompl(Ipcom_pkt *pkt_in, Ipsctp_sctp_hdr *hdr); IP_PUBLIC int ipsctp_send_shutdown(Ipsctp_tcb *tcb, Ipsctp_transport *tp); IP_PUBLIC int ipsctp_send_shutdown_complete(Ipsctp_tcb *tcb); IP_PUBLIC int ipsctp_send_shutdown_ack(Ipsctp_tcb *tcb, Ipsctp_transport *tp); IP_PUBLIC int ipsctp_handle_abort(Ipsctp_input_param *param, Ipsctp_chunk_hdr *ch); IP_PUBLIC int ipsctp_handle_abort_for_icmp(Ipsctp_tcb *tcb); #if 0/* no use in SCTP */ IP_PUBLIC void ipsctp_abort_assoc(Ipcom_pkt *pkt_in, Ipsctp_sctp_hdr *hdr, Ip_u8 *error_cause, Ip_u32 error_cause_len); #endif IP_PUBLIC void ipsctp_abort_assoc_tcb(Ipsctp_tcb *tcb, int ab_err, Ip_u8 *error_cause, Ip_u32 error_cause_len); IP_PUBLIC void ipsctp_abort_assoc_tcb_with_err(Ipsctp_tcb *tcb, int ab_err, Ip_u16 ca_type, Ip_u32 ca_data); IP_PUBLIC Ip_s32 ipsctp_create_output_seg(Ipsctp_tcb *tcb, Ip_bool msg_more); IP_PUBLIC void ipsctp_send_sack(Ipsctp_tcb *tcb); IP_PUBLIC int ipsctp_send_heartbeat(Ipsctp_tcb *tcb, Ipsctp_transport *tp); IP_PUBLIC int ipsctp_send_heartbeat_ack(Ipsctp_tcb *tcb, Ipsctp_transport *tp, Ipsctp_hb_chunk_hdr *in_ch); IP_PUBLIC Ip_u32 ipsctp_calc_rto(Ipsctp_tcb *tcb, Ipsctp_transport *transport, struct Ip_timeval *tv); IP_PUBLIC Ip_u8 * ipsctp_get_error_cause_space(Ipsctp_input_param *param, Ip_u16 len); IP_PUBLIC void ipsctp_stop_timers_for_shutdown(Ipsctp_tcb *tcb); IP_PUBLIC int ipsctp_change_state(Ipsctp_tcb *tcb, Ipsctp_state new_state); IP_PUBLIC void ipsctp_timer_add(Ipsctp_instance *inst, Ipsctp_tcb *tcb, Ipsctp_transport *transport, Ipsctp_timo type); IP_PUBLIC void ipsctp_timer_remove(Ipsctp_instance *inst, Ipsctp_tcb *tcb, Ipsctp_transport *transport, Ipsctp_timo type); IP_PUBLIC void ipsctp_stop_all_cookie_timers(Ipsctp_tcb *tcb); IP_PUBLIC Ipsctp_chunk_hdr * ipsctp_get_next_ctrl_chunk(void ** inputbuf, Ip_u16 *remain_len); IP_PUBLIC Ipsctp_chunk_hdr * ipsctp_get_next_chunk(void ** inputbuf, Ip_u16 *remain_len); IP_PUBLIC int ipsctp_queue_chunk_op_err(Ipsctp_tcb *tcb, Ip_u16 param_type, Ip_u8 *data, Ip_u16 data_len); IP_PUBLIC void ipsctp_queue_chunk_mult_errs(Ipsctp_tcb *stcb, void *errs_buf, Ip_u32 errs_buf_len); IP_PUBLIC Ip_u32 ipsctp_calc_rwnd(Ipsctp_tcb *tcb); IP_PUBLIC Ip_bool ipsctp_is_known_chunk(Ip_u8 type); IP_PUBLIC int ipsctp_sack_check(Ipsctp_tcb *tcb, Ip_bool gap_existed, Ip_bool send_sack); IP_PUBLIC void ipsctp_v4_init(void); IP_PUBLIC void ipsctp_register_af(Ipsctp_af_ops *sctp_af); IP_PUBLIC Ipsctp_transport * ipsctp_transport_lookup(Ipsctp_tcb * tcb, /* TCB of the association */ IP_CONST Ipsctp_addr *peer_soaddr); /* The peer socket address */ IP_PUBLIC Ipsctp_transport * ipsctp_alt_transport_lookup( Ipsctp_tcb * tcb, /* TCB of the association */ Ipsctp_transport *transport /* The SCTP transport */ ); IP_PUBLIC void ipsctp_send_cookie_ack(Ipsctp_tcb *stcb); IP_PUBLIC void ipsctp_v6_init(void); IP_PUBLIC void ipsctp_free_in_stream(Ipsctp_tcb *tcb, Ipsctp_stream_in *streams_in); IP_PUBLIC void ipsctp_free_out_stream(Ipsctp_tcb *tcb, Ipsctp_stream_out *streams_out); IP_PUBLIC void ipsctp_init_in_stream(Ipsctp_tcb *tcb, Ipsctp_stream_in *streams_out, Ip_u16 stream_number); IP_PUBLIC int ipsctp_threshold_management(Ipsctp_tcb *tcb, Ipsctp_transport *transport, Ip_u16 threshold); IP_PUBLIC Ip_s32 ipsctp_send_init(Ipsctp_tcb *stcb); IP_PUBLIC void ipsctp_sin_v4_map_v6(void *v4, void *v6); IP_PUBLIC Ip_bool ipsctp_is_output_queue_empty(Ipsctp_tcb *tcb); #ifdef IPSCTP_DEBUG IP_PUBLIC const char * ipsctp_addr_ntop(Ipsctp_addr *addr, char *dst, int len); #endif IP_PUBLIC int ipsctp_alloc_dummy_tcb(Ipsctp_instance* instance, Ipsctp_tcb **newtcb); IP_PUBLIC Ip_u32 ipsctp_log3int(Ip_u32 priority, Ip_u32 debug_flag, const char *format, int line, int a, int b); IP_PUBLIC void ipsctp_notify_cb(Ipsctp_tcb *tcb, Ipsctp_transport *transport, int event); IP_PUBLIC Ip_u32 ipsctp_time_now(void); IP_PUBLIC void ipsctp_tx_segments(Ipsctp_tcb *tcb); IP_PUBLIC int ipsctp_handle_sendall(Ipsctp_tcb *tcb, struct Ipsctp_sndrcvinfo *sndrcv, Ipcom_pkt *pkt, Ip_bool snd_btypes_check_flag); /*+++++++++ ipsctp_sock.c +++++++++*/ IP_PUBLIC void ipsctp_server_remove_from_backlog(Ipsctp_socket *listen_sock, Ipsctp_socket *sock, Ip_bool from_done); IP_PUBLIC void ipsctp_server_handshake_done(Ipsctp_socket *sock); IP_PUBLIC void ipsctp_sock_cleanup(Ipsctp_socket *sock); IP_PUBLIC void ipsctp_sock_kclose(Ipsctp_socket *sock); IP_GLOBAL int ipsctp_drop_tcb(Ipsctp_tcb *tcb, int error_code); IP_PUBLIC void ipsctp_close_association(Ipsctp_tcb *tcb); IP_PUBLIC Ipsctp_tcb * ipsctp_sock_lookup_da(Ipsctp_socket *sock, struct Ip_sockaddr *dst_addr); /*+++++++++ ipsctp_debug.c +++++++++*/ #ifdef IPSCTP_DEBUG IP_PUBLIC void ipsctp_print_hex(void *buf, const char *prompt, Ip_u32 len); IP_GLOBAL IP_CONST char * ipsctp_state_to_str(int state); IP_PUBLIC Ip_u32 ipsctp_show_buffer(Ipsctp_socket *sock); #endif #ifdef IPNET_DEBUG IP_GLOBAL int ipsctp_tick_to_string(void *unused, char *buf, Ip_size_t buf_len); #endif #ifdef __cplusplus } #endif #endif /* IPSCTP_H_H */