25163 lines
1.3 MiB
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
*********************************************************************************************************
* uC/TCP-IP
* The Embedded TCP/IP Suite
*
* (c) Copyright 2003-2007; Micrium, Inc.; Weston, FL
*
* All rights reserved. Protected by international copyright laws.
*
* uC/TCP-IP is provided in source form for FREE evaluation, for educational
* use or peaceful research. If you plan on using uC/TCP-IP in a commercial
* product you need to contact Micrium to properly license its use in your
* product. We provide ALL the source code for your convenience and to help
* you experience uC/TCP-IP. The fact that the source code is provided does
* NOT mean that you can use it without paying a licensing fee.
*
* Knowledge of the source code may NOT be used to develop a similar product.
*
* Please help us continue to provide the Embedded community with the finest
* software available. Your honesty is greatly appreciated.
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* NETWORK TCP LAYER
* (TRANSMISSION CONTROL PROTOCOL)
*
* Filename : net_tcp.c
* Version : V1.89
* Programmer(s) : ITJ
*********************************************************************************************************
* Note(s) : (1) Supports Transmission Control Protocol as described in RFC #793 with the following
* restrictions/constraints :
*
* (a) TCP Security & Precedence NOT supported RFC # 793, Section 3.6
*
* (b) TCP Urgent Data NOT supported RFC # 793, Section 3.7
* 'The Communication of
* Urgent Information'
*
* (c) The following TCP options NOT supported :
*
* (1) Window Scale RFC #1072, Section 2
* RFC #1323, Section 2
* (2) Selective Acknowledgement (SACK) RFC #1072, Section 3
* RFC #2018
* RFC #2883
* (3) TCP Echo RFC #1072, Section 4
* (4) Timestamp RFC #1323, Section 3.2
* (5) Protection Against Wrapped Sequences (PAWS) RFC #1323, Section 4
*
* (d) #### IP-Options-to-TCP-Connection RFC #1122, Section 4.2.3.8
* Handling NOT supported
*
* (e) #### ICMP-Error-Message-to-TCP-Connection RFC #1122, Section 4.2.3.9
* Handling NOT currently supported
*
* (2) TCP Layer assumes/requires Network Socket Layer (see 'net_sock.h MODULE Note #1a2').
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#define NET_TCP_MODULE
#include <net.h>
/*
*********************************************************************************************************
* MODULE
*
* Note(s) : (1) See 'net_tcp.h MODULE'.
*********************************************************************************************************
*/
#ifdef NET_TCP_MODULE_PRESENT
/*$PAGE*/
/*
*********************************************************************************************************
* LOCAL DEFINES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* TCP CONNECTION CONFIGURATION CODE DEFINES
*
* Note(s) : (1) (a) TCP connection configuration codes used as arguments for various NetTCP_ConnCfg() functions.
*
* (b) TCP connection configuration codes bit-field flags logically OR'd.
*********************************************************************************************************
*/
#define NET_TCP_CONN_CFG_NONE DEF_BIT_NONE
#define NET_TCP_CONN_CFG_MAX_SEG_SIZE_LOCAL DEF_BIT_00
#define NET_TCP_CONN_CFG_MAX_SEG_SIZE_REMOTE DEF_BIT_01
#define NET_TCP_CONN_CFG_MAX_SEG_SIZE_CONN DEF_BIT_02
#define NET_TCP_CONN_CFG_MAX_SEG_SIZE_ALL (NET_TCP_CONN_CFG_MAX_SEG_SIZE_LOCAL | \
NET_TCP_CONN_CFG_MAX_SEG_SIZE_REMOTE | \
NET_TCP_CONN_CFG_MAX_SEG_SIZE_CONN )
#define NET_TCP_CONN_CFG_MAX_SEG_SIZE_MASK NET_TCP_CONN_CFG_MAX_SEG_SIZE_ALL
#define NET_TCP_CONN_CFG_WIN_SIZE_RX DEF_BIT_02
#define NET_TCP_CONN_CFG_WIN_SIZE_TX DEF_BIT_03
#define NET_TCP_CONN_CFG_WIN_SIZE_CONN (NET_TCP_CONN_CFG_WIN_SIZE_RX | \
NET_TCP_CONN_CFG_WIN_SIZE_TX )
#define NET_TCP_CONN_CFG_WIN_SIZE_ALL NET_TCP_CONN_CFG_WIN_SIZE_CONN
#define NET_TCP_CONN_CFG_WIN_SIZE_MASK NET_TCP_CONN_CFG_WIN_SIZE_ALL
#define NET_TCP_CONN_CFG_TX_RTT_RTO DEF_BIT_04
#define NET_TCP_CONN_CFG_ALL (NET_TCP_CONN_CFG_NONE | \
NET_TCP_CONN_CFG_MAX_SEG_SIZE_ALL | \
NET_TCP_CONN_CFG_WIN_SIZE_ALL | \
NET_TCP_CONN_CFG_TX_RTT_RTO )
/*$PAGE*/
/*
*********************************************************************************************************
* TCP CONNECTION CLOSE/FREE CODE DEFINES
*
* Note(s) : (1) (a) TCP connection close codes used as arguments for various NetTCP_ConnClose() functions.
*
* (b) TCP connection close codes bit-field flags logically OR'd.
*
* (2) Available TCP connection free codes are identical to TCP connection close codes.
*********************************************************************************************************
*/
#define NET_TCP_CONN_CLOSE_NONE DEF_BIT_NONE
#define NET_TCP_CONN_CLOSE_CONN_NONE DEF_BIT_NONE
#define NET_TCP_CONN_CLOSE_CONN_TX_RESET DEF_BIT_00
#define NET_TCP_CONN_CLOSE_CONN_ALL (NET_TCP_CONN_CLOSE_CONN_NONE | \
NET_TCP_CONN_CLOSE_CONN_TX_RESET)
#define NET_TCP_CONN_CLOSE_CONN_MASK NET_TCP_CONN_CLOSE_CONN_ALL
#define NET_TCP_CONN_CLOSE_TMR_NONE DEF_BIT_NONE
#define NET_TCP_CONN_CLOSE_TMR_TX_IDLE DEF_BIT_04
#define NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN DEF_BIT_05
#define NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN DEF_BIT_06
#define NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY DEF_BIT_07
#define NET_TCP_CONN_CLOSE_TMR_RE_TX DEF_BIT_08
#define NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE DEF_BIT_09
#define NET_TCP_CONN_CLOSE_TMR_TIMEOUT DEF_BIT_10
#define NET_TCP_CONN_CLOSE_TMR_ALL (NET_TCP_CONN_CLOSE_TMR_NONE | \
NET_TCP_CONN_CLOSE_TMR_TX_IDLE | \
NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN | \
NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN | \
NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY | \
NET_TCP_CONN_CLOSE_TMR_RE_TX | \
NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE | \
NET_TCP_CONN_CLOSE_TMR_TIMEOUT )
#define NET_TCP_CONN_CLOSE_TMR_MASK NET_TCP_CONN_CLOSE_TMR_ALL
#define NET_TCP_CONN_CLOSE_ALL (NET_TCP_CONN_CLOSE_NONE | \
NET_TCP_CONN_CLOSE_CONN_ALL | \
NET_TCP_CONN_CLOSE_TMR_ALL )
#define NET_TCP_CONN_FREE_NONE NET_TCP_CONN_CLOSE_NONE
#define NET_TCP_CONN_FREE_TMR_NONE NET_TCP_CONN_CLOSE_TMR_NONE
#define NET_TCP_CONN_FREE_TMR_TX_IDLE NET_TCP_CONN_CLOSE_TMR_TX_IDLE
#define NET_TCP_CONN_FREE_TMR_TX_SILLY_WIN NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN
#define NET_TCP_CONN_FREE_TMR_TX_ZERO_WIN NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN
#define NET_TCP_CONN_FREE_TMR_TX_ACK_DLY NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY
#define NET_TCP_CONN_FREE_TMR_RE_TX NET_TCP_CONN_CLOSE_TMR_RE_TX
#define NET_TCP_CONN_FREE_TMR_KEEP_ALIVE NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE
#define NET_TCP_CONN_FREE_TMR_TIMEOUT NET_TCP_CONN_CLOSE_TMR_TIMEOUT
#define NET_TCP_CONN_FREE_TMR_ALL NET_TCP_CONN_CLOSE_TMR_ALL
#define NET_TCP_CONN_FREE_TMR_MASK NET_TCP_CONN_CLOSE_TMR_MASK
#define NET_TCP_CONN_FREE_ALL NET_TCP_CONN_CLOSE_ALL
/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/
/*$PAGE*/
/*
*********************************************************************************************************
* LOCAL DATA TYPES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* TCP SEQUENCE CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT08U NET_TCP_SEQ_CODE;
/*
*********************************************************************************************************
* TCP ACKNOWLEDGEMENT CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT08U NET_TCP_ACK_CODE;
/*
*********************************************************************************************************
* TCP CONNECTION RESET CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT08U NET_TCP_RESET_CODE;
/*
*********************************************************************************************************
* TCP WINDOW CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT08U NET_TCP_WIN_CODE;
/*
*********************************************************************************************************
* TCP CALCULATION CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT08U NET_TCP_CALC_CODE;
/*
*********************************************************************************************************
* TCP CONFIGURATION CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT08U NET_TCP_CFG_CODE;
/*
*********************************************************************************************************
* TCP CLOSE CODE DATA TYPE
*********************************************************************************************************
*/
typedef CPU_INT16U NET_TCP_CLOSE_CODE;
/*
*********************************************************************************************************
* TCP FREE CODE DATA TYPE
*********************************************************************************************************
*/
typedef NET_TCP_CLOSE_CODE NET_TCP_FREE_CODE;
/*
*********************************************************************************************************
* LOCAL TABLES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/
/*$PAGE*/
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
/* --------- RX FNCTS --------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static void NetTCP_RxPktValidateBuf (NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
#endif
static void NetTCP_RxPktValidate (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_HDR *ptcp_hdr,
NET_ERR *perr);
static void NetTCP_RxPktValidateOpt (NET_BUF_HDR *pbuf_hdr,
NET_TCP_HDR *ptcp_hdr,
CPU_INT08U tcp_hdr_len_size,
NET_ERR *perr);
static CPU_BOOLEAN NetTCP_RxPktValidateOptMaxSegSize (NET_BUF_HDR *pbuf_hdr,
CPU_INT08U *popt,
CPU_INT08U *popt_len,
NET_ERR *perr);
static void NetTCP_RxPktDemuxSeg (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandler (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerListen (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerSyncRxd (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerSyncTxd (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerConn (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerFinWait1 (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerFinWait2 (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerClosing (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerTimeWait (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerCloseWait (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerLastAck (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
/*$PAGE*/
static void NetTCP_RxPktConnHandlerSeg (NET_TCP_CONN *pconn,
NET_TCP_ACK_CODE ack_code,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerCfgConn (NET_TCP_CONN *pconn);
static void NetTCP_RxPktConnHandlerRxQ_Sync (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerRxQ_Conn (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerRxQ_AppData (NET_TCP_CONN *pconn,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerTxWinRemote (NET_TCP_CONN *pconn,
NET_TCP_ACK_CODE ack_code,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerReTxQ (NET_TCP_CONN *pconn,
NET_TCP_ACK_CODE ack_code,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static CPU_BOOLEAN NetTCP_RxPktConnHandlerListenQ_IsAvail(NET_TCP_CONN *pconn,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerSignalConn (NET_TCP_CONN *pconn,
NET_TCP_CONN_STATE state,
NET_ERR *perr);
static void NetTCP_RxPktConnHandlerSignalClose (NET_TCP_CONN *pconn,
CPU_BOOLEAN data_avail,
NET_ERR *perr);
static NET_TCP_SEQ_CODE NetTCP_RxPktConnIsValidSeq (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static NET_TCP_ACK_CODE NetTCP_RxPktConnIsValidAck (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static NET_TCP_RESET_CODE NetTCP_RxPktConnIsValidReset (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_RxPktFree (NET_BUF *pbuf_q);
static void NetTCP_RxPktDiscard (NET_BUF *pbuf,
NET_ERR *perr);
static void NetTCP_RxConnWinSizeCfg (NET_TCP_CONN *pconn);
static void NetTCP_RxConnWinSizeCfgUpdateTh (NET_TCP_CONN *pconn);
static void NetTCP_RxConnWinSizeHandler (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_update_code);
/*$PAGE*/
/* --------- TX FNCTS --------- */
static void NetTCP_TxConnWinSizeCfg (NET_TCP_CONN *pconn);
static void NetTCP_TxConnWinSizeCfgCongCtrl (NET_TCP_CONN *pconn);
static void NetTCP_TxConnWinSizeCfgMinTh (NET_TCP_CONN *pconn);
static void NetTCP_TxConnWinSizeHandlerCfgd (NET_TCP_CONN *pconn,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_update_code,
NET_ERR *perr);
static void NetTCP_TxConnWinSizeHandlerCongCtrl (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_ACK_CODE ack_code,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_update_code,
NET_ERR *perr);
static void NetTCP_TxConnWinSizeCalcSlowStartTh (NET_TCP_CONN *pconn);
static void NetTCP_TxConnWinSizeCongSet (NET_TCP_CONN *pconn,
NET_TCP_WIN_CODE win_inc_code);
static void NetTCP_TxConnWinSizeCongInc (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_inc_code);
static void NetTCP_TxConnWinSizeUpdateAvail (NET_TCP_CONN *pconn);
static void NetTCP_TxConnWinSizeDupAckCtrlReset (NET_TCP_CONN *pconn);
static void NetTCP_TxConnWinSizeDupAckCtrlUpdate (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
CPU_BOOLEAN reset_ctr);
static void NetTCP_TxConnWinSizeZeroWinHandler (NET_TCP_CONN *pconn,
NET_TCP_WIN_CODE win_update_code,
NET_TCP_CLOSE_CODE close_code);
static void NetTCP_TxConnWinSizeZeroWinTimeout (void *pconn_timeout);
/*$PAGE*/
static void NetTCP_TxConnSync (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr);
static void NetTCP_TxConnClose (NET_TCP_CONN *pconn,
NET_ERR *perr);
static void NetTCP_TxConnAck (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_ACK_CODE tx_ack_code,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr);
static void NetTCP_TxConnAckDlyReset (NET_TCP_CONN *pconn,
CPU_BOOLEAN tmr_free);
static void NetTCP_TxConnAckDlyTimeout (void *pconn_timeout);
static void NetTCP_TxConnReset (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_RESET_CODE tx_reset_code,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr);
static void NetTCP_TxConnProbe (NET_TCP_CONN *pconn,
CPU_BOOLEAN tx_probe_data_octet,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr);
static void NetTCP_TxConnTxQ (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_ACK_CODE tx_ack_code,
CPU_BOOLEAN tx_q_timeout,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr);
static void NetTCP_TxConnTxQ_TimeoutIdle (void *pconn_timeout);
static void NetTCP_TxConnTxQ_TimeoutIdleSet (NET_TCP_CONN *pconn);
static void NetTCP_TxConnTxQ_TimeoutIdleClr (NET_TCP_CONN *pconn);
static void NetTCP_TxConnTxQ_TimeoutSillyWin (void *pconn_timeout);
static void NetTCP_TxConnReTxQ (NET_TCP_CONN *pconn,
CPU_BOOLEAN re_tx_q_timeout,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr);
static void NetTCP_TxConnReTxQ_Timeout (void *pconn_timeout);
static void NetTCP_TxConnReTxQ_TimeoutSet (NET_TCP_CONN *pconn,
CPU_BOOLEAN re_tx_q_timeout,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr);
static void NetTCP_TxConnPrepareSegAddrs (NET_TCP_CONN *pconn,
CPU_INT08U *psrc_port,
CPU_INT08U *psrc_addr,
CPU_INT16U src_port_len,
CPU_INT16U src_addr_len,
CPU_INT08U *pdest_port,
CPU_INT08U *pdest_addr,
CPU_INT16U dest_port_len,
CPU_INT16U dest_addr_len,
NET_ERR *perr);
/*$PAGE*/
static void NetTCP_TxConnRTT_Init (NET_TCP_CONN *pconn);
static void NetTCP_TxConnRTT_Reset (NET_TCP_CONN *pconn);
static void NetTCP_TxConnRTT_CalcUpdate (NET_TCP_CONN *pconn);
static void NetTCP_TxConnRTO_Init (NET_TCP_CONN *pconn);
static void NetTCP_TxConnRTO_CfgMaxTimeout (NET_TCP_CONN *pconn);
static void NetTCP_TxConnRTO_CalcUpdate (NET_TCP_CONN *pconn);
static NET_TCP_TIMEOUT_MS NetTCP_TxConnRTO_CalcBackOff (NET_TCP_CONN *pconn,
NET_TCP_TIMEOUT_MS rto_ms);
static void NetTCP_TxConnRTT_RTO_Init (NET_TCP_CONN *pconn);
static void NetTCP_TxConnRTT_RTO_Calc (NET_TCP_CONN *pconn,
NET_TCP_CALC_CODE calc_code,
NET_TCP_TX_RTT_TS_MS rtt_ts_txd_ms,
NET_TCP_TX_RTT_TS_MS rtt_ts_rxd_ms);
static void NetTCP_TxPktHandler (NET_BUF *pbuf,
NET_IP_ADDR src_addr,
NET_TCP_PORT_NBR src_port,
NET_IP_ADDR dest_addr,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
NET_IP_TOS TOS,
NET_IP_TTL TTL,
CPU_INT16U flags_tcp,
CPU_INT16U flags_ip,
void *popts_tcp,
void *popts_ip,
NET_ERR *perr);
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static void NetTCP_TxPktValidate (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_PORT_NBR src_port,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
CPU_INT16U flags_tcp,
void *popts_tcp,
NET_ERR *perr);
static void NetTCP_TxPktValidateOpt (void *popts_tcp,
CPU_INT16U flags_tcp,
NET_ERR *perr);
static void NetTCP_TxPktValidateOptMaxSegSize (void *popt_tcp,
CPU_INT08U *popt_len,
void **popt_next,
CPU_INT16U flags_tcp,
NET_ERR *perr);
#endif
/*$PAGE*/
static void NetTCP_TxPkt (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_IP_ADDR src_addr,
NET_TCP_PORT_NBR src_port,
NET_IP_ADDR dest_addr,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
NET_IP_TOS TOS,
NET_IP_TTL TTL,
CPU_INT16U flags_tcp,
CPU_INT16U flags_ip,
void *popts_tcp,
void *popts_ip,
NET_ERR *perr);
static CPU_INT08U NetTCP_TxPktPrepareOpt (void *popts_tcp,
CPU_INT08U *popt_hdr,
NET_ERR *perr);
static void NetTCP_TxPktPrepareOptMaxSegSize (void *popts_tcp,
CPU_INT08U *popt_hdr,
CPU_INT08U *popt_len,
void **popt_next,
NET_ERR *perr);
static void NetTCP_TxPktPrepareHdr (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
CPU_INT16U tcp_hdr_len_tot,
CPU_INT08U tcp_opt_len_tot,
NET_IP_ADDR src_addr,
NET_TCP_PORT_NBR src_port,
NET_IP_ADDR dest_addr,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
CPU_INT16U flags_tcp,
CPU_INT32U *ptcp_hdr_opts,
NET_ERR *perr);
static void NetTCP_TxPktFree (NET_BUF *pbuf_q);
static void NetTCP_TxPktDiscard (NET_BUF *pbuf,
NET_ERR *perr);
/*$PAGE*/
/* ------ TCP CONN FNCTS ------ */
static void NetTCP_ConnCfg (NET_TCP_CONN *pconn,
NET_TCP_CFG_CODE cfg_code);
static void NetTCP_ConnCfgMaxSegSize (NET_TCP_CONN *pconn);
static void NetTCP_ConnClose (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
CPU_BOOLEAN close_conn_app,
NET_TCP_CLOSE_CODE close_code);
static void NetTCP_ConnCloseHandler (NET_TCP_CONN *pconn,
CPU_BOOLEAN close_conn_app,
NET_TCP_CLOSE_CODE close_code);
static void NetTCP_ConnCloseTimeout (void *pconn_timeout);
static void NetTCP_ConnClosingTimeoutDataAvail (void *pconn_timeout);
static void NetTCP_ConnFreeHandler (NET_TCP_CONN *pconn,
NET_TCP_FREE_CODE free_code);
static void NetTCP_ConnFreeTmr (NET_TCP_CONN *pconn,
NET_TCP_FREE_CODE free_code);
static void NetTCP_ConnFreeBufQ (NET_BUF **pbuf_q_head,
NET_BUF **pbuf_q_tail);
static void NetTCP_ConnClr (NET_TCP_CONN *pconn);
static void NetTCP_ConnCopy (NET_TCP_CONN *pconn_dest,
NET_TCP_CONN *pconn_src);
static void NetTCP_ConnDiscard (NET_TCP_CONN *pconn);
/*
*********************************************************************************************************
* LOCAL CONFIGURATION ERRORS
*********************************************************************************************************
*/
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_Init()
*
* Description : (1) Initialize Transmission Control Protocol Layer :
*
* (a) Perform TCP Module/OS initialization
* (b) Perform TCP Module/BSP initialization
* (c) Initialize TCP connection pool
* (d) Initialize TCP connection table
* (e) Initialize TCP statistics & error counters
*
*
* Argument(s) : perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP layer successfully initialized.
*
* - RETURNED BY NetOS_TCP_Init() : --
* NET_OS_ERR_INIT_TCP_RX_Q TCP receive queue(s) NOT
* successfully initialized.
* NET_OS_ERR_INIT_TCP_RX_Q_TIMEOUT TCP receive queue timeout(s) NOT
* successfully configured.
* NET_OS_ERR_INIT_TCP_TX_Q TCP transmit queue(s) NOT
* successfully initialized.
* NET_OS_ERR_INIT_TCP_TX_Q_TIMEOUT TCP transmit queue timeout(s) NOT
* successfully configured.
*
* Return(s) : none.
*
* Caller(s) : Net_Init().
*
* This function is an INTERNAL network protocol suite function & MUST NOT be called by
* application function(s).
*
* Note(s) : (2) TCP connection pool MUST be initialized PRIOR to initializing the pool with pointers to
* TCP connections.
*********************************************************************************************************
*/
void NetTCP_Init (NET_ERR *perr)
{
NET_TCP_CONN *pconn;
NET_TCP_CONN_QTY i;
NET_ERR stat_err;
/* --------------- PERFORM TCP/OS INIT --------------- */
NetOS_TCP_Init(perr); /* Create TCP obj(s). */
if (*perr != NET_OS_ERR_NONE) {
return;
}
/* --------------- PERFORM TCP/BSP INIT --------------- */
NetTCP_InitTxSeqNbr(); /* Init tx seq nbr ctr. */
/* ------------- INIT TCP CONN POOL/STATS ------------- */
NetTCP_ConnPoolPtr = (NET_TCP_CONN *)0; /* Init-clr TCP conn pool (see Note #2). */
NetStat_PoolInit((NET_STAT_POOL *)&NetTCP_ConnPoolStat,
(NET_STAT_POOL_QTY) NET_TCP_CFG_NBR_CONN,
(NET_ERR *)&stat_err);
/* ---------------- INIT TCP CONN TBL ----------------- */
pconn = &NetTCP_ConnTbl[0];
for (i = 0; i < NET_TCP_CFG_NBR_CONN; i++) {
pconn->Type = NET_TCP_TYPE_CONN; /* Init each TCP conn type/id--NEVER modify. */
pconn->ID = (NET_TCP_CONN_ID)i;
pconn->ConnState = NET_TCP_CONN_STATE_FREE; /* Init each TCP conn as free/NOT used. */
pconn->Flags = NET_TCP_FLAG_NONE;
#if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED)
NetTCP_ConnClr(pconn);
#endif
/* Free each TCP conn to TCP conn pool (see Note #2). */
pconn->NextPtr = (void *)NetTCP_ConnPoolPtr;
NetTCP_ConnPoolPtr = (NET_TCP_CONN *)pconn;
pconn++;
}
/*$PAGE*/
/* ------------- INIT TCP STAT & ERR CTRS ------------- */
#if (NET_CTR_CFG_STAT_EN == DEF_ENABLED)
NetTCP_StatRxPktCtr = 0;
NetTCP_StatRxSegProcessedCtr = 0;
NetTCP_StatTxSegCtr = 0;
NetTCP_StatTxSegConnSyncCtr = 0;
NetTCP_StatTxSegConnCloseCtr = 0;
NetTCP_StatTxSegConnAckCtr = 0;
NetTCP_StatTxSegConnResetCtr = 0;
NetTCP_StatTxSegConnProbeCtr = 0;
NetTCP_StatTxSegConnTxQ_Ctr = 0;
NetTCP_StatTxSegConnReTxQ_Ctr = 0;
#endif
#if (NET_CTR_CFG_ERR_EN == DEF_ENABLED)
NetTCP_ErrNullPtrCtr = 0;
NetTCP_ErrNoneAvailCtr = 0;
NetTCP_ErrNotUsedCtr = 0;
NetTCP_ErrRxHdrLenCtr = 0;
NetTCP_ErrRxHdrSegLenCtr = 0;
NetTCP_ErrRxHdrPortSrcCtr = 0;
NetTCP_ErrRxHdrPortDestCtr = 0;
NetTCP_ErrRxHdrFlagsCtr = 0;
NetTCP_ErrRxHdrChkSumCtr = 0;
NetTCP_ErrRxHdrOptsCtr = 0;
NetTCP_ErrRxDestCtr = 0;
NetTCP_ErrRxPktDiscardedCtr = 0;
NetTCP_ErrTxOptTypeCtr = 0;
NetTCP_ErrTxPktDiscardedCtr = 0;
NetTCP_ErrConnInvalidCtr = 0;
NetTCP_ErrConnInvalidOpCtr = 0;
NetTCP_ErrConnInvalidStateCtr = 0;
NetTCP_ErrConnCloseCtr = 0;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NetTCP_ErrRxInvalidBufIxCtr = 0;
NetTCP_ErrRxHdrDataLenCtr = 0;
NetTCP_ErrTxInvalidProtocolCtr = 0;
NetTCP_ErrTxInvalidSizeCtr = 0;
NetTCP_ErrTxInvalidBufIxCtr = 0;
NetTCP_ErrTxHdrDataLenCtr = 0;
NetTCP_ErrTxHdrPortSrcCtr = 0;
NetTCP_ErrTxHdrPortDestCtr = 0;
NetTCP_ErrTxHdrFlagsCtr = 0;
NetTCP_ErrTxHdrOptLenCtr = 0;
NetTCP_ErrTxHdrOptCfgCtr = 0;
NetTCP_ErrConnInvalidTypeCtr = 0;
#endif
#endif
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_Rx()
*
* Description : (1) Process received segments & demultiplex to socket or application layer connection :
*
* (a) Validate TCP packet
* (b) Demultiplex TCP packet to TCP connection
* (c) Handle/Process TCP segment
* (d) Return TCP error code(s)
*
* (2) Although TCP data units are typically referred to as 'segments' (see RFC #793, Section 3.1),
* the term 'TCP packet' (see RFC #1983, 'packet') is used for TCP Receive until the packet is
* validated as a TCP segment.
*
*
* Argument(s) : pbuf Pointer to network buffer that received TCP packet.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP segment successfully received & processed.
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* ---- RETURNED BY NetTCP_RxPktDiscard() : -----
* NET_ERR_RX Receive error; packet discarded.
*
* Return(s) : none.
*
* Caller(s) : NetIP_RxPktDemuxDatagram().
*
* This function is an INTERNAL network protocol suite function & MUST NOT be called by
* application function(s).
*
* Note(s) : (3) NetTCP_Rx() blocked until network initialization completes.
*
* (4) TCP receive statistics updated in NetTCP_RxPktConnHandler(); do NOT re-update.
*
* (a) Network buffer already freed & error counter already incremented in previous
* function(s).
*
* See also 'NetTCP_RxPktConnHandler() Note #2'.
*********************************************************************************************************
*/
/*$PAGE*/
void NetTCP_Rx (NET_BUF *pbuf,
NET_ERR *perr)
{
#if ((((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) || \
(NET_CTR_CFG_STAT_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_BUF_HDR *pbuf_hdr;
NET_TCP_HDR *ptcp_hdr;
#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit rx (see Note #3). */
*perr = NET_ERR_INIT_INCOMPLETE;
return;
}
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE PTR ------------------- */
if (pbuf == (NET_BUF *)0) {
NetTCP_RxPktDiscard(pbuf, perr);
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
#endif
NET_CTR_STAT_INC(NetTCP_StatRxPktCtr);
/* ----------------- VALIDATE TCP PKT ----------------- */
pbuf_hdr = &pbuf->Hdr;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NetTCP_RxPktValidateBuf(pbuf_hdr, perr); /* Validate rx'd buf. */
switch (*perr) {
case NET_TCP_ERR_NONE:
break;
case NET_ERR_INVALID_PROTOCOL:
case NET_BUF_ERR_INVALID_IX:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
ptcp_hdr = (NET_TCP_HDR *)&pbuf->Data[pbuf_hdr->TCP_UDP_HdrDataIx];
NetTCP_RxPktValidate(pbuf, pbuf_hdr, ptcp_hdr, perr); /* Validate rx'd pkt. */
/* -------------- DEMUX PKT TO TCP CONN --------------- */
switch (*perr) {
case NET_TCP_ERR_NONE:
NetTCP_RxPktDemuxSeg(pbuf, pbuf_hdr, perr);
break;
case NET_TCP_ERR_INVALID_PORT_NBR:
case NET_TCP_ERR_INVALID_LEN_HDR:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_INVALID_LEN_DATA:
case NET_TCP_ERR_INVALID_FLAG:
case NET_TCP_ERR_INVALID_CHK_SUM:
case NET_TCP_ERR_INVALID_OPT_LEN:
case NET_TCP_ERR_INVALID_OPT_END:
case NET_TCP_ERR_INVALID_OPT_NBR:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* --------------- HANDLE TCP PKT/CONN ---------------- */
switch (*perr) { /* Chk err from NetTCP_RxPktDemuxSeg(). */
case NET_TCP_ERR_NONE:
NetTCP_RxPktConnHandler(pbuf, pbuf_hdr, perr);
break;
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_CONN:
case NET_ERR_RX_DEST:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ---------------- RTN TCP ERR CODES ----------------- */
switch (*perr) { /* Chk err from NetTCP_RxPktConnHandler(). */
case NET_TCP_ERR_NONE:
/* See Note #4. */
break;
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
case NET_TCP_ERR_CONN_CLOSED:
case NET_TCP_ERR_CONN_RESET_VALID:
*perr = NET_TCP_ERR_NONE;
break;
case NET_ERR_RX:
/* See Note #4a. */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_INVALID_CONN:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_INVALID_CONN_STATE:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxAppData()
*
* Description : (1) Deframe application data from TCP connection's enqueued TCP segment(s) :
*
* (a) Wait on TCP connection application receive queue for packet buffer(s)
* (b) Deframe application data from enqueued TCP segment(s)
* (c) Update TCP connection application receive queue
* (1) Free TCP packet buffer(s)
* (d) Update TCP connection receive window
*
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to receive application data.
*
* pdata_buf Pointer to application buffer to receive application data.
* --------- Argument validated in NetSock_RxDataHandlerStream().
*
* data_buf_len Size of application receive buffer (in octets).
* ------------ Argument validated in NetSock_RxDataHandlerStream().
*
* flags Flags to select receive options; bit-field flags logically OR'd :
* -----
* NET_TCP_FLAG_NONE No TCP receive flags selected.
* NET_TCP_FLAG_RX_DATA_PEEK Receive TCP application data without consuming
* the data; i.e. data NOT removed from TCP
* connection's application receive queue(s).
* NET_TCP_FLAG_RX_BLOCK Receive TCP application data with blocking,
* if flag set; without blocking, if clear.
*
* Argument validated in NetSock_RxDataHandlerStream().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection application data successfully
* deframed; check return value for number of
* data octets received.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_CONN_DATA_INVALID TCP connection application receive queue contains
* invalid or improperly sequenced data.
*
* NET_TCP_ERR_RX_Q_CLOSED TCP connection application receive queue closed
* (see Note #3e3B).
* NET_TCP_ERR_RX_Q_EMPTY TCP connection application receive queue empty
* (see Note #3e2B).
*
* ------- RETURNED BY NetTCP_ConnIsUsed() : -------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
*
* ------ RETURNED BY NetOS_TCP_RxQ_Wait() : -------
* NET_TCP_ERR_RX_Q_SIGNAL_ABORT TCP connection receive queue signal aborted;
* TCP connection closed/aborted.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
*
* ---------- RETURNED BY NetOS_Lock() : -----------
* NET_OS_ERR_LOCK Network access NOT acquired.
*
* Return(s) : Total application data octets deframed into receive buffer, if NO errors.
*
* 0, otherwise.
*
* Caller(s) : NetSock_RxDataHandlerStream().
*
* This function is an INTERNAL network protocol suite function & SHOULD NOT be called by
* application function(s).
*$PAGE*
* Note(s) : (2) NetTCP_RxAppData() blocked until network initialization completes.
*
* See 'NetTCP_ConnIsUsed() Note #1'.
*
* (3) RFC #793, Section 3.9 'Event Processing : RECEIVE Call' specifies how to handle receive
* data requests from the application layer :
*
* (a) For the "CLOSED STATE ... return 'error: connection does not exist'".
*
* (b) (1) For the "LISTEN STATE, SYN-SENT STATE, SYN-RECEIVED STATE ... queue for processing
* after entering ESTABLISHED state".
*
* (2) The application layer may request to receive application data before the TCP
* connection enters the connected state. Such requests will block or return
* no data.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_AppData() Note #1bA'
* & Note #5b2.
*
* (c) For the "ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE" ...
*
* (1) ... that "if insufficient incoming segments are queued to satisfy the request,
* queue the request".
*
* (2) "Reassemble queued incoming segments into receive buffer and return to user."
*
* (d) For the "CLOSE-WAIT STATE ... since the remote side has already sent FIN, RECEIVEs
* must be satisfied by the text already on hand, but not yet delivered to the user.
* If no text is awaiting delivery, the RECEIVE will get a 'error: connection closing'
* response. Otherwise, any remaining text can be used to satisfy the RECEIVE".
*
* (e) (1) For the "CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE ... return 'error:
* connection closing'".
*
* (2) Typically, these states will have already received ALL remainining closing
* data from the closing remote host.
*
* (A) However, in case all receive data from the remote host has NOT yet been
* received, application layer receives from these states are permitted until
* the TCP connection's sequence receive state is closed & the TCP connection's
* application receive queue is empty.
*
* (B) If all receive data from the remote host has NOT yet been received but the
* application receive queue is currently empty, return application receive
* queue empty error(s).
*
* (3) Once a TCP connection has closed & ALL receive data has been received by the
* application layer :
*
* (A) Close the TCP connection;
* (B) Return application receive queue closed error.
*$PAGE*
* (4) (a) RFC #793, Section 3.3 states that :
*
* (1) "Every octet of data sent over a TCP connection has a sequence number."
* (2) In addition, "SYN and FIN ... control information ... [is] implicitly assign[ed]
* sequence numbers ... [but] is not physically carried in the segment data space".
*
* (A) "For sequence number purposes, the SYN is considered to occur before the
* first actual data octet of the segment in which it occurs," ...
* (B) "While the FIN is considered to occur after the last actual data octet in
* a segment in which it occurs."
*
* (3) "The segment length (SEG.LEN) includes both data and sequence space occupying
* controls.
*
*
* ----- ------------------------ Synchronization
* ^ | Initial SEQ # (SYN) | <--- Sequence Number
* | ------------------------ (see Note #4a2A)
* | | Data Octet # 1 | ---
* | | Data Octet # 2 | ^
* | Data Octet # 3 | |
* TCP Connection | . | | Data Octet
* Sequences | . | | Sequence Number(s)
* (see Note #4a) | . | | (see Note #4a1)
* | Data Octet # (N - 2) | |
* | | Data Octet # (N - 1) | v
* | | Data Octet # N | --- Closing
* | ------------------------ Sequence Number
* v | Close SEQ # (FIN) | <--- (see Note #4a2B)
* ----- ------------------------
*
*
* See also 'NetTCP_TxConnSync() Note #3'
* & 'NetTCP_TxConnClose() Note #2'.
*
* (b) Therefore, since TCP synchronization or close sequence numbers are NOT actual data
* sequences or octets that are transmitted or received; segments which include these
* TCP control sequence numbers MUST adjust TCP data sequence numbers & TCP segment
* lengths by these TCP control sequence numbers.
*
* (1) A TCP data segment MUST adjust its data index by the possible synchronization
* control sequence.
*
* (A) On a received TCP segment's first data read, the segment's base data index
* is NOT offset -- even though for a synchronization segment, this base data
* index starts on the sequence number following the synchronization control
* sequence.
*
* (B) On any additional received TCP segment data reads, the segment's base data
* index MUST be offset by possible synchronization control sequence.
*
* (2) TCP connections & TCP data segments MUST advance their sequence numbers & adjust
* their segment lengths by possible TCP control sequences.
*
* (A) A TCP connection MUST advance its sequence numbers by :
*
* (1) Possible synchronization sequence; but only on the first, initial access
* to a TCP synchronization segment; ...
* (2) All accessed data sequence(s); ...
* (3) Possible closing sequence; which SHOULD only occur once on the
* last access to a TCP closing segment.
*
* (B) (1) A received TCP segment MUST advance its sequence numbers by :
*
* (a) Possible synchronization sequence; but only on the first, initial
* access to a TCP synchronization segment; ...
* (b) All accessed data sequence(s).
*
* (2) (a) A received TCP segment MUST adjust its total segment length by :
*
* (1) Possible synchronization sequence; but only on the first, initial
* access to a TCP synchronization segment; ...
* (2) All accessed data sequence(s).
*
* (3) Possible closing sequence adjustment MAY be ignored since
* all effective segment data handling occurs prior to accessing any
* trailing closing sequence.
*
* (b) A received TCP segment MUST adjust its data segment length ONLY by :
*
* (b) All accessed data sequence(s).
*$PAGE*
* (5) (a) Stream-type connections receive all data octets in one or more non-distinct packets.
* In other words, the application data is NOT bounded by any specific packet(s); rather,
* it is contiguous & sequenced from one packet to the next.
*
* (b) Therefore, the TCP connection receive queue is signaled ONLY when data is received for
* a connection where data was previously unavailable.
*
* (c) Consequently, it is typical -- but NOT absolutely required -- that a single application
* task only receive or request to receive application data from a TCP connection.
*
* See also 'net_sock.c NetSock_RxDataHandlerStream() Note #2'.
*
* (6) Since pointer arithmetic is based on the specific pointer data type & inherent pointer
* data type size, pointer arithmetic operands :
*
* (a) MUST be in terms of the specific pointer data type & data type size; ...
* (b) SHOULD NOT & in some cases MUST NOT be cast to other data types or data type sizes.
*
* (7) RFC #793, Section 3.7 'Data Communication : Managing the Window' states that "the window
* sent in each segment indicates the range of sequence numbers the sender of the window
* (the data receiver) is currently prepared to accept. There is an assumption that this
* is related to the currently available data buffer space available for this connection
* ... One strategy would be to ... [update the] information when the window is larger".
*
* See also 'NetTCP_RxPktConnHandlerRxQ_Sync() Note #5',
* 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #6',
* & 'NetTCP_RxConnWinSizeHandler() Note #2a'.
*
* (8) (a) #### Since segments enqueued to a TCP connection's application receive queue have
* already been acknowledged to the remote host & since no mechanism exists for a TCP
* connection to re-request previously acknowledged segments, any TCP connection whose
* application receive queue becomes corrupted MUST be closed to prevent the application
* layer from receiving the corrupted data.
*
* (b) For any internal errors where the TCP connection's application receive queue is NOT
* corrupted, the TCP connection is NOT closed. Thus, the application layer may try to
* re-receive the application data.
*
* However, a TCP connection may deadlock due to persistant internal errors -- i.e. the
* internal errors prevent the TCP connection from deframing application data from the
* application receive queue which also prevents the TCP connection from receiving
* additional application data (see Note ####). Thus, exception handling code in the
* application layer SHOULD eventually detect & close any TCP connection deadlocked due
* to internal errors.
*********************************************************************************************************
*/
/*$PAGE*/
CPU_INT16U NetTCP_RxAppData (NET_TCP_CONN_ID conn_id_tcp,
void *pdata_buf,
CPU_INT16U data_buf_len,
CPU_INT16U flags,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
CPU_INT16U seg_len_close;
NET_TCP_SEQ_NBR seq_nbr_cur;
#endif
CPU_BOOLEAN block;
CPU_BOOLEAN conn_closed;
CPU_BOOLEAN q_prevly_empty;
CPU_BOOLEAN peek;
CPU_BOOLEAN frag_adv;
NET_TCP_CONN *pconn;
NET_BUF *pbuf_head;
NET_BUF *pbuf_seg;
NET_BUF *pbuf_seg_prev;
NET_BUF *pbuf_seg_next;
NET_BUF *pbuf_frag;
NET_BUF *pbuf_frag_next;
NET_BUF_HDR *pbuf_seg_hdr;
NET_BUF_HDR *pbuf_seg_prev_hdr;
NET_BUF_HDR *pbuf_seg_next_hdr;
NET_BUF_HDR *pbuf_frag_hdr;
NET_BUF_SIZE seg_len_avail;
NET_BUF_SIZE data_ix_frag;
NET_BUF_SIZE data_ix_pkt;
NET_BUF_SIZE data_len_pkt;
CPU_INT16U data_len_buf_rem;
CPU_INT16U data_len_tot;
CPU_INT16U seg_len_data;
CPU_INT16U seg_len_data_rem;
CPU_INT16U seg_len_data_tot;
CPU_INT16U seg_len_sync;
CPU_INT16U seg_len_sync_init;
CPU_INT08U *p_data;
NET_TCP_SEQ_NBR seq_nbr_init;
NET_TCP_SEQ_NBR seq_nbr_ix;
NET_ERR err;
/*$PAGE*/
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return (0);
}
#endif
/* ---------------- VALIDATE TCP CONN ----------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
conn_closed = DEF_NO;
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #3a. */
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #3b. */
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN: /* See Note #3c. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
break;
case NET_TCP_CONN_STATE_CLOSE_WAIT: /* See Note #3d. */
case NET_TCP_CONN_STATE_CLOSING: /* See Note #3e. */
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL: /* See Note #3e3. */
if (pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) {
conn_closed = DEF_YES;
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ------------ WAIT ON TCP CONN APP RX Q ------------- */
if (pconn->RxQ_App_Head == (NET_BUF *)0) { /* If no rx'd data pkts; ... */
if (conn_closed != DEF_NO) { /* ... & conn closed (see Note #3e3), ... */
if (pconn->ConnState == NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL) {
/* ... close TCP conn (see Note #3e3A) ... */
NetTCP_ConnCloseHandler(pconn, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
}
*perr = NET_TCP_ERR_RX_Q_CLOSED; /* ... & rtn rx Q closed err (see Note #3e3B); ... */
return (0);
}
block = DEF_BIT_IS_SET(flags, NET_TCP_FLAG_RX_BLOCK);
if (block != DEF_YES) { /* ... & non-blocking rx ... */
*perr = NET_TCP_ERR_RX_Q_EMPTY; /* ... rtn rx Q empty err. */
return (0);
}
NetOS_Unlock();
NetOS_TCP_RxQ_Wait(conn_id_tcp, perr);
NetOS_Lock(&err);
if ( err != NET_OS_ERR_NONE) {
*perr = err; /* Rtn err from NetOS_Lock(). */
return (0);
}
if (*perr != NET_TCP_ERR_NONE) {
return (0); /* Rtn err from NetOS_TCP_RxQ_Wait(). */
}
if (pconn->RxQ_App_Head == (NET_BUF *)0) { /* If still NO rx'd data pkts, ... */
*perr = NET_TCP_ERR_RX_Q_EMPTY; /* ... rtn rx Q empty err. */
return (0);
}
q_prevly_empty = DEF_YES;
} else {
NetOS_TCP_RxQ_Clr(conn_id_tcp, &err); /* Clr any possible async rx Q signal. */
q_prevly_empty = DEF_NO;
}
/*$PAGE*/
/* ----------- DEFRAME TCP CONN RX APP DATA ----------- */
pbuf_head = (NET_BUF *) pconn->RxQ_App_Head;
pbuf_seg = (NET_BUF *) pbuf_head;
pbuf_seg_prev = (NET_BUF *) 0;
p_data = (CPU_INT08U *) pdata_buf;
data_len_buf_rem = (CPU_INT16U ) data_buf_len;
data_len_tot = (CPU_INT16U ) 0;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
pbuf_seg_hdr = (NET_BUF_HDR *)&pbuf_seg->Hdr;
seq_nbr_cur = (NET_TCP_SEQ_NBR) pbuf_seg_hdr->TCP_SeqNbr;
#endif
while ((pbuf_seg != (NET_BUF *)0) && /* Copy app rx data from TCP conn q'd seg(s). */
(data_len_buf_rem > 0)) {
pbuf_seg_hdr = (NET_BUF_HDR *)&pbuf_seg->Hdr;
pbuf_seg_next = (NET_BUF *) pbuf_seg_hdr->NextPrimListPtr;
pbuf_frag = (NET_BUF *) pbuf_seg;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (seq_nbr_cur != pbuf_seg_hdr->TCP_SeqNbr) { /* If next q'd seg's seq nbr NOT consecutive, ... */
/* ... close TCP conn (see Note #8a). */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_DATA_INVALID;
return (0);
}
#endif
/* Init seg lens. */
seg_len_data = pbuf_seg_hdr->TCP_SegLenData;
seg_len_data_rem = seg_len_data;
seg_len_data_tot = 0;
seg_len_sync = 0;
seg_len_sync_init = 0;
if (pbuf_seg_hdr->TCP_SegSync == DEF_YES) {
seg_len_sync = NET_TCP_SEG_LEN_SYNC;
}
/* If still init seg len, cfg init sync seg len. */
if (pbuf_seg_hdr->TCP_SegLen == pbuf_seg_hdr->TCP_SegLenInit) {
seg_len_sync_init = seg_len_sync;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
seg_len_close = 0;
if (pbuf_seg_hdr->TCP_SegClose == DEF_YES) {
seg_len_close = NET_TCP_SEG_LEN_CLOSE;
}
#endif
/* Calc start seq nbr ix into seg data (see Note #4b1). */
seq_nbr_init = (NET_TCP_SEQ_NBR)(pbuf_seg_hdr->TCP_SeqNbrInit + seg_len_sync - seg_len_sync_init);
seq_nbr_ix = (NET_TCP_SEQ_NBR)(pbuf_seg_hdr->TCP_SeqNbr - seq_nbr_init);
data_ix_frag = (NET_BUF_SIZE ) seq_nbr_ix;
frag_adv = DEF_YES;
while ((pbuf_frag != (NET_BUF *)0) &&
(frag_adv == DEF_YES)) {
pbuf_frag_hdr = (NET_BUF_HDR *)&pbuf_frag->Hdr;
/* While seg's frag data ix >= cur frag data len ... */
if (data_ix_frag >= (NET_BUF_SIZE)pbuf_frag_hdr->DataLen) {
data_ix_frag -= (NET_BUF_SIZE)pbuf_frag_hdr->DataLen;
pbuf_frag_next = (NET_BUF *)pbuf_frag_hdr->NextBufPtr;
pbuf_frag = (NET_BUF *)pbuf_frag_next; /* ... adv to next seg frag. */
} else {
frag_adv = DEF_NO;
}
}
/*$PAGE*/
while ((pbuf_frag != (NET_BUF *)0) && /* Copy app rx data from avail seg pkt buf(s). */
(data_len_buf_rem > 0) &&
(seg_len_data_rem > 0)) {
pbuf_frag_hdr = (NET_BUF_HDR *)&pbuf_frag->Hdr;
pbuf_frag_next = (NET_BUF *) pbuf_frag_hdr->NextBufPtr;
seg_len_avail = pbuf_frag_hdr->DataLen - data_ix_frag;
if (seg_len_avail > (NET_BUF_SIZE)seg_len_data_rem) { /* If seg frag pkt data len > rem seg len, ... */
seg_len_avail = (NET_BUF_SIZE)seg_len_data_rem; /* ... limit copy to rem seg len. */
}
if (data_len_buf_rem > seg_len_avail) { /* If rem data buf len > seg frag pkt data len, ... */
data_len_pkt = (NET_BUF_SIZE)seg_len_avail; /* ... copy all pkt buf data len. */
} else {
data_len_pkt = (NET_BUF_SIZE)data_len_buf_rem; /* Else limit copy to rem data buf len. */
}
/* Calc ix into seg frag's data. */
data_ix_pkt = (NET_BUF_SIZE)pbuf_frag_hdr->DataIx + data_ix_frag;
data_ix_frag = 0;
NetBuf_DataRd((NET_BUF *) pbuf_frag,
(NET_BUF_SIZE) data_ix_pkt,
(NET_BUF_SIZE) data_len_pkt,
(CPU_INT08U *) p_data,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) { /* See Note #7b. */
*perr = NET_TCP_ERR_CONN_FAIL;
return (0);
}
/* Update data ptr & lens. */
p_data += data_len_pkt; /* MUST NOT cast ptr operand (see Note #6b). */
data_len_tot += (CPU_INT16U)data_len_pkt;
data_len_buf_rem -= (CPU_INT16U)data_len_pkt;
seg_len_data_tot += (CPU_INT16U)data_len_pkt;
seg_len_data_rem -= (CPU_INT16U)data_len_pkt;
pbuf_frag = pbuf_frag_next;
}
if (data_len_buf_rem > 0) { /* If rem data buf len > 0, adv to next q'd seg. */
pbuf_seg_prev = pbuf_seg;
pbuf_seg = pbuf_seg_next;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (seg_len_data_tot != seg_len_data) { /* If calc'd seg data len != actual seg data len, ... */
/* ... close TCP conn (see Note #8a). */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_DATA_INVALID;
return (0);
}
/* Adv seq nbr by cur seg's : ... */
seq_nbr_cur += (NET_TCP_SEQ_NBR)seg_len_sync_init; /* ... init sync seg len (see Note #4b2A1), ... */
seq_nbr_cur += (NET_TCP_SEQ_NBR)seg_len_data; /* ... data seg len (see Note #4b2A2), ... */
seq_nbr_cur += (NET_TCP_SEQ_NBR)seg_len_close; /* ... & close seg len (see Note #4b2A3). */
#endif
}
}
/*$PAGE*/
/* ----------- UPDATE TCP CONN APP RX Q ----------- */
peek = DEF_BIT_IS_SET(flags, NET_TCP_FLAG_RX_DATA_PEEK);
if (peek == DEF_YES) { /* If peek opt req'd ... */
if (q_prevly_empty == DEF_YES) { /* ... & TCP conn app rx Q prev'ly empty, ... */
NetOS_TCP_RxQ_Signal(conn_id_tcp, &err); /* ... signal app rx Q ... */
/* ... to negate non-consuming peek (see Note #5b). */
if (err != NET_TCP_ERR_NONE) { /* If app rx Q signal failed, ... */
peek = DEF_NO; /* ... consume pkt buf(s). */
}
}
}
if (peek != DEF_YES) { /* If peek opt NOT req'd, unlink ALL seg pkt buf(s) */
/* .. whose data was entirely consumed. */
if (pbuf_seg != (NET_BUF *)0) { /* If TCP conn app rx Q NOT empty after data rd(s) */
if (seg_len_data_rem > 0) { /* .. & cur seg's rem data len > 0; .. */
pbuf_seg_hdr->PrevPrimListPtr = (void *)0; /* .. unlink from prev q'd seg(s), .. */
pconn->RxQ_App_Head = (NET_BUF *)pbuf_seg;/* .. set new TCP conn app rx Q head, .. */
/* .. & update seg's seq nbr (see Note #4b2B1) .. */
pbuf_seg_hdr->TCP_SeqNbr += (CPU_INT32U)(seg_len_data_tot + seg_len_sync_init);
/* .. & seg's seg lens (see Note #4b2B2). */
pbuf_seg_hdr->TCP_SegLen -= (CPU_INT16U)(seg_len_data_tot + seg_len_sync_init);
pbuf_seg_hdr->TCP_SegLenData -= (CPU_INT16U) seg_len_data_tot;
if (pbuf_seg_prev != (NET_BUF *)0) { /* If prev q'd seg(s) avail, ... */
pbuf_seg_prev_hdr = &pbuf_seg_prev->Hdr;
pbuf_seg_prev_hdr->NextPrimListPtr = (void *)0; /* ... unlink from app rx Q ... */
NetTCP_RxPktFree(pbuf_head); /* ... & free ALL rd seg pkt buf(s). */
}
} else { /* Else if cur seg's rem data len = 0 ... */
if (pbuf_seg_next != (NET_BUF *)0) { /* ... & rem rx q'd seg(s) avail, ... */
/* ... unlink cur seg from rem q'd seg(s) ... */
pbuf_seg_next_hdr = &pbuf_seg_next->Hdr;
pbuf_seg_next_hdr->PrevPrimListPtr = (void *)0;
pbuf_seg_hdr->NextPrimListPtr = (void *)0;
/* ... set new TCP conn app rx Q head; ... */
pconn->RxQ_App_Head = (NET_BUF *)pbuf_seg_next;
} else { /* ... & NO rem rx q'd seg(s) avail, ... */
/* ... unlink ALL q'd seg(s); ... */
pconn->RxQ_App_Head = (NET_BUF *)0;
pconn->RxQ_App_Tail = (NET_BUF *)0;
}
NetTCP_RxPktFree(pbuf_head); /* ... & free rd seg pkt buf(s) from app rx Q. */
}
} else { /* Else clr app rx Q ... */
pconn->RxQ_App_Head = (NET_BUF *)0;
pconn->RxQ_App_Tail = (NET_BUF *)0;
NetTCP_RxPktFree(pbuf_head); /* ... & free ALL seg pkt buf(s) from app rx Q. */
}
/* --------- UPDATE TCP CONN RX WIN SIZE ---------- */
/* Inc TCP conn's rx win size (see Note #7). */
NetTCP_RxConnWinSizeHandler((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_WIN_SIZE)data_len_tot,
(NET_TCP_WIN_CODE)NET_TCP_CONN_RX_WIN_INC);
}
*perr = NET_TCP_ERR_NONE;
return (data_len_tot);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnReq()
*
* Description : (1) Transmit TCP connection request :
*
* (a) Configure TCP connections' IP parameters
* (b) Transmit TCP connection request
* (c) Update TCP connection state
*
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to transmit connection request.
*
* TOS Specific TOS to transmit TCP/IP packet
* (see 'net_ip.h IP HEADER TYPE OF SERVICE (TOS) DEFINES').
*
* TTL Specific TTL to transmit TCP/IP packet (see RFC #1122, Section 3.2.1.7) :
*
* NET_IP_HDR_TTL_MIN 1 minimum TTL transmit value
* NET_IP_HDR_TTL_MAX 255 maximum TTL transmit value
* NET_IP_HDR_TTL_DFLT default TTL transmit value
* NET_IP_HDR_TTL_NONE 0 replace with default TTL
*
* flags_ip Flags to select IP transmit options; bit-field flags logically OR'd :
*
* NET_IP_FLAG_NONE No IP transmit flags selected.
* NET_IP_FLAG_TX_DONT_FRAG Set IP 'Don't Frag' flag.
*
* popts_ip Pointer to one or more IP options configuration data structures :
*
* NULL NO IP transmit options configuration.
* NET_IP_OPT_CFG_ROUTE_TS Route &/or Internet Timestamp options
* configuration.
* NET_IP_OPT_CFG_SECURITY Security options configuration
* (see 'net_ip.c Note #1f').
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* ---- RETURNED BY NetTCP_ConnIsUsed() : -----
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
*
* ---- RETURNED BY NetTCP_TxConnSync() : -----
* NET_TCP_ERR_NONE TCP connection request successfully
* transmitted.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
* NET_TCP_ERR_TX TCP transmit error.
* NET_ERR_TX Transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetSock_ConnHandlerStream().
*
* This function is an INTERNAL network protocol suite function & SHOULD NOT be called by
* application function(s).
*
* Note(s) : (2) NetTCP_TxConnReq() blocked until network initialization completes.
*
* See 'NetTCP_ConnIsUsed() Note #1'.
*
* (3) On ANY errors, return error to TCP connection caller & allow caller to retry or close
* connection(s) but do NOT close TCP connection.
*
* (4) #### IP options currently NOT implemented.
*********************************************************************************************************
*/
/*$PAGE*/
void NetTCP_TxConnReq (NET_TCP_CONN_ID conn_id_tcp,
NET_IP_TOS TOS,
NET_IP_TTL TTL,
CPU_INT16U flags_ip,
void *popts_ip,
NET_ERR *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
#endif
pconn = &NetTCP_ConnTbl[conn_id_tcp];
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------- VALIDATE TCP CONN STATE -------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
break;
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_CONN_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* -------------- CFG TCP CONN IP PARAMS -------------- */
pconn->TxIP_TOS = TOS;
pconn->TxIP_TTL = TTL;
pconn->TxIP_Flags = flags_ip;
(void)&popts_ip; /* Prevent compiler warning (see Note #4). */
/* ----------------- TX TCP CONN REQ ------------------ */
NetTCP_TxConnSync((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_ERR *)perr);
if (*perr != NET_TCP_ERR_NONE) { /* See Note #3. */
return;
}
/* -------------- UPDATE TCP CONN STATE --------------- */
pconn->ConnState = NET_TCP_CONN_STATE_SYNC_TXD;
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnAppData()
*
* Description : (1) Prepare & transmit data from Application layer(s) via TCP connection :
*
* (a) Validate application data
*
* (b) Transmit application data via TCP Transmit :
* (1) Validate TCP connection
* (2) Wait on TCP connection transmit queue
* (3) Prepare TCP data segment(s) :
* (A) TCP segment addresses
* (B) Prepare application data :
* (1) Get buffer(s) for application data
* (2) Copy application data into TCP packet buffer(s)
* (3) Update TCP segment data controls
* (4) Update application data controls
* (4) Update TCP connection transmit window
*
* (c) Update TCP connection :
* (1) Append TCP transmit segment(s) to TCP connection transmit queue
* (2) Update TCP connection sequence number(s)
*
* (d) Transmit TCP data segment(s) via TCP Transmit
*
*
* Argument(s) : conn_id_tcp Handle identifier of connection to transmit application data.
*
* p_data Pointer to application data.
* ------ Argument validated in NetSock_TxDataHandlerStream().
*
* data_len Length of application data (in octets) [see Note #5].
* -------- Argument validated in NetSock_TxDataHandlerStream().
*
* flags Flags to select transmit options; bit-field flags logically OR'd :
* -----
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_BLOCK Transmit TCP application data with blocking,
* if flag set; without blocking, if clear.
*
* Argument validated in NetSock_TxDataHandlerStream().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Application data successfully prepared &
* transmitted via TCP layer.
* NET_TCP_ERR_NULL_PTR Argument 'p_data' passed a NULL pointer.
* NET_TCP_ERR_INVALID_DATA_SIZE Argument 'data_len' passed an invalid size.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_CONN_DATA_INVALID TCP connection application transmit queue contains
* invalid or improperly sequenced data.
* NET_TCP_ERR_TX_Q_FULL TCP connection transmit queue full.
* NET_TCP_ERR_TX_Q_SUSPEND TCP connection transmit queue temporarily suspended.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* -------- RETURNED BY NetTCP_ConnIsUsed() : ---------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
*
* -------- RETURNED BY NetOS_TCP_TxQ_Wait() : --------
* NET_TCP_ERR_TX_Q_SIGNAL_ABORT TCP connection transmit queue signal aborted;
* TCP connection closed/aborted.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
*
* --------- RETURNED BY NetTCP_TxConnTxQ() : ---------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_ACK_NONE TCP connection acknowledgement NOT requested.
* NET_TCP_ERR_CONN_ACK_DLYD TCP connection acknowledgement transmit delayed.
* NET_TCP_ERR_CONN_ACK_PREVLY_TXD TCP connection acknowledgement previously
* transmitted for segment.
* NET_TCP_ERR_CONN_ACK_INVALID TCP connection acknowledgement NOT valid for
* current TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* NET_TCP_ERR_TX TCP transmit error.
* NET_ERR_TX Transmit error.
*
* ------------ RETURNED BY NetOS_Lock() : ------------
* NET_OS_ERR_LOCK Network access NOT acquired.
*
* Return(s) : Number of data octets transmitted, if NO errors.
*
* 0, otherwise.
*
* Caller(s) : NetSock_TxDataHandlerStream().
*
* This function is an INTERNAL network protocol suite function & SHOULD NOT be called by
* application function(s).
*$PAGE*
* Note(s) : (2) NetTCP_TxConnAppData() blocked until network initialization completes.
*
* See 'NetTCP_ConnIsUsed() Note #1'.
*
* (3) RFC #793, Section 3.9 'Event Processing : SEND Call' specifies how to handle transmit
* data requests from the application layer :
*
* (a) For the "CLOSED STATE ... return 'error: connection does not exist'".
*
* (b) For the "LISTEN STATE" ...
*
* (1) "If the foreign socket is specified, then" ...
*
* (A) "Change the connection from passive to active," ...
* (B) "select an ISS" ...
* (C) "Send a SYN segment," ...
* (D) "Set" ...
* (1) "SND.UNA to ISS," ...
* (2) "SND.NXT to ISS+1."
* (E) "Enter SYN-SENT state."
* (F) "Data associated with SEND may be" ...
* (1) "sent with SYN segment" ...
* (2) (a) "or queued for transmission after entering ESTABLISHED state."
* (b) "If there is no room to queue the request, respond with 'error:
* insufficient resources'."
*
* (2) "If Foreign [sic] socket was not specified, then return 'error: foreign socket
* unspecified'."
*
* (A) #### NOT yet implemented; see also
* 'net_sock.c NetSock_TxDataHandlerStream() Note #2aA'.
*
* (c) For the "SYN-SENT STATE, SYN-RECEIVED STATE" ...
*
* (1) "Queue the data for transmission after entering ESTABLISHED state."
* (2) "If no space to queue, respond with 'error: insufficient resources'."
*
* (d) For the "ESTABLISHED STATE, CLOSE-WAIT STATE" ...
*
* (1) (A) "Segmentize the buffer" ...
* (B) "and send it with a piggybacked ackknowledgment" ...
* (1) "(acknowledgment value = RCV.NXT)"
* (2) "If there is no insufficient space to remember this buffer, simply return
* 'error: insufficient resources'."
*
* (e) For the "FIN-WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSING STATE, LAST-ACK STATE,
* TIME-WAIT STATE" ...
*
* (1) "return 'error: connection closing'" ...
* (2) "and do not service request."
*$PAGE*
* (4) TCP segments with transmit data are sequenced into the TCP connection's transmit
* queue to await transmission at the appropriate time(s) [see 'NetTCP_TxConnTxQ()
* Note #1b'].
*
* (a) Transmit TCP segments are inserted into a doubly-linked Transmit Queue, ordered
* consecutively by sequence number(s) [see also Note #4b].
*
* (1) 'TxQ_Head' points to the head of the Transmit Queue;
* 'TxQ_Tail' points to the tail of the Transmit Queue.
*
* (2) Segment buffers' 'PrevPrimListPtr' & 'NextPrimListPtr' doubly-link each
* segment to form the Transmit Queue.
*
* (b) Transmit data is packetized into TCP segments in sequence-order. Therefore, new
* transmit segments are sequenced after previously packetized segments starting at
* the tail of the Transmit Queue.
*
* (c) Segments at the head of the Transmit Queue are available & ready to be transmitted
* via the Internet Transmit Layer.
*
*
* | |
* |<------- TCP Connection Transmit Queue ------->|
* | (see Note #4) |
*
* Segments Ready Segments Sequenced
* to Transmit into Transmit Queue
* start at head starting at tail
* (see Note #4c) (see Note #4b)
*
* | NextPrimListPtr |
* | (see Note #4a2) |
* v | v
* |
* Head of ------- ------- v ------- ------- (see Note #4a1)
* Transmit ---->| |------>| |------>| |------>| |
* Queue | | | | | | | | Tail of
* | |<------| |<------| |<------| |<---- Transmit
* (see Note #4a1) | | | | ^ | | | | Queue
* | | | | | | | | |
* ------- ------- | ------- -------
* |
* PrevPrimListPtr
* (see Note #4a2)
*
*$PAGE*
* (5) 'data_len' of 0 octets NOT allowed.
*
* (6) Certain network connections MUST periodically suspend network transmit(s) to handle
* network receive packet(s). To protect TCP connections from transmit corruption while
* suspended, ALL TCP data transmits & TCP transmit queue handling MUST be blocked for
* suspended connections until the connection is no longer suspended.
*
* See also 'NetTCP_TxConnTxQ() Note #10b2A2'.
*
* (7) (a) RFC #793, Section 3.8 'Interfaces : User/TCP Interface : TCP User Commands : Send'
* states that :
*
* (1) "If the PUSH flag is set, the data must be transmitted promptly to the receiver,
* and the PUSH bit will be set in the last TCP segment created from the buffer."
*
* (2) "If the PUSH flag is not set, the data may be combined with data from subsequent
* SENDs for transmission efficiency."
*
* (b) RFC #1122, Section 4.2.2.2 states that :
*
* (1) "When an application issues a series of SEND calls without setting the PUSH
* flag, the TCP MAY aggregate the data internally without sending it."
*
* (2) "The PSH bit is not a record marker and is independent of segment boundaries.
* The transmitter SHOULD collapse successive PSH bits when it packetizes data,
* to send the largest possible segment.
*
* (3) (A) "A TCP MAY implement PUSH flags on SEND calls."
*
* (B) (1) "If PUSH flags are not implemented, then the sending TCP: ...
*
* (a) must not buffer data indefinitely, and ...
* (b) MUST set the PSH bit in the last buffered segment (i.e., when
* there is no more queued data to be sent)."
*
* (1) However, NO RFC specifies whether the PUSH bit should be
* set ONLY in the last buffered segment. Therefore, is is
* assumed that the PUSH bit MAY be set in the last buffered
* segment of each call to SEND.
*
* (2) "When the PUSH flag is not implemented on SEND calls, i.e., when
* the application/TCP interface uses a pure streaming model,
* responsibility for aggregating any tiny data fragments to form
* reasonable sized segments is partially borne by the application
* layer."
*
* (4) (A) "An application program is logically required to set the PUSH flag in a
* SEND call whenever it needs to force delivery of the data to avoid a
* communication deadlock. However, a TCP SHOULD send a maximum-sized
* segment whenever possible, to improve performance."
*
* (B) "Generally, an interactive application protocol must set the PUSH flag
* at least in the last SEND call in each command or response sequence."
*
* (8) Since pointer arithmetic is based on the specific pointer data type & inherent pointer
* data type size, pointer arithmetic operands :
*
* (a) MUST be in terms of the specific pointer data type & data type size; ...
* (b) SHOULD NOT & in some cases MUST NOT be cast to other data types or data type sizes.
*
* (9) Network buffers allocated for TCP connection transmit SHOULD be fully used even if
* the TCP connection's configured transmit window is zero.
*
* See also 'NetTCP_TxConnWinSizeHandlerCfgd() Note #2'.
*
* (10) (a) Since segments enqueued to a TCP connection's transmit queue have already been
* reported as transmitted to the application & since no mechanism exists for a TCP
* connection to re-request previously transmitted data, any TCP connection whose
* transmit queue becomes corrupted MUST be closed to force the application layer to
* abort &/or recover from the corrupted data.
*
* (b) For any internal errors where the TCP connection's transmit queue is NOT corrupted,
* the TCP connection is NOT closed. Thus, the application layer may try to re-transmit
* the application data.
*
* (c) On ANY transmit error, any remaining application data transmit is immediately aborted.
*
* See also 'NetTCP_TxConnTxQ() Note #12'.
* & 'NetTCP_TxConnReTxQ() Note #11'.
*********************************************************************************************************
*/
/*$PAGE*/
CPU_INT16U NetTCP_TxConnAppData (NET_TCP_CONN_ID conn_id_tcp,
void *p_data,
CPU_INT16U data_len,
CPU_INT16U flags,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_BUF *pbuf;
NET_BUF *pbuf_head;
NET_BUF *pbuf_tail;
NET_BUF *pbuf_q_tail;
NET_BUF_HDR *pbuf_hdr;
NET_BUF_HDR *pbuf_hdr_head;
NET_BUF_HDR *pbuf_hdr_tail;
NET_BUF_HDR *pbuf_hdr_q_tail;
NET_BUF_SIZE buf_size_max;
NET_BUF_SIZE buf_size_max_data;
NET_BUF_SIZE buf_size_max_tail;
NET_BUF_SIZE buf_size_max_tail_data;
NET_BUF_SIZE data_ix_pkt;
NET_BUF_SIZE data_ix_pkt_tail;
NET_BUF_SIZE data_len_pkt_tail;
NET_BUF_SIZE data_len_pkt_rem;
NET_BUF_SIZE data_len_pkt;
NET_BUF_SIZE data_len_mss;
CPU_INT16U data_len_rem;
CPU_INT16U data_len_tot;
CPU_INT16U flags_tcp;
CPU_INT08U *p_data_pkt;
CPU_BOOLEAN tx_q_append;
CPU_BOOLEAN tx_data;
CPU_BOOLEAN tx_err;
CPU_BOOLEAN block;
NET_TCP_SEQ_NBR seq_nbr;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* ---------------- VALIDATE APP DATA ----------------- */
if (p_data == (void *)0) {
*perr = NET_TCP_ERR_NULL_PTR;
return (0);
}
if (data_len < 1) { /* Validate data len (see Note #5). */
NET_CTR_ERR_INC(NetTCP_ErrTxInvalidSizeCtr);
*perr = NET_TCP_ERR_INVALID_DATA_SIZE;
return (0);
}
/* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return (0);
}
#endif
/*$PAGE*/
/* ---------------- VALIDATE TCP CONN ----------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
switch (pconn->ConnState) { /* Validate conn state. */
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #3a. */
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #3b. */
/* #### NOT yet implemented (see Note #3bA). */
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #3c. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
tx_data = DEF_NO;
break;
case NET_TCP_CONN_STATE_CONN: /* See Note #3d. */
case NET_TCP_CONN_STATE_CLOSE_WAIT:
tx_data = DEF_YES;
break;
case NET_TCP_CONN_STATE_FIN_WAIT_1: /* See Note #3e. */
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
}
switch (pconn->TxQ_State) { /* Validate tx Q state. */
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
break;
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* See Note #6. */
*perr = NET_TCP_ERR_TX_Q_SUSPEND;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* -------------- WAIT ON TCP CONN TX Q --------------- */
if (tx_data == DEF_YES) { /* If tx rdy, ... */
if (data_len < 1) { /* ... but NO tx data avail, ... */
/* ... tx q'd data OR immed ack; ... */
NetTCP_TxConnTxQ((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_ACK_CODE )NET_TCP_CONN_TX_ACK_IMMED,
(CPU_BOOLEAN )DEF_NO,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL,
(NET_ERR *)perr);
return (0);
}
/* ... Else if tx data avail, ... */
if (pconn->TxWinSizeCfgdRem < 1) { /* ... but tx Q full ... */
block = DEF_BIT_IS_SET(flags, NET_TCP_FLAG_TX_BLOCK);
if (block != DEF_YES) { /* ... & non-blocking tx, ... */
*perr = NET_TCP_ERR_TX_Q_FULL; /* ... rtn tx Q full err. */
return (0);
}
NetOS_Unlock();
NetOS_TCP_TxQ_Wait(conn_id_tcp, perr);
NetOS_Lock(&err);
if ( err != NET_OS_ERR_NONE) {
*perr = err; /* Rtn err from NetOS_Lock(). */
return (0);
}
if (*perr != NET_TCP_ERR_NONE) {
return (0); /* Rtn err from NetOS_TCP_TxQ_Wait(). */
}
if (pconn->TxWinSizeCfgdRem < 1) { /* If tx Q still full, ... */
*perr = NET_TCP_ERR_TX_Q_FULL; /* ... rtn tx Q full err. */
return (0);
}
} else {
NetOS_TCP_TxQ_Clr(conn_id_tcp, &err); /* Clr any possible async tx Q signal. */
}
}
/* ------- PREPARE APP TX DATA INTO TCP SEG(S) -------- */
/* Prepare seg addrs. */
NetTCP_TxConnPrepareSegAddrs((NET_TCP_CONN *) pconn,
(CPU_INT08U *)&src_port,
(CPU_INT08U *)&src_addr,
(CPU_INT16U ) sizeof(src_port),
(CPU_INT16U ) sizeof(src_addr),
(CPU_INT08U *)&dest_port,
(CPU_INT08U *)&dest_addr,
(CPU_INT16U ) sizeof(dest_port),
(CPU_INT16U ) sizeof(dest_addr),
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) {
*perr = NET_TCP_ERR_CONN_FAULT;
return (0);
}
/*$PAGE*/
pbuf_head = (NET_BUF *)0;
pbuf_tail = (NET_BUF *)0;
p_data_pkt = (CPU_INT08U *)p_data;
tx_q_append = (CPU_BOOLEAN )DEF_YES;
data_len_mss = (NET_BUF_SIZE)pconn->MaxSegSizeConn;
data_len_rem = (CPU_INT16U )data_len;
data_len_tot = (CPU_INT16U )0;
/* Prepare TCP tx seg hdr ctrls. */
seq_nbr = pconn->TxSeqNbrNextQ;
flags_tcp = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_ACK;
if (pconn->TxQ_Tail != (NET_BUF *)0) { /* If tx Q NOT empty; ... */
pbuf = pconn->TxQ_Tail;
pbuf_hdr = &pbuf->Hdr;
data_ix_pkt_tail = (NET_BUF_SIZE)pbuf_hdr->DataIx;
data_len_pkt_tail = (NET_BUF_SIZE)pbuf_hdr->TCP_SegLenData;
/* ... calc tail seg's max data size, ... */
buf_size_max_tail = NetBuf_GetMaxSize(pbuf, data_ix_pkt_tail);
buf_size_max_tail_data = DEF_MIN(buf_size_max_tail, data_len_mss);
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (data_len_pkt_tail > buf_size_max_tail_data) { /* If seg len > max data size, tx Q data seg invalid; */
/* ... close TCP conn (see Note #10a). */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_DATA_INVALID;
return (0);
}
#endif
if (data_len_pkt_tail < buf_size_max_tail_data) { /* ... & if avail data space on tx Q's tail seg, ... */
/* ... append data on tx Q tail seg (see Note #7b1). */
data_ix_pkt = data_ix_pkt_tail + data_len_pkt_tail;
data_len_pkt_rem = buf_size_max_tail_data - data_len_pkt_tail;
if (data_len_rem > (NET_BUF_SIZE)data_len_pkt_rem) {/* If data len rem > pkt data len rem, ... */
data_len_pkt = (NET_BUF_SIZE)data_len_pkt_rem; /* ... limit pkt data len to pkt data len rem. */
} else {
data_len_pkt = (NET_BUF_SIZE)data_len_rem; /* Else limit pkt data len to data len rem. */
}
NetBuf_DataWr((NET_BUF *) pbuf, /* Wr app data into TCP tx buf. */
(NET_BUF_SIZE) data_ix_pkt,
(NET_BUF_SIZE) data_len_pkt,
(CPU_INT08U *) p_data_pkt,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) { /* If wr err, tx Q data corrupted; ... */
/* ... close TCP conn (see Note #10a). */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAULT;
return (0);
}
/* Update TCP seg tx buf ctrls. */
pbuf_hdr->DataLen += (NET_BUF_SIZE)data_len_pkt;
pbuf_hdr->TotLen += (NET_BUF_SIZE)data_len_pkt;
pbuf_hdr->TCP_SegLenInit += (CPU_INT16U )data_len_pkt;
pbuf_hdr->TCP_SegLen += (CPU_INT16U )data_len_pkt;
pbuf_hdr->TCP_SegLenData += (CPU_INT16U )data_len_pkt;
pbuf_head = (NET_BUF *)pbuf; /* Set tx Q tail as first seg onto tx app data chain. */
pbuf_tail = (NET_BUF *)pbuf;
tx_q_append = (CPU_BOOLEAN)DEF_NO;
/* Update data ptr & lens. */
p_data_pkt += data_len_pkt; /* MUST NOT cast ptr operand (see Note #8b). */
data_len_tot += (CPU_INT16U)data_len_pkt;
data_len_rem -= (CPU_INT16U)data_len_pkt;
seq_nbr += (NET_TCP_SEQ_NBR)data_len_pkt;
/* Dec TCP conn's tx win size (see Note #9). */
NetTCP_TxConnWinSizeHandlerCfgd((NET_TCP_CONN *) pconn,
(NET_TCP_WIN_SIZE) data_len_pkt,
(NET_TCP_WIN_CODE) NET_TCP_CONN_TX_WIN_DEC,
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) {
*perr = NET_TCP_ERR_CONN_FAULT;
return (0);
}
}
}
/*$PAGE*/
/* Calc max data size. */
data_ix_pkt = NET_BUF_DATA_TX_IX;
buf_size_max = NetBuf_GetMaxSize((NET_BUF *)0,
(NET_BUF_SIZE)data_ix_pkt);
buf_size_max_data = DEF_MIN(buf_size_max, data_len_mss);
tx_err = DEF_NO;
while ((data_len_rem > 0) && /* Prepare TCP seg(s) for ALL app data ... */
(pconn->TxWinSizeCfgdRem > 0) && /* ... as net rsrc(s)/err(s) permit. */
(tx_err == DEF_NO)) {
if (data_len_rem > (NET_BUF_SIZE)buf_size_max_data) { /* If data len rem > max data size, ... */
data_len_pkt = (NET_BUF_SIZE)buf_size_max_data; /* ... limit pkt data len to max data size. */
} else {
data_len_pkt = (NET_BUF_SIZE)data_len_rem; /* Else limit pkt data len to data len rem. */
}
pbuf = NetBuf_Get((NET_BUF_SIZE) data_len_pkt, /* Get app data tx buf. */
(NET_BUF_SIZE) data_ix_pkt,
(CPU_INT16U ) NET_BUF_FLAG_NONE,
(NET_ERR *)&err);
if (err != NET_BUF_ERR_NONE) {
tx_err = DEF_YES;
}
if (tx_err == DEF_NO) {
NetBuf_DataWr((NET_BUF *) pbuf, /* Wr app data into TCP tx buf. */
(NET_BUF_SIZE) data_ix_pkt,
(NET_BUF_SIZE) data_len_pkt,
(CPU_INT08U *) p_data_pkt,
(NET_ERR *)&err);
if (err != NET_BUF_ERR_NONE) {
NetTCP_TxPktDiscard(pbuf, &err);
tx_err = DEF_YES;
}
}
if (tx_err == DEF_NO) {
/* Init TCP seg(s) tx buf ctrls. */
pbuf_hdr = &pbuf->Hdr;
pbuf_hdr->DataIx = (CPU_INT16U )data_ix_pkt;
pbuf_hdr->DataLen = (NET_BUF_SIZE)data_len_pkt;
pbuf_hdr->TotLen = (NET_BUF_SIZE)pbuf_hdr->DataLen;
pbuf_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_APP;
pbuf_hdr->TCP_UDP_PortSrc = (NET_PORT_NBR)src_port;
pbuf_hdr->IP_AddrSrc = (CPU_INT32U )src_addr;
pbuf_hdr->TCP_UDP_PortDest = (NET_PORT_NBR)dest_port;
pbuf_hdr->IP_AddrDest = (CPU_INT32U )dest_addr;
pbuf_hdr->TCP_SegLenInit = (CPU_INT16U )data_len_pkt;
pbuf_hdr->TCP_SegLen = (CPU_INT16U )pbuf_hdr->TCP_SegLenInit;
pbuf_hdr->TCP_SegLenData = (CPU_INT16U )pbuf_hdr->TCP_SegLenInit;
pbuf_hdr->TCP_SegSync = (CPU_BOOLEAN )DEF_NO;
pbuf_hdr->TCP_SegClose = (CPU_BOOLEAN )DEF_NO;
pbuf_hdr->TCP_SegAck = (CPU_BOOLEAN )DEF_YES;
pbuf_hdr->TCP_SegReset = (CPU_BOOLEAN )DEF_NO;
pbuf_hdr->TCP_SeqNbrInit = (CPU_INT32U )seq_nbr;
pbuf_hdr->TCP_SeqNbr = (CPU_INT32U )pbuf_hdr->TCP_SeqNbrInit;
pbuf_hdr->TCP_Flags = (CPU_INT16U )flags_tcp;
if (pbuf_tail != (NET_BUF *)0) { /* If tx app data chain NOT empty, ... */
/* ... append seg(s) @ chain tail. */
pbuf_hdr_tail = (NET_BUF_HDR *)&pbuf_tail->Hdr;
pbuf_hdr_tail->NextPrimListPtr = (void *) pbuf;
pbuf_hdr->PrevPrimListPtr = (void *) pbuf_tail;
pbuf_tail = (NET_BUF *) pbuf;
} else { /* Else add seg as first seg onto tx app data chain. */
pbuf_head = (NET_BUF *) pbuf;
pbuf_tail = (NET_BUF *) pbuf;
}
/* Update data ptr & lens. */
p_data_pkt += data_len_pkt; /* MUST NOT cast ptr operand (see Note #8b). */
data_len_tot += (CPU_INT16U)data_len_pkt;
data_len_rem -= (CPU_INT16U)data_len_pkt;
seq_nbr += (NET_TCP_SEQ_NBR)data_len_pkt;
/* Dec TCP conn's tx win size (see Note #9). */
NetTCP_TxConnWinSizeHandlerCfgd((NET_TCP_CONN *) pconn,
(NET_TCP_WIN_SIZE) data_len_pkt,
(NET_TCP_WIN_CODE) NET_TCP_CONN_TX_WIN_DEC,
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) {
*perr = NET_TCP_ERR_CONN_FAULT;
return (0);
}
}
}
/*$PAGE*/
if (pbuf_head == (NET_BUF *)0) { /* If NO data seg'd, rtn no rsrc(s) err ... */
*perr = NET_TCP_ERR_NONE_AVAIL; /* ... (see Notes #3b1F2b, #3c2, & #3d2). */
return (0);
}
DEF_BIT_SET(pbuf_hdr->TCP_Flags, NET_TCP_FLAG_TX_PUSH); /* Set PUSH flag in last q'd tx seg (see Note #7b3B1b). */
/* ----------------- UPDATE TCP CONN ------------------ */
if (pconn->TxQ_Tail != (NET_BUF *)0) { /* If tx Q NOT empty ... */
if (tx_q_append == DEF_YES) { /* ... & tx app data chain NOT already on tx Q, ... */
/* ... append seg(s) @ Q tail (see Note #4b). */
pbuf_q_tail = (NET_BUF *) pconn->TxQ_Tail;
pbuf_hdr_q_tail = (NET_BUF_HDR *)&pbuf_q_tail->Hdr;
pbuf_hdr_q_tail->NextPrimListPtr = (void *) pbuf_head;
pbuf_hdr_head = (NET_BUF_HDR *)&pbuf_head->Hdr;
pbuf_hdr_head->PrevPrimListPtr = (void *) pbuf_q_tail;
}
pconn->TxQ_Tail = (NET_BUF *)pbuf_tail;
} else { /* Else add seg(s) to empty tx Q. */
pconn->TxQ_Head = (NET_BUF *)pbuf_head;
pconn->TxQ_Tail = (NET_BUF *)pbuf_tail;
}
/* Update TCP conn tx seq nbr(s). */
pconn->TxSeqNbrNextQ = seq_nbr;
/* ---------------- TX TCP DATA SEG(S) ---------------- */
if (tx_data == DEF_YES) {
NetTCP_TxConnTxQ((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_ACK_CODE )NET_TCP_CONN_TX_ACK_NONE,
(CPU_BOOLEAN )DEF_NO,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL,
(NET_ERR *)perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return (0); /* Prevent 'break NOT reachable' compiler warning. */
}
}
*perr = NET_TCP_ERR_NONE;
return (data_len_tot);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnGet()
*
* Description : (1) Allocate & initialize a TCP connection :
*
* (a) Get a TCP connection
* (b) Validate TCP connection
* (c) Initialize TCP connection
* (d) Update TCP connection pool statistics
* (e) Return TCP connection handle identifier
* OR
* Null identifier & error code, on failure
*
* (2) The TCP connection pool is implemented as a stack :
*
* (a) 'NetTCP_ConnPoolPtr' points to the head of the TCP connection pool.
*
* (b) TCP connections' 'NextPtr's link each TCP connection to form the TCP connection pool stack.
*
* (c) TCP connections are inserted & removed at the head of the TCP connection pool stack.
*
*
* TCP connections are
* inserted & removed
* at the head
* (see Note #2c)
*
* | NextPtr
* | (see Note #2b)
* v |
* |
* ------- ------- v ------- -------
* TCP Connection ---->| |------>| |------>| |------>| |
* Pool Pointer | | | | | | | |
* | | | | | | | |
* (see Note #2a) ------- ------- ------- -------
*
* | |
* |<------- Pool of Free TCP Connections -------->|
* | (see Note #2) |
*
*
* Argument(s) : perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection successfully allocated &
* initialized.
* NET_TCP_ERR_NONE_AVAIL NO available TCP connections to allocate.
* NET_TCP_ERR_INVALID_CONN_TYPE TCP connection is NOT a valid type.
*
* Return(s) : TCP connection handle identifier, if NO errors.
*
* NET_TCP_CONN_ID_NONE, otherwise.
*
* Caller(s) : various.
*
* This function is an INTERNAL network protocol suite function & MUST NOT be called by
* application function(s).
*
* Note(s) : (3) (a) TCP connection pool is accessed by 'NetTCP_ConnPoolPtr' during execution of
*
* (1) NetTCP_Init()
* (2) NetTCP_ConnGet()
* (3) NetTCP_ConnFree()
*
* (b) Since the primary tasks of the network protocol suite are prevented from running
* concurrently (see 'net.h Note #2'), it is NOT necessary to protect the shared
* resources of the connection pool since no asynchronous access from other network
* tasks is possible.
*********************************************************************************************************
*/
/*$PAGE*/
NET_TCP_CONN_ID NetTCP_ConnGet (NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CONN_ID conn_id_tcp;
NET_ERR stat_err;
/* ------------------- GET TCP CONN ------------------- */
if (NetTCP_ConnPoolPtr != (NET_TCP_CONN *)0) { /* If TCP conn pool NOT empty, get TCP conn from pool. */
pconn = (NET_TCP_CONN *)NetTCP_ConnPoolPtr;
NetTCP_ConnPoolPtr = (NET_TCP_CONN *)pconn->NextPtr;
} else { /* If none avail, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrNoneAvailCtr);
*perr = NET_TCP_ERR_NONE_AVAIL;
return (NET_TCP_CONN_ID_NONE);
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE TCP CONN ----------------- */
if (pconn->Type != NET_TCP_TYPE_CONN) {
NetTCP_ConnDiscard(pconn);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
*perr = NET_TCP_ERR_INVALID_CONN_TYPE;
return (NET_TCP_CONN_ID_NONE);
}
#endif
/* ------------------ INIT TCP CONN ------------------- */
NetTCP_ConnClr(pconn);
DEF_BIT_SET(pconn->Flags, NET_TCP_FLAG_USED); /* Set TCP conn as used. */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSED;
/* ------------ UPDATE TCP CONN POOL STATS ------------ */
NetStat_PoolEntryUsedInc(&NetTCP_ConnPoolStat, &stat_err);
/* ----------------- RTN TCP CONN ID ------------------ */
conn_id_tcp = pconn->ID;
*perr = NET_TCP_ERR_NONE;
return (conn_id_tcp);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnFree()
*
* Description : Free a TCP connection.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to free.
*
* Return(s) : none.
*
* Caller(s) : NetSock_Listen(),
* NetSock_GetConnTransport().
*
* This function is an INTERNAL network protocol suite function & MUST NOT be called by
* application function(s).
*
* Note(s) : (1) #### To prevent freeing a TCP connection already freed via previous TCP connection
* free, NetTCP_ConnFree() checks if the TCP connection is used BEFORE freeing the
* TCP connection.
*
* This prevention is only best-effort since any invalid duplicate TCP connection frees
* MAY be asynchronous to potentially valid TCP connection gets. Thus the invalid TCP
* connection free(s) MAY corrupt the TCP connection's valid operation(s).
*
* However, since the primary tasks of the network protocol suite are prevented from
* running concurrently (see 'net.h Note #2'), it is NOT necessary to protect TCP
* connection resources from possible corruption since no asynchronous access from
* other network tasks is possible.
*********************************************************************************************************
*/
void NetTCP_ConnFree (NET_TCP_CONN_ID conn_id_tcp)
{
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_ERR err;
#endif
NET_TCP_CONN *pconn;
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp == NET_TCP_CONN_ID_NONE) {
return;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, &err);
if (err != NET_TCP_ERR_NONE) { /* If TCP conn NOT used, ... */
return; /* ... rtn but do NOT free (see Note #1). */
}
#endif
/* ------------------ FREE TCP CONN ------------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
NetTCP_ConnFreeHandler(pconn, NET_TCP_CONN_FREE_ALL);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCloseFromConn()
*
* Description : Close a TCP connection via a network connection.
*
* (1) When a network connection closes a TCP connection, the TCP connection :
*
* (a) (1) Closes NO other network connection(s),
* (2) MUST NOT recursively re-close other network connection(s);
*
* (b) SHOULD clear network connection(s)' handle identifiers.
*
* See also 'net_sock.c NetSock_CloseFromConn() Note #1',
* & 'net_conn.c NetConn_CloseFromTransport() Note #1b'.
*
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to close.
*
* Return(s) : none.
*
* Caller(s) : NetConn_CloseTransport().
*
* This function is an INTERNAL network protocol suite function & MUST NOT be called by
* application function(s).
*
* Note(s) : (2) #### To prevent closing a TCP connection already closed via previous TCP connection
* close, NetTCP_ConnCloseFromConn() checks if the TCP connection is used BEFORE closing
* the TCP connection.
*
* This prevention is only best-effort since any invalid duplicate TCP connection closes
* MAY be asynchronous to potentially valid TCP connection gets. Thus the invalid TCP
* connection closes(s) MAY corrupt the TCP connection's valid operation(s).
*
* However, since the primary tasks of the network protocol suite are prevented from
* running concurrently (see 'net.h Note #2'), it is NOT necessary to protect TCP
* connection resources from possible corruption since no asynchronous access from
* other network tasks is possible.
*********************************************************************************************************
*/
void NetTCP_ConnCloseFromConn (NET_TCP_CONN_ID conn_id_tcp)
{
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_ERR err;
#endif
NET_TCP_CONN *pconn;
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp == NET_TCP_CONN_ID_NONE) {
return;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, &err);
if (err != NET_TCP_ERR_NONE) { /* If TCP conn NOT used, ... */
return; /* ... rtn but do NOT close (see Note #2). */
}
#endif
/* ------------------ CLOSE TCP CONN ------------------ */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_NO, /* See Note #1. */
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnSetID_Conn()
*
* Description : Set a TCP connection's network connection handle identifier.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to set.
*
* conn_id Handle identifier of network connection.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection's network connection handle
* identifier successfully set.
* NET_TCP_ERR_INVALID_CONN_ID Invalid network connection handle identifier.
*
* ----- RETURNED BY NetTCP_ConnIsUsed() : -----
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
*
* ------ RETURNED BY NetConn_IsUsed() : -------
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* Return(s) : none.
*
* Caller(s) : NetSock_GetConnTransport().
*
* This function is an INTERNAL network protocol suite function & MUST NOT be called by
* application function(s).
*
* Note(s) : none.
*********************************************************************************************************
*/
void NetTCP_ConnSetID_Conn (NET_TCP_CONN_ID conn_id_tcp,
NET_CONN_ID conn_id,
NET_ERR *perr)
{
NET_TCP_CONN *pconn;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* --------------- VALIDATE NET CONN ID --------------- */
if (conn_id != NET_CONN_ID_NONE) {
(void)NetConn_IsUsed(conn_id, perr);
if (*perr != NET_CONN_ERR_NONE) {
return;
}
}
#endif
pconn = &NetTCP_ConnTbl[conn_id_tcp];
pconn->ID_Conn = conn_id; /* Set TCP conn's conn id. */
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnSetStateListen()
*
* Description : Set TCP connection to LISTEN state.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to set LISTEN state.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection state successfully set to LISTEN.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_ID Invalid network connection handle identifier.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* ------ RETURNED BY NetTCP_ConnIsUsed() : -------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
*
* Return(s) : none.
*
* Caller(s) : NetSock_Listen().
*
* This function is an INTERNAL network protocol suite function & SHOULD NOT be called by
* application function(s).
*
* Note(s) : none.
*********************************************************************************************************
*/
void NetTCP_ConnSetStateListen (NET_TCP_CONN_ID conn_id_tcp,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
CPU_BOOLEAN used;
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_transport;
NET_ERR err;
#endif
NET_TCP_CONN *pconn;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
#endif
pconn = &NetTCP_ConnTbl[conn_id_tcp];
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE CONN IDs ----------------- */
conn_id = pconn->ID_Conn;
used = NetConn_IsUsed(conn_id, &err);
if (used != DEF_YES) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
conn_id_transport = NetConn_ID_TransportGet(conn_id, &err);
if (conn_id_tcp != (NET_TCP_CONN_ID)conn_id_transport) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
#endif
/*$PAGE*/
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
pconn->ConnState = NET_TCP_CONN_STATE_LISTEN;
break;
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnReqClose()
*
* Description : (1) Request TCP connection close :
*
* (a) Handle TCP connection close See Note #2a
* (b) Update TCP connection timer See Note #2b
*
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to request close.
*
* conn_close_code Indicate whether to close transport connection :
*
* NET_CONN_CLOSE_FULL Close TCP connection but do NOT allow
* closing receive data to be available.
* NET_CONN_CLOSE_HALF Close TCP connection but allow
* closing receive data to be available.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection close successfully requested.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_INVALID_CONN_ID Invalid network connection handle identifier.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* ----- RETURNED BY NetTCP_ConnIsUsed() : -----
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
*
* ---- RETURNED BY NetTCP_TxConnClose() : -----
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID TCP connection acknowledgement NOT valid for
* current TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
* NET_TCP_ERR_TX TCP transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetSock_CloseHandlerStream().
*
* This function is an INTERNAL network protocol suite function & SHOULD NOT be called by
* application function(s).
*$PAGE*
* Note(s) : (2) (a) RFC #793, Section 3.9 'Event Processing : CLOSE Call' specifies how to handle
* close requests from the application layer :
*
* (1) For the "CLOSED STATE ... return 'error: connection does not exist'".
*
* (2) For the "LISTEN STATE ... any outstanding RECEIVEs are returned with 'error:
* closing' responses. Delete TCB [and] enter CLOSED state".
*
* (3) For the "SYN-SENT STATE ... Delete the TCB and return 'error: closing'
* responses to any queued SENDs, or RECEIVEs".
*
* (4) For the "SYN-RECEIVED STATE" ...
*
* (A) "if no SENDs have been issued and there is no pending data to send," ...
* (1) "then form a FIN segment and send it," ...
* (2) "and enter FIN-WAIT-1 state;" ...
*
* (B) "otherwise queue for processing after entering ESTABLISHED state."
*
* (5) For the "ESTABLISHED STATE" ...
*
* (A) "Queue this until all preceding SENDs have been segmentized," ...
* (B) "then form a FIN segment and send it" ...
* (C) "In any case, enter FIN-WAIT-1 state."
*
* (6) For the "FIN-WAIT-1 STATE, FIN-WAIT-2 STATE" ...
*
* (A) "Strictly speaking, this is an error and should receive a 'error: connection
* closing' response."
*
* (B) "An 'ok' response would be acceptable, too, as long as a second FIN is not
* emitted (the first FIN may be retransmitted though)."
*
* (7) For the "CLOSE-WAIT STATE" ...
*
* (A) "Queue this request until all preceding SENDs have been segmentized;" ...
* (B) "then send a FIN segment," ...
* (C) (1) "enter CLOSING state."
* (2) RFC #1122, Section 4.2.2.20.(a) amends the state transition to "enter
* LAST-ACK state, not CLOSING".
*
* (8) For the "CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE ... respond with 'error:
* connection closing'".
*
* (b) RFC #793, Section 3.9 'Event Processing : CLOSE Call' does NOT specify which timeout
* values to set for each state transition to closing state(s).
*
* #### Therefore, the following timeout values will be used for the following close
* state transitions :
*
* (1) SYN-RECEIVED STATE -> FIN-WAIT-1 STATE TCP User/Connection timeout
* See also 'NetTCP_RxPktConnHandlerSyncRxd() Note #3'.
*
* (2) ESTABLISHED STATE -> FIN-WAIT-1 STATE TCP User/Connection timeout
* See also 'NetTCP_RxPktConnHandlerConn() Note #3'.
*
* (3) CLOSE-WAIT STATE -> LAST-ACK STATE TCP Time-Wait / Two TCP Maximum
* Segment Lifetimes timeout
* See also 'NetTCP_RxPktConnHandlerLastAck() Note #3'.
*
* (c) RFC #1122, Section 4.2.2.13 states that "a TCP connection may terminate in two ways" :
*
* (1) "The normal TCP close sequence using a FIN handshake."
* (2) "An 'abort' in which one or more RST segments are sent and the connection state
* is immediately discarded."
*
* (3) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* FIN-WAIT-2 STATE' states that "if the retransmission queue is empty, the user's
* CLOSE can be acknowledged".
*
* (b) However, TCP connection should signal the application layer that "the user's close
* [is] acknowledged" whenever its re-transmit queue becomes &/or is empty :
*
* (1) Transition from LISTEN to CLOSED
* (2) Transition from SYN-SENT to CLOSED
*
* See also 'NetTCP_RxPktConnHandlerSignalClose() Note #1'.
*
* (4) On ANY errors, network resources MUST be appropriately freed :
*
* (a) Close the TCP connection.
* (b) #### Do NOT close the network or application connection(s); application layer
* responsible for closing remaining connection(s)?
*********************************************************************************************************
*/
/*$PAGE*/
void NetTCP_ConnReqClose (NET_TCP_CONN_ID conn_id_tcp,
CPU_INT08U conn_close_code,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
CPU_BOOLEAN used;
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_transport;
#endif
NET_TCP_CONN *pconn;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
#endif
pconn = &NetTCP_ConnTbl[conn_id_tcp];
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE CONN IDs ----------------- */
conn_id = pconn->ID_Conn;
used = NetConn_IsUsed(conn_id, &err);
if (used != DEF_YES) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
conn_id_transport = NetConn_ID_TransportGet(conn_id, &err);
if (conn_id_tcp != (NET_TCP_CONN_ID)conn_id_transport) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
#endif
/*$PAGE*/
/* ---------------- HANDLE CONN CLOSE ----------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #2a1. */
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #2a2. */
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #2a3. */
/* Signal app conn close (see Note #3b) ... */
NetTCP_RxPktConnHandlerSignalClose(pconn, DEF_NO, &err);
/* ... & close TCP conn. */
NetTCP_ConnCloseHandler(pconn, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_NONE;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #2a4. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN: /* See Note #2a5. */
NetTCP_TxConnClose(pconn, perr); /* Tx TCP conn close (see Note #2a5B), ... */
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ... enter fin-wait-1 state (see Note #2a5C), ... */
pconn->ConnState = NET_TCP_CONN_STATE_FIN_WAIT_1;
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN_CLOSING;
pconn->ConnCloseCode = conn_close_code;
timeout_sec = pconn->TimeoutConn_sec; /* ... & reset conn tmr (see Notes #2b1 & #2b2). */
break;
case NET_TCP_CONN_STATE_CLOSE_WAIT: /* See Note #2a7. */
NetTCP_TxConnClose(pconn, perr); /* Tx TCP conn close (see Note #2a7B), ... */
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ... enter last-ack state (see Note #2a7C2), ... */
pconn->ConnState = NET_TCP_CONN_STATE_LAST_ACK;
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN_CLOSING;
pconn->ConnCloseCode = conn_close_code;
/* ... & start time-wait tmr (see Note #2b3). */
timeout_sec = pconn->TimeoutMaxSeg_sec * NET_TCP_CONN_TIMEOUT_MAX_SEG_SCALAR;
break;
case NET_TCP_CONN_STATE_FIN_WAIT_1: /* See Note #2a6. */
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT: /* See Note #2a8. */
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* -------------------- UPDATE TMR -------------------- */
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if (err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfgMaxSegSizeLocal()
*
* Description : Configure TCP connection's local maximum segment size.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to configure local maximum segment size.
*
* max_seg_size Desired maximum segment size.
*
* Return(s) : DEF_OK, Local maximum segment size successfully configured.
*
* DEF_FAIL, otherwise.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : (1) RFC #793, Section 3.1 'Header Format : Options : Maximum Segment Size' states that
* a TCP connection advertises its "maximum receive segment size ... only ... in the
* initial connection request (i.e., in segments with the SYN control bit set)".
*
* Thus any configuration of the local receive maximum segment size MUST be performed
* by the application layer PRIOR to any TCP connection request/synchronization.
*********************************************************************************************************
*/
CPU_BOOLEAN NetTCP_ConnCfgMaxSegSizeLocal (NET_TCP_CONN_ID conn_id_tcp,
NET_TCP_SEG_SIZE max_seg_size)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
#if ((NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) || \
(NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED))
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp < NET_TCP_CONN_ID_MIN) {
return (DEF_FAIL);
}
if (conn_id_tcp > NET_TCP_CONN_ID_MAX) {
return (DEF_FAIL);
}
#endif
/* -------------- VALIDATE MAX SEG SIZE --------------- */
#if (NET_TCP_MAX_SEG_SIZE_MIN > 0)
if (max_seg_size < NET_TCP_MAX_SEG_SIZE_MIN) {
max_seg_size = NET_TCP_MAX_SEG_SIZE_MIN;
}
#endif
#if ((NET_TCP_MAX_SEG_SIZE_MAX < DEF_INT_08U_MAX_VAL) || \
((NET_TCP_MAX_SEG_SIZE_MAX < DEF_INT_16U_MAX_VAL) && (NET_TCP_MAX_SEG_SIZE_MAX > DEF_INT_08U_MAX_VAL)) || \
((NET_TCP_MAX_SEG_SIZE_MAX < DEF_INT_32U_MAX_VAL) && (NET_TCP_MAX_SEG_SIZE_MAX > DEF_INT_16U_MAX_VAL)))
if (max_seg_size > NET_TCP_MAX_SEG_SIZE_MAX) {
max_seg_size = NET_TCP_MAX_SEG_SIZE_MAX;
}
#endif
/* ------------ CFG TCP CONN MAX SEG SIZE ------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
CPU_CRITICAL_ENTER();
pconn->MaxSegSizeLocal = max_seg_size;
CPU_CRITICAL_EXIT();
return (DEF_OK);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfgRxWinSize()
*
* Description : Configure TCP connection's receive window size.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to configure receive window size.
*
* win_size Desired receive window size.
*
* Return(s) : DEF_OK, Receive window size successfully configured.
*
* DEF_FAIL, otherwise.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : (1) A TCP connection's receive window controls should NOT be updated until after the
* following TCP connection control(s) have been configured :
*
* (a) TCP connection's connection maximum segment size ('MaxSegSizeConn')
* [see 'NetTCP_RxConnWinSizeCfgUpdateTh() Note #2b']
*********************************************************************************************************
*/
CPU_BOOLEAN NetTCP_ConnCfgRxWinSize (NET_TCP_CONN_ID conn_id_tcp,
NET_TCP_WIN_SIZE win_size)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
#if ((NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) || \
(NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED))
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp < NET_TCP_CONN_ID_MIN) {
return (DEF_FAIL);
}
if (conn_id_tcp > NET_TCP_CONN_ID_MAX) {
return (DEF_FAIL);
}
#endif
/* --------------- VALIDATE RX WIN SIZE --------------- */
#if (NET_TCP_WIN_SIZE_MIN > 0)
if (win_size < NET_TCP_WIN_SIZE_MIN) {
win_size = NET_TCP_WIN_SIZE_MIN;
}
#endif
#if ((NET_TCP_WIN_SIZE_MAX < DEF_INT_08U_MAX_VAL) || \
((NET_TCP_WIN_SIZE_MAX < DEF_INT_16U_MAX_VAL) && (NET_TCP_WIN_SIZE_MAX > DEF_INT_08U_MAX_VAL)) || \
((NET_TCP_WIN_SIZE_MAX < DEF_INT_32U_MAX_VAL) && (NET_TCP_WIN_SIZE_MAX > DEF_INT_16U_MAX_VAL)))
if (win_size > NET_TCP_WIN_SIZE_MAX) {
win_size = NET_TCP_WIN_SIZE_MAX;
}
#endif
/* --------- CFG TCP CONN RX WIN SIZE --------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
CPU_CRITICAL_ENTER();
if (pconn->MaxSegSizeConn == NET_TCP_MAX_SEG_SIZE_NONE) { /* If TCP conn MSS NOT cfg'd (see Note #1a), .. */
CPU_CRITICAL_EXIT();
return (DEF_FAIL); /* .. do NOT cfg TCP conn rx win. */
}
pconn->RxWinSizeCfgd = win_size; /* Cfg new rx win size. */
if (pconn->RxWinSizeCfgdActual <= pconn->RxWinSizeCfgd) { /* If actual <= cfg'd rx win size, ... */
pconn->RxWinSizeCfgdActual = pconn->RxWinSizeCfgd; /* ... update actual rx win size. */
pconn->RxWinSizeCfgdActualUpdateRem = 0;
} else { /* Else cfg rem'ing win size update val. */
pconn->RxWinSizeCfgdActualUpdateRem = pconn->RxWinSizeCfgdActual - pconn->RxWinSizeCfgd;
}
NetTCP_RxConnWinSizeCfg(pconn); /* Cfg rx win ctrls. */
CPU_CRITICAL_EXIT();
return (DEF_OK);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfgReTxMaxTh()
*
* Description : Configure TCP connection's maximum number of same segment retransmissions.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to configure maximum number of
* same segment retransmissions.
*
* nbr_re_tx Desired maximum number of same segment retransmissions.
*
* Return(s) : DEF_OK, Maximum number of same segment retransmissions successfully configured.
*
* DEF_FAIL, otherwise.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : none.
*********************************************************************************************************
*/
CPU_BOOLEAN NetTCP_ConnCfgReTxMaxTh (NET_TCP_CONN_ID conn_id_tcp,
CPU_INT16U nbr_max_re_tx)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
#if ((NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) || \
(NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED))
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp < NET_TCP_CONN_ID_MIN) {
return (DEF_FAIL);
}
if (conn_id_tcp > NET_TCP_CONN_ID_MAX) {
return (DEF_FAIL);
}
#endif
/* ---------------- VALIDATE RE-TX TH ----------------- */
#if (NET_TCP_RE_TX_TH_MIN > DEF_INT_16U_MIN_VAL)
if (nbr_max_re_tx < NET_TCP_RE_TX_TH_MIN) {
nbr_max_re_tx = NET_TCP_RE_TX_TH_MIN;
}
#endif
#if (NET_TCP_RE_TX_TH_MAX < DEF_INT_16U_MAX_VAL)
if (nbr_max_re_tx > NET_TCP_RE_TX_TH_MAX) {
nbr_max_re_tx = NET_TCP_RE_TX_TH_MAX;
}
#endif
/* -------------- CFG TCP CONN RE-TX TH --------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
CPU_CRITICAL_ENTER();
pconn->TxSegReTxTh = nbr_max_re_tx;
CPU_CRITICAL_EXIT();
return (DEF_OK);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfgReTxMaxTimeout()
*
* Description : Configure TCP connection's maximum retransmission timeout.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to configure retransmission
* maximum timeout value.
*
* timeout_sec Desired value for TCP connection retransmission maximum timeout
* (in seconds).
*
* Return(s) : DEF_OK, TCP connection retransmission maximum timeout successfully configured.
*
* DEF_FAIL, otherwise.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : (1) (a) RFC #2988, Section 2.4 states that "a maximum value MAY be placed on RTO
* provided it is at least 60 seconds".
*
* (b) RFC #1122, Section 4.2.3.1 states that "the recommended ... RTO ... upper
* bound should be 2*MSL".
*
* (c) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2, Page 299
* states that "the timeout value ... [has] an upper limit of 64 seconds".
********************************************************************************************************
*/
CPU_BOOLEAN NetTCP_ConnCfgReTxMaxTimeout (NET_TCP_CONN_ID conn_id_tcp,
NET_TCP_TIMEOUT_SEC timeout_sec)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
#if ((NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) || \
(NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED))
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp < NET_TCP_CONN_ID_MIN) {
return (DEF_FAIL);
}
if (conn_id_tcp > NET_TCP_CONN_ID_MAX) {
return (DEF_FAIL);
}
#endif
/* ---------------- VALIDATE RTO MAX ------------------ */
/* See Note #1. */
#if (NET_TCP_TX_RTO_MAX_TIMEOUT_MIN_SEC > 0)
if (timeout_sec < NET_TCP_TX_RTO_MAX_TIMEOUT_MIN_SEC) {
timeout_sec = NET_TCP_TX_RTO_MAX_TIMEOUT_MIN_SEC;
}
#endif
#if ((NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC < DEF_INT_08U_MAX_VAL) || \
((NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC < DEF_INT_16U_MAX_VAL) && (NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC > DEF_INT_08U_MAX_VAL)) || \
((NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC < DEF_INT_32U_MAX_VAL) && (NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC > DEF_INT_16U_MAX_VAL)))
if (timeout_sec > NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC) {
timeout_sec = NET_TCP_TX_RTO_MAX_TIMEOUT_MAX_SEC;
}
#endif
/* --------------- CFG TCP CONN RTO MAX --------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
CPU_CRITICAL_ENTER();
pconn->TxRTT_RTO_Max_sec = timeout_sec;
NetTCP_TxConnRTO_CfgMaxTimeout(pconn); /* Cfg RTO ctrls. */
CPU_CRITICAL_EXIT();
return (DEF_OK);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfgTxAckImmedRxdPushEn()
*
* Description : Configure TCP connection's transmit immediate acknowledgement for received & pushed TCP
* segments enable.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to configure transmit immediate
* acknowledgement for received & pushed TCP segments enable.
*
* tx_immed_ack_en Desired value for TCP connection transmit immediate acknowledgement
* for received & pushed TCP segments enable :
*
* DEF_ENABLED TCP connection acknowledgements
* immediately transmitted for any
* pushed TCP segments received.
*
* DEF_DISABLED TCP connection acknowledgements NOT
* immediately transmitted for any
* pushed TCP segments received.
*
*
* Return(s) : DEF_OK, TCP connection transmit immediate acknowledgement for received & pushed TCP
* segments enable successfully configured.
*
* DEF_FAIL, otherwise.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : (1) See 'NetTCP_TxConnAck() Note #4a4A1'.
*********************************************************************************************************
*/
CPU_BOOLEAN NetTCP_ConnCfgTxAckImmedRxdPushEn (NET_TCP_CONN_ID conn_id_tcp,
CPU_BOOLEAN tx_immed_ack_en)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
#if ((NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) || \
(NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED))
/* ---------------- VALIDATE TCP CONN ----------------- */
if (conn_id_tcp < NET_TCP_CONN_ID_MIN) {
return (DEF_FAIL);
}
if (conn_id_tcp > NET_TCP_CONN_ID_MAX) {
return (DEF_FAIL);
}
#endif
/* ------------- VALIDATE TX IMMED ACK EN ------------- */
switch (tx_immed_ack_en) {
case DEF_ENABLED:
case DEF_DISABLED:
break;
default:
tx_immed_ack_en = DEF_ENABLED; /* See Note #1. */
break;
}
/* ----------- CFG TCP CONN TX IMMED ACK EN ----------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
CPU_CRITICAL_ENTER();
pconn->TxAckImmedRxdPushEn = tx_immed_ack_en;
CPU_CRITICAL_EXIT();
return (DEF_OK);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnIsUsed()
*
* Description : Validate TCP connection in use.
*
* Argument(s) : conn_id_tcp Handle identifier of TCP connection to validate.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection successfully validated as
* in use.
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
*
* Return(s) : DEF_YES, TCP connection valid & in use.
*
* DEF_NO, TCP connection invalid or NOT in use.
*
* Caller(s) : various.
*
* This function is an INTERNAL network protocol suite function & SHOULD NOT be called by
* application function(s).
*
* Note(s) : (1) NetTCP_ConnIsUsed() blocked until network initialization completes.
*
* (2) NetTCP_ConnIsUsed() MUST be called with the global network lock already acquired.
*********************************************************************************************************
*/
CPU_BOOLEAN NetTCP_ConnIsUsed (NET_TCP_CONN_ID conn_id_tcp,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
CPU_BOOLEAN used;
#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit (see Note #1). */
*perr = NET_ERR_INIT_INCOMPLETE;
return (DEF_NO);
}
#endif
/* --------------- VALIDATE TCP CONN ID --------------- */
if (conn_id_tcp < NET_TCP_CONN_ID_MIN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidCtr);
*perr = NET_TCP_ERR_INVALID_CONN;
return (DEF_NO);
}
if (conn_id_tcp > NET_TCP_CONN_ID_MAX) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidCtr);
*perr = NET_TCP_ERR_INVALID_CONN;
return (DEF_NO);
}
/* -------------- VALIDATE TCP CONN USED -------------- */
pconn = &NetTCP_ConnTbl[conn_id_tcp];
used = DEF_BIT_IS_SET(pconn->Flags, NET_TCP_FLAG_USED);
if (used != DEF_YES) {
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (DEF_NO);
}
*perr = NET_TCP_ERR_NONE;
return (DEF_YES);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnPoolStatGet()
*
* Description : Get TCP connection's statistics pool.
*
* Argument(s) : none.
*
* Return(s) : TCP connection statistics pool, if NO errors.
*
* NULL statistics pool, otherwise.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : (1) NetTCP_ConnPoolStatGet() blocked until network initialization completes; return NULL
* statistics pool.
*********************************************************************************************************
*/
NET_STAT_POOL NetTCP_ConnPoolStatGet (void)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
NET_ERR err;
#endif
NET_STAT_POOL stat_pool;
#if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED)
if (Net_InitDone != DEF_YES) { /* If init NOT complete, ... */
NetStat_PoolClr(&stat_pool, &err);
return (stat_pool); /* ... rtn NULL stat pool (see Note #1). */
}
#endif
CPU_CRITICAL_ENTER();
stat_pool = NetTCP_ConnPoolStat;
CPU_CRITICAL_EXIT();
return (stat_pool);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnPoolStatResetMaxUsed()
*
* Description : Reset TCP connection's statistics pool's maximum number of entries used.
*
* Argument(s) : none.
*
* Return(s) : none.
*
* Caller(s) : Application.
*
* This function is a network protocol suite application interface (API) function & MAY be
* called by application function(s).
*
* Note(s) : none.
*********************************************************************************************************
*/
void NetTCP_ConnPoolStatResetMaxUsed (void)
{
NET_ERR err;
NetStat_PoolResetUsedMax(&NetTCP_ConnPoolStat, &err);
}
/*$PAGE*/
/*
*********************************************************************************************************
*********************************************************************************************************
* LOCAL FUNCTIONS
*********************************************************************************************************
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* NetTCP_RxPktValidateBuf()
*
* Description : Validate received buffer header as TCP protocol.
*
* Argument(s) : pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Received buffer's TCP header validated.
* NET_ERR_INVALID_PROTOCOL Buffer's protocol type is NOT TCP.
* NET_BUF_ERR_INVALID_IX Invalid buffer index.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_Rx().
*
* Note(s) : none.
*********************************************************************************************************
*/
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static void NetTCP_RxPktValidateBuf (NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
/* --------------- VALIDATE TCP BUF HDR --------------- */
if (pbuf_hdr->ProtocolHdrType != NET_PROTOCOL_TYPE_TCP) {
NET_CTR_ERR_INC(Net_ErrInvalidProtocolCtr);
*perr = NET_ERR_INVALID_PROTOCOL;
return;
}
if (pbuf_hdr->TCP_UDP_HdrDataIx == NET_BUF_IX_NONE) {
NET_CTR_ERR_INC(NetTCP_ErrRxInvalidBufIxCtr);
*perr = NET_BUF_ERR_INVALID_IX;
return;
}
*perr = NET_TCP_ERR_NONE;
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktValidate()
*
* Description : (1) Validate received TCP packet :
*
* (a) Get TCP packet RTT timestamp received. See 'NetTCP_TxConnRTT_RTO_Calc()
* Note #2a2A2'
*
* (b) (1) Validate the received packet's following TCP header fields :
*
* (A) Source Port
* (B) Destination Port
* (C) Header Length
* (D) Segment Length See Note #3
* (E) Flags
* (F) Check-Sum See Note #4
* (G) Options
*
* (2) Validation ignores the following TCP header fields :
*
* (A) Sequence Number
* (B) Acknowledgement Number
* (C) Window Advertisement
* (D) Urgent Pointer See 'net_tcp.c Note #1b'
*
* (c) Convert the following TCP header fields from network-order to host-order :
*
* (1) Source Port See Note #1cB1
* (2) Destination Port See Note #1cB2
* (3) Sequence Number See Note #1cB3
* (4) Acknowledgement Number See Note #1cB4
* (5) Header Length/Flags See Note #1cB5
* (6) Window Advertisement See Note #1cB6
* (7) Check-Sum See Note #4f
* (8) Urgent Pointer See 'net_tcp.c Note #1b'
*
* (A) These fields are NOT converted directly in the received packet buffer's
* data area but are converted in local or network buffer variables ONLY.
*
* (B) The following TCP header fields are converted & stored in network buffer
* variables :
*
* (1) Source Port
* (2) Destination Port
* (3) Sequence Number
* (4) Acknowledgement Number
* (5) Header Length/Flags
* (6) Window Advertisement
*
* (d) Update network buffer's protocol controls.
*
*
* Argument(s) : pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header.
* -------- Argument validated in NetTCP_Rx().
*
* ptcp_hdr Pointer to received packet's TCP header.
* -------- Argument validated in NetTCP_Rx()/NetTCP_RxPktValidateBuf().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Received packet validated.
* NET_TCP_ERR_INVALID_PORT_NBR Invalid TCP port number.
* NET_TCP_ERR_INVALID_LEN_HDR Invalid TCP header length.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP segment length.
* NET_TCP_ERR_INVALID_LEN_DATA Invalid TCP data length.
* NET_TCP_ERR_INVALID_FLAG Invalid TCP flags.
* NET_TCP_ERR_INVALID_CHK_SUM Invalid TCP check-sum.
*
* - RETURNED BY NetTCP_RxPktValidateOpt() : -
* NET_TCP_ERR_INVALID_OPT_LEN Invalid TCP option length.
* NET_TCP_ERR_INVALID_OPT_END Invalid TCP option list ending.
* NET_TCP_ERR_INVALID_OPT_NBR Invalid TCP option number of same option.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_Rx().
*$PAGE*
* Note(s) : (2) See 'net_tcp.h TCP HEADER' for TCP header format.
*
* (3) Since TCP segment headers do NOT contain a segment length field, the TCP Segment Length
* is assumed to be the remaining IP Datagram Length.
*
* (4) (a) TCP header Check-Sum field MUST be validated BEFORE (or AFTER) any multi-octet words
* are converted from network-order to host-order since "the sum of 16-bit integers can
* be computed in either byte order" [RFC #1071, Section 2.(B)].
*
* In other words, the TCP Segment Check-Sum CANNOT be validated AFTER SOME but NOT ALL
* multi-octet words have been converted from network-order to host-order.
*
* (b) However, ALL received packets' multi-octet words are converted in local or network
* buffer variables ONLY (see Note #1cA). Therefore, TCP Segment Check-Sum may be
* validated at any point.
*
* (c) The TCP Segment Check-Sum MUST be validated AFTER the TCP segment length has been
* validated so that the total TCP Segment Length (in octets) will already be calculated
* for the TCP Check-Sum calculation.
*
* For efficiency, the TCP Segment Check-Sum is validated AFTER all other TCP header
* fields have been validated. Thus, the iteration-intensive TCP Segment Check-Sum is
* calculated only after all other TCP header fields have been quickly validated.
*
* (d) (1) In addition to the TCP segment header & data, the TCP Check-Sum calculation
* includes "a 96-bit pseudo header conceptually prefixed to the TCP header ...
* [which] contains the Source Address, the Destination Address, the Protocol,
* and TCP length" (see RFC #793, Section 3.1 'Header Format : Checksum').
*
* (2) Since network check-sum functions REQUIRE that 16-bit one's-complement check-
* sum calculations be performed on headers & data arranged in network-order (see
* 'net_util.c NetUtil_16BitOnesCplChkSumDataVerify() Note #4'), TCP pseudo-header
* values MUST be set or converted to network-order.
*
* (e) RFC #793, Section 3.1 'Header Format : Checksum' specifies that "if a segment contains
* an odd number of header and text octets ... the last octet is padded ... with zeros to
* form a 16-bit word for checksum purposes".
*
* See also 'net_util.c NetUtil_16BitSumDataCalc() Note #8'.
*
* (f) After the TCP Segment Check-Sum is validated, it is NOT necessary to convert the Check-
* Sum from network-order to host-order since it is NOT required for further processing.
*
* (5) (a) Since the minimum network buffer size MUST be configured such that the entire TCP
* header MUST be received in a single packet (see 'net_buf.h NETWORK BUFFER INDEX &
* SIZE DEFINES Note #1c'), after the TCP header size is decremented from the first
* packet buffer's remaining number of data octets, any remaining octets MUST be user
* &/or application data octets.
*
* (1) Note that the 'Data' index is updated regardless of a null-size data length.
*
* (b) If additional packet buffers exist, the remaining IP datagram 'Data' MUST be user
* &/or application data. Therefore, the 'Data' length does NOT need to be adjusted
* but the 'Data' index MUST be updated.
*
* (c) #### Total TCP Segment Length & Data Length is duplicated in ALL fragmented packet
* buffers (may NOT be necessary; remove if unnecessary).
*
* (6) RFC #1122, Sections 3.2.1 & 3.2.2 require that IP & ICMP packets with certain invalid
* header fields be "silently discarded". However, NO RFC specifies how TCP should handle
* received segments with invalid header fields.
*
* Therefore, it is assumed that ALL TCP segments with ANY invalid header fields SHOULD
* be silently discarded.
*********************************************************************************************************
*/
static void NetTCP_RxPktValidate (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_HDR *ptcp_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_INT08U tcp_hdr_len_tot;
CPU_INT16U tcp_hdr_len;
CPU_INT16U tcp_tot_len;
CPU_INT16U tcp_data_len;
CPU_INT16U tcp_flags;
CPU_INT16U tcp_flags_reserved;
CPU_BOOLEAN tcp_chk_sum_valid;
NET_TCP_PSEUDO_HDR tcp_pseudo_hdr;
NET_BUF *pbuf_next;
NET_BUF_HDR *pbuf_next_hdr;
/*$PAGE*/
/* ---------------- GET TCP RTT RX TS ----------------- */
pbuf_hdr->TCP_RTT_TS_Rxd_ms = (CPU_INT32U)NetTCP_TxConnRTT_GetTS_ms();
/* ---------------- VALIDATE TCP PORTS ---------------- */
NET_UTIL_VAL_COPY_GET_NET_16(&pbuf_hdr->TCP_UDP_PortSrc, &ptcp_hdr->PortSrc);
if (pbuf_hdr->TCP_UDP_PortSrc == NET_TCP_PORT_NBR_RESERVED) {
NET_CTR_ERR_INC(NetTCP_ErrRxHdrPortSrcCtr);
*perr = NET_TCP_ERR_INVALID_PORT_NBR;
return;
}
NET_UTIL_VAL_COPY_GET_NET_16(&pbuf_hdr->TCP_UDP_PortDest, &ptcp_hdr->PortDest);
if (pbuf_hdr->TCP_UDP_PortDest == NET_TCP_PORT_NBR_RESERVED) {
NET_CTR_ERR_INC(NetTCP_ErrRxHdrPortDestCtr);
*perr = NET_TCP_ERR_INVALID_PORT_NBR;
return;
}
/* --------------- VALIDATE TCP HDR LEN --------------- */
/* See 'net_tcp.h TCP HEADER Note #2'. */
NET_UTIL_VAL_COPY_GET_NET_16(&pbuf_hdr->TCP_HdrLen_Flags, &ptcp_hdr->HdrLen_Flags);
tcp_hdr_len = pbuf_hdr->TCP_HdrLen_Flags & NET_TCP_HDR_LEN_MASK;
tcp_hdr_len >>= NET_TCP_HDR_LEN_SHIFT;
if (tcp_hdr_len < NET_TCP_HDR_LEN_MIN) { /* If hdr len < min hdr len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_HDR;
return;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (tcp_hdr_len > NET_TCP_HDR_LEN_MAX) { /* If hdr len > max hdr len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_HDR;
return;
}
#endif
tcp_hdr_len_tot = tcp_hdr_len * NET_TCP_HDR_LEN_WORD_SIZE;
/* ------------- VALIDATE TCP SEG TOT LEN ------------- */
tcp_tot_len = pbuf_hdr->IP_DatagramLen; /* See Note #3. */
pbuf_hdr->TCP_UDP_TotLen = tcp_tot_len;
if (pbuf_hdr->TCP_UDP_TotLen < NET_TCP_TOT_LEN_MIN) { /* If seg tot len < min tot len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrSegLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_SEG;
return;
}
if (pbuf_hdr->TCP_UDP_TotLen > NET_TCP_TOT_LEN_MAX) { /* If seg tot len > max tot len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrSegLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_SEG;
return;
}
/* ---------------- VALIDATE TCP FLAGS ---------------- */
/* See 'net_tcp.h TCP HEADER Note #2'. */
#if 1 /* ???? Allow invalid reserved flags for rx'd segs? */
tcp_flags = pbuf_hdr->TCP_HdrLen_Flags & NET_TCP_HDR_FLAG_MASK;
tcp_flags_reserved = DEF_BIT_IS_SET_ANY(tcp_flags, NET_TCP_HDR_FLAG_RESERVED);
if (tcp_flags_reserved != DEF_NO) { /* If reserved flag bits set, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrFlagsCtr);
*perr = NET_TCP_ERR_INVALID_FLAG;
return;
}
#endif
pbuf_hdr->TCP_SegSync = DEF_BIT_IS_SET(pbuf_hdr->TCP_HdrLen_Flags, NET_TCP_HDR_FLAG_SYNC );
pbuf_hdr->TCP_SegClose = DEF_BIT_IS_SET(pbuf_hdr->TCP_HdrLen_Flags, NET_TCP_HDR_FLAG_CLOSE);
pbuf_hdr->TCP_SegAck = DEF_BIT_IS_SET(pbuf_hdr->TCP_HdrLen_Flags, NET_TCP_HDR_FLAG_ACK );
pbuf_hdr->TCP_SegReset = DEF_BIT_IS_SET(pbuf_hdr->TCP_HdrLen_Flags, NET_TCP_HDR_FLAG_RESET);
/*$PAGE*/
/* ---------------- VALIDATE TCP OPTS ----------------- */
if (tcp_hdr_len_tot > NET_TCP_HDR_SIZE_MIN) { /* If hdr len > min, validate/process TCP opts. */
NetTCP_RxPktValidateOpt(pbuf_hdr, ptcp_hdr, tcp_hdr_len_tot, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
/* --------------- VALIDATE TCP CHK SUM --------------- */
/* See Note #4. */
/* Prepare TCP chk sum pseudo-hdr (see Note #4d). */
tcp_pseudo_hdr.AddrSrc = (NET_IP_ADDR)NET_UTIL_HOST_TO_NET_32(pbuf_hdr->IP_AddrSrc);
tcp_pseudo_hdr.AddrDest = (NET_IP_ADDR)NET_UTIL_HOST_TO_NET_32(pbuf_hdr->IP_AddrDest);
tcp_pseudo_hdr.Zero = (CPU_INT08U )0x00;
tcp_pseudo_hdr.Protocol = (CPU_INT08U )NET_IP_HDR_PROTOCOL_TCP;
tcp_pseudo_hdr.TotLen = (CPU_INT16U )NET_UTIL_HOST_TO_NET_16(pbuf_hdr->TCP_UDP_TotLen);
tcp_chk_sum_valid = NetUtil_16BitOnesCplChkSumDataVerify((void *) pbuf,
(void *)&tcp_pseudo_hdr,
(CPU_INT16U) NET_TCP_PSEUDO_HDR_SIZE,
(NET_ERR *) perr);
if (tcp_chk_sum_valid != DEF_OK) {
NET_CTR_ERR_INC(NetTCP_ErrRxHdrChkSumCtr);
*perr = NET_TCP_ERR_INVALID_CHK_SUM;
return;
}
#if 0 /* See Note #4f. */
(void)NET_UTIL_VAL_GET_NET_16(&ptcp_hdr->ChkSum);
#endif
/* ---------------- CONVERT TCP FIELDS ---------------- */
/* See Note #1c. */
NET_UTIL_VAL_COPY_GET_NET_32(&pbuf_hdr->TCP_SeqNbr, &ptcp_hdr->SeqNbr);
NET_UTIL_VAL_COPY_GET_NET_32(&pbuf_hdr->TCP_AckNbr, &ptcp_hdr->AckNbr);
NET_UTIL_VAL_COPY_GET_NET_16(&pbuf_hdr->TCP_WinSize, &ptcp_hdr->WinSize);
/* ----------------- UPDATE BUF CTRLS ----------------- */
/* Calc TCP data len/ix (see Note #5a). */
pbuf_hdr->TCP_UDP_HdrLen = tcp_hdr_len_tot;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (pbuf_hdr->TCP_UDP_HdrLen > tcp_tot_len) {
NET_CTR_ERR_INC(NetTCP_ErrRxHdrDataLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_DATA;
return;
}
if (pbuf_hdr->TCP_UDP_HdrLen > pbuf_hdr->DataLen) {
NET_CTR_ERR_INC(NetTCP_ErrRxHdrDataLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_DATA;
return;
}
#endif
tcp_data_len = tcp_tot_len - pbuf_hdr->TCP_UDP_HdrLen;
pbuf_hdr->TCP_UDP_DataLen = tcp_data_len;
pbuf_hdr->TCP_SegLenInit = pbuf_hdr->TCP_UDP_DataLen;
pbuf_hdr->TCP_SegLen = pbuf_hdr->TCP_SegLenInit;
pbuf_hdr->TCP_SegLenData = pbuf_hdr->TCP_SegLenInit;
pbuf_hdr->TCP_SeqNbrInit = pbuf_hdr->TCP_SeqNbr;
pbuf_hdr->DataLen -= (NET_BUF_SIZE) pbuf_hdr->TCP_UDP_HdrLen;
pbuf_hdr->DataIx = (CPU_INT16U )(pbuf_hdr->TCP_UDP_HdrDataIx + pbuf_hdr->TCP_UDP_HdrLen);
pbuf_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_APP;
pbuf_next = (NET_BUF *)pbuf_hdr->NextBufPtr;
while (pbuf_next != (NET_BUF *)0) { /* Calc ALL pkt bufs' data len/ix (see Note #5b). */
pbuf_next_hdr = &pbuf_next->Hdr;
pbuf_next_hdr->DataIx = pbuf_next_hdr->TCP_UDP_HdrDataIx;
pbuf_next_hdr->TCP_UDP_HdrLen = 0; /* NULL TCP hdr len in each pkt buf. */
pbuf_next_hdr->TCP_UDP_TotLen = tcp_tot_len; /* Dup TCP tot len & ... */
pbuf_next_hdr->TCP_UDP_DataLen = tcp_data_len; /* ... data len in each pkt buf (see Note #5c). */
pbuf_next_hdr->TCP_SegLenInit = pbuf_next_hdr->TCP_UDP_DataLen;
pbuf_next_hdr->TCP_SegLen = pbuf_next_hdr->TCP_SegLenInit;
pbuf_next_hdr->TCP_SegLenData = pbuf_next_hdr->TCP_SegLenInit;
pbuf_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_APP;
pbuf_next = (NET_BUF *)pbuf_next_hdr->NextBufPtr;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktValidateOpt()
*
* Description : Validate & process received packet's TCP options.
*
* Argument(s) : pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* ptcp_hdr Pointer to received packet's TCP header.
* -------- Argument validated in NetTCP_Rx()/NetTCP_RxPktValidateBuf().
*
* tcp_hdr_len_size Length of received packet's TCP header.
* ---------------- Argument validated in NetTCP_RxPktValidate().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP options validated & processed.
* NET_TCP_ERR_INVALID_OPT_LEN Invalid TCP option length.
* NET_TCP_ERR_INVALID_OPT_END Invalid TCP option list ending.
* NET_TCP_ERR_INVALID_OPT_NBR Invalid TCP option number of same option.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktValidate().
*
* Note(s) : (1) (a) See 'net_tcp.h TCP HEADER OPTIONS DEFINES' for supported TCP options' summary.
*
* (b) See 'net_tcp.c Note #1c' for unsupported TCP options.
*
* See also Note #2b3.
*
* (2) (a) RFC # 793, Section 3.1 'Options' states that each option is "a multiple of 8 bits
* in length" and "may begin on any octet boundary".
*
* (1) Since TCP options are NOT required or guaranteed to align multi-octet words on
* appropriate word boundaries, ALL TCP options are decoded & processed a single
* octet at a time.
*
* (b) RFC #1122, Section 4.2.2.5 states that ... :
*
* (1) "A TCP MUST be able to receive a TCP option in any segment."
*
* (2) "A TCP MUST ignore without error any TCP option it does not implement, assuming
* that the option has a field length" ...
*
* (3) "All TCP options defined in the future will have length fields."
*
* See also 'net_tcp.h TCP HEADER OPTIONS DEFINES Note #2b'.
*********************************************************************************************************
*/
static void NetTCP_RxPktValidateOpt (NET_BUF_HDR *pbuf_hdr,
NET_TCP_HDR *ptcp_hdr,
CPU_INT08U tcp_hdr_len_size,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_INT08U *popts;
CPU_INT08U *popt;
CPU_INT08U opt_list_len_size;
CPU_INT08U opt_list_len_rem;
CPU_INT08U opt_len;
CPU_INT08U opt_nbr_max_seg_size;
CPU_BOOLEAN opt_err;
CPU_BOOLEAN opt_list_end;
opt_list_len_size = tcp_hdr_len_size - NET_TCP_HDR_SIZE_MIN; /* Calc opt list len size. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------- VALIDATE TCP HDR OPT LIST SIZE -------- */
if (opt_list_len_size > NET_TCP_HDR_OPT_SIZE_MAX) { /* If tot opt len > max opt size, ... */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN; /* ... rtn err. */
return;
}
if ((opt_list_len_size % NET_TCP_HDR_OPT_SIZE_WORD) != 0) { /* If tot opt len NOT multiple of opt size, ... */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN; /* ... rtn err. */
return;
}
#endif
/*$PAGE*/
opt_err = DEF_NO;
opt_list_end = DEF_NO;
opt_nbr_max_seg_size = 0;
popts = (CPU_INT08U *)&ptcp_hdr->Opts[0];
opt_list_len_rem = opt_list_len_size;
/* ------------- DECODE/VALIDATE TCP OPTS ------------- */
while (opt_list_len_rem > 0) { /* Process each opt in list (see Notes #1 & #2). */
switch (*popts) {
case NET_TCP_HDR_OPT_END_LIST: /* ------------------- END OPT LIST ------------------- */
opt_list_end = DEF_YES; /* Mark end of opt list. */
opt_len = NET_TCP_HDR_OPT_LEN_END_LIST;
break;
case NET_TCP_HDR_OPT_NOP: /* --------------------- NOP OPT ---------------------- */
#if 1 /* ???? NOP's invalid after END? */
if (opt_list_end != DEF_NO) { /* If opt found AFTER end of opt list, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_END;
return;
}
#endif
opt_len = NET_TCP_HDR_OPT_LEN_NOP;
break;
case NET_TCP_HDR_OPT_MAX_SEG_SIZE: /* ----------------- MAX SEG SIZE OPT ----------------- */
if (opt_list_end != DEF_NO) { /* If opt found AFTER end of opt list, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_END;
return;
}
if (opt_nbr_max_seg_size > 0) { /* If > 1 max seg size opt, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_NBR;
return;
}
opt_nbr_max_seg_size++;
opt_err = NetTCP_RxPktValidateOptMaxSegSize(pbuf_hdr, popts, &opt_len, perr);
break;
#if 0 /* --------------- UNSUPPORTED TCP OPTS --------------- */
/* See Notes #1b & #2b2. */
case NET_TCP_HDR_OPT_WIN_SCALE:
case NET_TCP_HDR_OPT_SACK_PERMIT:
case NET_TCP_HDR_OPT_SACK:
case NET_TCP_HDR_OPT_ECHO_REQ:
case NET_TCP_HDR_OPT_ECHO_REPLY:
case NET_TCP_HDR_OPT_TS:
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'default'. */
#endif
default: /* ----------------- UNKNOWN TCP OPTS ----------------- */
popt = popts;
popt++;
opt_len = *popt; /* Validate opt len (see Note #2b3). */
if (opt_len < NET_TCP_HDR_OPT_LEN_MIN_LEN) { /* If opt len < min opt len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return;
}
break;
}
if (opt_err != DEF_NO) { /* If ANY opt errs, rtn err. */
return;
}
if (opt_len > opt_list_len_rem) { /* If opt len > rem opt list len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return;
}
opt_list_len_rem -= opt_len;
popts += opt_len;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktValidateOptMaxSegSize()
*
* Description : Validate & process received TCP Maximum Segment Size option.
*
* Argument(s) : pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* popt Pointer to Maximum Segment Size option.
* ---- Argument validated in NetTCP_RxPktValidateOpt().
*
* popt_len Pointer to variable that will receive the TCP option length (in octets).
* -------- Argument validated in NetTCP_RxPktValidateOpt().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP option validated & processed.
* NET_TCP_ERR_INVALID_OPT_LEN Invalid TCP option length.
*
* Return(s) : DEF_NO, NO Maximum Segment Size option error.
*
* DEF_YES, otherwise.
*
* Caller(s) : NetTCP_RxPktValidateOpt().
*
* Note(s) : (1) See 'net_tcp.h TCP HEADER OPTIONS DEFINES Note #2b1' for TCP Maximum Segment Size
* option summary.
*
* (2) (a) RFC # 793, Section 3.1 'Options' states that each option is "a multiple of 8 bits
* in length" and "may begin on any octet boundary".
*
* (b) Since TCP options are NOT required or guaranteed to align multi-octet words on
* appropriate word boundaries, ALL TCP options are decoded & processed a single
* octet at a time.
*********************************************************************************************************
*/
static CPU_BOOLEAN NetTCP_RxPktValidateOptMaxSegSize (NET_BUF_HDR *pbuf_hdr,
CPU_INT08U *popt,
CPU_INT08U *popt_len,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_SEG_SIZE max_seg_size;
*popt_len = NET_TCP_HDR_OPT_LEN_MAX_SEG_SIZE;
popt++;
if (*popt != *popt_len) { /* If opt len != max seg size opt len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return (DEF_YES);
}
/* Calc max seg size (see Note #2b). */
popt++;
max_seg_size = *popt;
max_seg_size <<= DEF_OCTET_NBR_BITS;
popt++;
max_seg_size += *popt;
if (max_seg_size > NET_TCP_MAX_SEG_SIZE_MAX) { /* If max seg size > max, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrRxHdrOptsCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return (DEF_YES);
}
pbuf_hdr->TCP_MaxSegSize = (CPU_INT16U)max_seg_size;
*perr = NET_TCP_ERR_NONE;
return (DEF_NO);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktDemuxSeg()
*
* Description : (1) Demultiplex received packet to appropriate TCP connection :
*
* (a) Search connection lists for connection whose local &/or remote addresses are
* identical to the received packet's destination & source addresses.
*
* (b) Update network buffer's connection controls.
*
*
* Argument(s) : pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Received packet successfully demultiplexed
* to appropriate TCP connection.
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number(s).
* NET_ERR_RX_DEST Invalid destination; no connection available
* for received packet.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_Rx().
*
* Note(s) : (2) The 'SRCH CONN LIST(S) FOR PKT/CONN ADDR(S)' pre-processor 'else'-conditional code will
* never be compiled/linked since 'net_conn.h' ensures that the family type configuration
* constant (NET_CONN_CFG_FAMILY) is configured with an appropriate family type value
* (see 'net_conn.h CONFIGURATION ERRORS'). The 'else'-conditional code is included for
* completeness & as an extra precaution in case 'net_conn.h' is incorrectly modified.
*
* (3) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : CLOSED [State]' states
* that "an incoming segment ... causes a RST to be sent in response".
*
* (b) RFC #792, Section 'Destination Unreachable Message : Description' states that
* "if, in the destination host, the IP module cannot deliver the datagram because
* the indicated ... process port is not active, the destination host may send a
* destination unreachable message to the source host".
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktDemuxSeg (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
NET_IP_ADDR addr_ip;
#endif
CPU_INT08U addr_local[NET_CONN_CFG_ADDR_LEN];
CPU_INT08U addr_remote[NET_CONN_CFG_ADDR_LEN];
NET_TCP_PORT_NBR port_nbr;
NET_CONN_LIST_IX protocol_ix;
NET_CONN_FAMILY family;
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_transport;
NET_CONN_ID conn_id_app;
NET_ERR err;
/* ---- SRCH CONN LIST(S) FOR PKT/CONN ADDR(S) ---- */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
family = NET_CONN_FAMILY_IP_V4_SOCK;
protocol_ix = NET_CONN_LIST_IX_IP_V4_SOCK_TCP;
/* Cfg srch local addr as pkt dest addr. */
port_nbr = (NET_TCP_PORT_NBR)NET_UTIL_HOST_TO_NET_16(pbuf_hdr->TCP_UDP_PortDest);
addr_ip = (NET_IP_ADDR )NET_UTIL_HOST_TO_NET_32(pbuf_hdr->IP_AddrDest);
Mem_Copy((void *)&addr_local[NET_CONN_ADDR_IP_IX_PORT],
(void *)&port_nbr,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_PORT);
Mem_Copy((void *)&addr_local[NET_CONN_ADDR_IP_IX_ADDR],
(void *)&addr_ip,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
/* Cfg srch remote addr as pkt src addr. */
port_nbr = (NET_TCP_PORT_NBR)NET_UTIL_HOST_TO_NET_16(pbuf_hdr->TCP_UDP_PortSrc);
addr_ip = (NET_IP_ADDR )NET_UTIL_HOST_TO_NET_32(pbuf_hdr->IP_AddrSrc);
Mem_Copy((void *)&addr_remote[NET_CONN_ADDR_IP_IX_PORT],
(void *)&port_nbr,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_PORT);
Mem_Copy((void *)&addr_remote[NET_CONN_ADDR_IP_IX_ADDR],
(void *)&addr_ip,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
#else /* See Note #2. */
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
/*$PAGE*/
conn_id = NetConn_Srch((NET_CONN_FAMILY ) family, /* Srch for TCP conn whose local/remote addrs ... */
(NET_CONN_LIST_IX ) protocol_ix, /* ... are identical to pkt dest/src addrs. */
(NET_CONN_LIST_TYPE) NET_CONN_LIST_TYPE_ALL,
(CPU_BOOLEAN ) DEF_YES,
(CPU_INT08U *)&addr_local[0],
(CPU_INT08U *)&addr_remote[0],
(NET_CONN_ADDR_LEN ) NET_CONN_CFG_ADDR_LEN,
(NET_CONN_ID *)&conn_id_transport,
(NET_CONN_ID *)&conn_id_app);
if (conn_id == NET_CONN_ID_NONE) { /* If complete TCP conn NOT found, .. */
conn_id = NetConn_Srch((NET_CONN_FAMILY ) family, /* .. srch for TCP half-conn whose local addr .. */
(NET_CONN_LIST_IX ) protocol_ix, /* .. is identical to pkt dest addr. */
(NET_CONN_LIST_TYPE) NET_CONN_LIST_TYPE_ALL,
(CPU_BOOLEAN ) DEF_NO,
(CPU_INT08U *)&addr_local[0],
(CPU_INT08U *) 0,
(NET_CONN_ADDR_LEN ) NET_CONN_CFG_ADDR_LEN,
(NET_CONN_ID *)&conn_id_transport,
(NET_CONN_ID *)&conn_id_app);
if (conn_id == NET_CONN_ID_NONE) { /* If NO TCP conn found, ... */
NetTCP_TxConnReset((NET_TCP_CONN *) 0, /* ... tx TCP conn reset (see Note #3a), ... */
(NET_BUF_HDR *) pbuf_hdr,
(NET_TCP_RESET_CODE) NET_TCP_CONN_TX_RESET,
(NET_TCP_CLOSE_CODE) NET_TCP_CONN_CLOSE_ALL,
(NET_ERR *)&err);
NetICMP_TxMsgErr(pbuf, /* ... tx ICMP port unreach (see Note #3b), ... */
NET_ICMP_MSG_TYPE_DEST_UNREACH,
NET_ICMP_MSG_CODE_DEST_PORT,
NET_ICMP_MSG_PTR_NONE,
&err);
NET_CTR_ERR_INC(NetTCP_ErrRxDestCtr);
*perr = NET_ERR_RX_DEST; /* ... & rtn dest err. */
return;
} else {
pbuf_hdr->ConnType = NET_CONN_TYPE_CONN_HALF;
}
} else {
pbuf_hdr->ConnType = NET_CONN_TYPE_CONN_FULL;
}
/* ------------ UPDATE BUF CONN CTRLS ------------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (conn_id == NET_CONN_ID_NONE) {
*perr = NET_CONN_ERR_INVALID_CONN;
return;
}
if (conn_id_transport == NET_CONN_ID_NONE) {
*perr = NET_CONN_ERR_INVALID_CONN;
return;
}
#endif
pbuf_hdr->Conn_ID = (CPU_INT16S)conn_id;
pbuf_hdr->Conn_ID_Transport = (CPU_INT16S)conn_id_transport;
pbuf_hdr->Conn_ID_App = (CPU_INT16S)conn_id_app;
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandler()
*
* Description : (1) Handle received TCP packets for its TCP connection :
*
* (a) Demultiplex TCP packet to appropriate TCP connection state handler
* (b) Free/Discard TCP packet
* (c) Update receive statistics See Note #2
*
*
* Argument(s) : pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for later processing.
* NET_TCP_ERR_CONN_RESET_VALID Received reset segment successfully handled;
* i.e. the TCP connection was reset.
* NET_TCP_ERR_CONN_CLOSED TCP connection successfully closed.
*
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
*
* ---- RETURNED BY NetTCP_ConnIsUsed() : -----
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN Invalid TCP connection number.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
*
* --- RETURNED BY NetTCP_RxPktDiscard() : ----
* NET_ERR_RX Receive error; packet discarded.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_Rx().
*
* Note(s) : (2) (a) SOME TCP receive statistics updated in NetTCP_RxPktDiscard(); do NOT re-update.
*
* (b) Update TCP receive statistics even if any transitory transmit error(s) occur in
* TCP connection state handler functions.
*
* (3) RFC #1122, Section 4.2.2.13 states that "a host MAY implement a 'half-duplex' TCP
* close sequence ... i.e., closed in only one direction, and a host is permitted to
* continue sending data in the open direction on a half-closed connection".
*
* (a) "A host ... that has called CLOSE cannot continue to read data from the
* connection. If such a host issues a CLOSE call while received data is
* still pending ... its TCP SHOULD send a RST to show that data was lost."
*
* However, since it does NOT seem reasonable to allow a half-closed connection
* "to continue sending data in the open direction" (i.e. from the host that did
* NOT issue a CLOSE call) but prevent the receiving host (i.e. the host that DID
* issue the CLOSE call) from receiving the transmitted data; it is assumed that
* the host that issued the CLOSE call MUST be allowed to receive data transmitted
* from the other host that has NOT yet issued its CLOSE.
*
* (b) However, "if such a host issues a CLOSE call ... [and] new data is received
* after CLOSE is called, its TCP SHOULD send a RST to show that data was lost".
*
* In other words, since a TCP connection in the connection-closing-data-available
* state is closed to further TCP data or controls, a TCP reset is transmitted as
* for the CLOSED state.
*
* (c) "Some systems have not implemented half-closed connections."
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandler (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if (((NET_CTR_CFG_STAT_EN == DEF_ENABLED) || \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN_ID conn_id_tcp;
NET_TCP_CONN *pconn;
NET_ERR err;
conn_id_tcp = (NET_TCP_CONN_ID)pbuf_hdr->Conn_ID_Transport;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN USED -------------- */
(void)NetTCP_ConnIsUsed(conn_id_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
#endif
/*$PAGE*/
pconn = &NetTCP_ConnTbl[conn_id_tcp];
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN:
NetTCP_RxPktConnHandlerListen(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_SEQ_FIN_INVALID:
case NET_TCP_ERR_CONN_LISTEN_Q_MAX:
case NET_TCP_ERR_INVALID_CONN_ID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_ERR_TX:
case NET_CONN_ERR_NOT_USED:
case NET_CONN_ERR_INVALID_CONN:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
NetTCP_RxPktConnHandlerSyncRxd(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_SYNC_TXD:
NetTCP_RxPktConnHandlerSyncTxd(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_SEQ_FIN_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_CONN:
NetTCP_RxPktConnHandlerConn(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_FIN_WAIT_1:
NetTCP_RxPktConnHandlerFinWait1(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_ID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
case NET_CONN_ERR_INVALID_CONN:
case NET_CONN_ERR_NOT_USED:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_FIN_WAIT_2:
NetTCP_RxPktConnHandlerFinWait2(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_NONE_AVAIL:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CLOSING:
NetTCP_RxPktConnHandlerClosing(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_ID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
case NET_CONN_ERR_INVALID_CONN:
case NET_CONN_ERR_NOT_USED:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_TIME_WAIT:
NetTCP_RxPktConnHandlerTimeWait(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_NONE_AVAIL:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CLOSE_WAIT:
NetTCP_RxPktConnHandlerCloseWait(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_LAST_ACK:
NetTCP_RxPktConnHandlerLastAck(pconn, pbuf, pbuf_hdr, perr);
switch (*perr) {
case NET_TCP_ERR_CONN_RESET_VALID:
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_CLOSED:
NetTCP_RxPktFree(pbuf);
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_ERR_CONN_DATA_VALID'. */
case NET_TCP_ERR_CONN_DATA_VALID:
NET_CTR_STAT_INC(NetTCP_StatRxSegProcessedCtr);
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_SEQ_SYNC_INVALID:
case NET_TCP_ERR_CONN_SEQ_INVALID:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_RESET_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_CONN_DATA_DUP:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
case NET_TCP_ERR_NONE_AVAIL:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NetTCP_TxConnReset((NET_TCP_CONN *) 0, /* Tx TCP conn reset (see Note #3b). */
(NET_BUF_HDR *) pbuf_hdr,
(NET_TCP_RESET_CODE) NET_TCP_CONN_TX_RESET,
(NET_TCP_CLOSE_CODE) NET_TCP_CONN_CLOSE_ALL,
(NET_ERR *)&err);
NetTCP_RxPktDiscard(pbuf, perr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_CLOSED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerListen()
*
* Description : (1) Handle TCP connection in LISTEN state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Reset (RST) See Note #2a
* (2) Acknowledgement (ACK) See Note #2b
* (3) Synchronization (SYN) See Note #2c
*
* (b) Check if TCP connection listen queue is available See Note #3
*
* (c) Prepare/configure TCP connection :
*
* (1) Clone new TCP connection from current TCP listen connection, See Note #5a
* if half-connection :
*
* (A) Get connections
* (B) Set connection identification handles
* (C) Set connection addresses
* (D) Add connection into connection list
* (E) Copy connection from half-connection
*
* (2) Re-configure current TCP listen connection, See Note #5b
* if full-connection
*
* (d) Update TCP connection :
* (1) Handle received TCP segment See Note #2c2
* (2) Configure TCP connection remote host maximum segment size See Note #7
*
* (e) Transmit TCP connection synchronization for valid received See Note #2c3
* TCP connection reqeusts
*
* (f) Update TCP connection state See Note #2c
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_FIN_INVALID Received segment's finish/close flag is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is
* NOT valid for current TCP connection.
*
* NET_TCP_ERR_CONN_LISTEN_Q_MAX TCP connection listen queue is NOT available
* queue a new connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
*
* ------ RETURNED BY NetTCP_RxPktConnIsValidReset() : ------
* ------- RETURNED BY NetTCP_RxPktConnIsValidAck() : -------
* ------- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -------
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* - RETURNED BY NetTCP_RxPktConnHandlerListenQ_IsAvail() : -
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_INVALID_CONN_ID Invalid application connection.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* ----------- RETURNED BY NetTCP_TxConnSync() : ------------
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
* NET_TCP_ERR_TX TCP transmit error.
* NET_ERR_TX Transmit error.
*
* ------- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -------
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for later processing (see Note #2c2).
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State]' states that :
*
* (a) "An incoming RST should be ignored."
*
* (b) "Any acknowledgment is bad if it arrives on a connection still in the LISTEN state.
* An acceptable reset segment should be formed for any arriving ACK-bearing segment."
*
* (c) "If the SYN bit is set ... the connection state should be changed to SYN-RECEIVED" ...
*
* (1) "Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ ..."
* (A) See Note #2c3
*
* (2) "And any other control or text should be queued for processing later."
*
* (A) If any control or text is queued for later processing, the next sequence octet to
* receive (RCV.NXT) MUST include the length of this received segment (SEG.LEN) :
*
* (1) RCV.NXT = SEG.SEQ + SEG.LEN + 1
*
* (3) "ISS should be selected and a SYN segment sent."
*
* (d) "Any other control or text-bearing segment (not containing SYN) must have an ACK and
* thus would be discarded by the ACK processing ... So you are unlikely to get here,
* but if you do, drop the segment, and return."
*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states to
* "not process the FIN if the state is CLOSED, LISTEN or SYN-SENT since the SEG.SEQ cannot
* be validated; drop the segment".
*
* (3) (a) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 18.11, Pages 257-258 states
* that :
*
* (1) "Each listening end point has a fixed length queue of connections that have been
* accepted by TCP (i.e., the three-way handshake is complete), but not yet accepted
* by the application."
*
* (3) "When a connection request arrives (i.e., the SYN segment), ... the current number
* of connections already queued for this listening end point [is checked] to see
* whether to accept the connection or not."
*
* (4) "If there is room on this listening end point's queue for this new connection, ...
* the TCP module ACKs the SYN and completes the connection."
*
* (5) "If there is not room on the queue for the new connection" ... :
*
* (A) "TCP just ignores the received SYN."
* (B) "Nothing is sent back (i.e., no RST segment)."
*
* (b) (A) Wright/Stevens, TCP/IP Illustrated, Volume 2, 3rd Printing, Section 15.9, Page 455
* reiterates that :
*
* (2) A "listen ... socket ... limit[s] ... the number of connections that can be
* queued on the socket," ...
*
* (5) "after which the socket layer refuses to queue additional connection requests.
* When this occurs, TCP ignores incoming connection requests."
*
* (B) Wright/Stevens, TCP/IP Illustrated, Volume 2, 3rd Printing, Section 28.2, Page 930
* also states that :
*
* (5) (A) "By silently dropping the segment" ...
* (B) "and not replying with an RST," ...
* (C) "The client's connection request should time out, causing the client to
* retransmit the SYN."
*
* (C) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 18.11, Pages 259-260
* summarizes that :
*
* (5) (A) "TCP ignores the incoming SYN when the queue is full," ...
* (B) "and doesn't respond with an RST," ...
*
* (C) (1) "because ... this condition could change in a short while ... [and] by
* ignoring the SYN, the server forces the client TCP to re-transmit the
* SYN later, hoping that the queue will then have room for the new
* connection".
*
* (2) Whereas page 259-260 counters that "if the server's TCP responded with
* a reset, the client's active open would abort".
*
* See also 'NetTCP_RxPktConnHandlerListenQ_IsAvail() Note #1'.
*$PAGE*
* (4) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
* since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
* is configured with an appropriate family type value (see 'net_conn.h CONFIGURATION ERRORS').
* The 'else'-conditional code is included for completeness & as an extra precaution in case
* 'net_conn.h' is incorrectly modified.
*
* (5) (a) (1) If any received TCP connection request to a LISTEN-state connection is a half-connection
* -- i.e. a connection with ONLY the local address specified/configured -- then a new
* connection is cloned from the LISTEN-state connection to handle each unique connection
* request.
*
* (2) The following connection parameters are cloned/copied from the LISTEN-state connection :
*
* (A) Application connection handle identifier
* (1) When the cloned connection is fully connected/established, it is queued to the
* LISTEN-state connection's application connection as a cloned network connection
* until the connection is accepted & a new application connection is created.
*
* See also 'net_sock.c NetSock_Accept() Notes #1d & #1e'.
*
* (B) (1) TCP connection receive parameters
* (2) TCP connection transmit parameters
* (3) TCP connection timeout values
*
* See also 'NetTCP_ConnCopy() Note #1'.
*
* (b) If any received TCP connection request to a LISTEN-state connection is a full-connection --
* i.e. a connection with BOTH the local & remote addresses specified/configured -- then the
* LISTEN-state connection is re-configured to handle the received connection request.
*
* (6) On ANY TCP LISTEN-connection preparation errors, network resources MUST be appropriately freed :
*
* (a) If NO TCP connections available, NO resources need be freed.
* (b) If NO network connections available, ONLY the TCP connection need be closed.
* (c) If network connection preparation fails, the TCP & network connection MUST both
* be closed. However, the TCP connection need NOT close application connection(s).
*
* See also 'NetTCP_ConnCloseHandler() Note #2b1C1'.
*
* (d) If any remaining TCP connection preparation fails, the TCP & network connection MUST
* both be closed. The application connection(s) SHOULD NOT be closed since it is cloned
* from the LISTEN-state connection (see Note #4), but network connections MAY need to be
* de-referenced from the application connection(s).
*
* See also 'NetTCP_ConnCloseHandler() Note #2b';
* & 'net_conn.c NetConn_CloseApp() Note #1'
* & 'net_sock.c NetSock_FreeConnFromSock() Note #2'.
*
* (7) RFC #1122, Section 4.2.2.6 states that ... :
*
* (a) A "TCP SHOULD send an MSS (Maximum Segment Size) option in every SYN segment".
*
* (b) "If an MSS option is not received at connection setup, TCP MUST assume a default
* send MSS of 536."
*
* (8) TCP connection timeout for LISTEN state is implemented by TCP connection retransmission
* function(s) (see 'NetTCP_TxConnReTxQ() Note #3c').
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerListen (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
NET_IP_ADDR addr_ip;
#endif
CPU_INT08U addr_local[NET_CONN_CFG_ADDR_LEN];
CPU_INT08U addr_remote[NET_CONN_CFG_ADDR_LEN];
CPU_BOOLEAN q_avail;
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
NET_TCP_PORT_NBR port_nbr;
NET_CONN_FAMILY conn_family;
NET_CONN_LIST_IX conn_protocol_ix;
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_clone;
NET_CONN_ID conn_id_clone_app;
NET_TCP_CONN_ID conn_id_clone_tcp;
NET_TCP_CONN *pconn_clone;
NET_TCP_CONN *pconn_tx_sync;
NET_ERR err;
NET_ERR err_rtn;
/* ---------- VALIDATE RX'D TCP PKT ----------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose != DEF_NO) { /* If invalid fin/close rx'd, ... */
*perr = NET_TCP_ERR_CONN_SEQ_FIN_INVALID;
return; /* ... ignore TCP pkt (see Note #2e). */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (reset_code != NET_TCP_CONN_RX_RESET_NONE) { /* If reset rx'd, ... */
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* ... ignore TCP pkt (see Note #2a). */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (ack_code != NET_TCP_CONN_RX_ACK_NONE) { /* If ack rx'd, ... */
/* ... tx TCP conn reset (see Note #2b). */
NetTCP_TxConnReset(pconn, pbuf_hdr, NET_TCP_CONN_TX_RESET, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (seq_code != NET_TCP_CONN_RX_SEQ_SYNC) { /* If sync NOT rx'd, ... */
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* ... ignore TCP pkt (see Note #2d). */
}
/* Else sync avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_SYNC;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_SYNC;
/*$PAGE*/
/* ---------- CHK TCP CONN LISTEN Q ----------- */
q_avail = NetTCP_RxPktConnHandlerListenQ_IsAvail(pconn, perr); /* Chk TCP listen Q avail. */
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (q_avail != DEF_YES) { /* If TCP listen Q NOT avail (see Note #3a5), */
*perr = NET_TCP_ERR_CONN_LISTEN_Q_MAX;
return; /* ... ignore TCP pkt (see Note #3a5A). */
}
/* ------------- PREPARE TCP CONN ------------- */
if (pbuf_hdr->ConnType != NET_CONN_TYPE_CONN_FULL) { /* If pkt demux'd to half-conn, clone new conn */
/* .. from LISTEN half-conn (see Note #5a). */
/* ---------------- GET CONNS ----------------- */
conn_id_clone_tcp = NetTCP_ConnGet(&err);
if ( err != NET_TCP_ERR_NONE) { /* See Note #6a. */
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
pconn_clone = &NetTCP_ConnTbl[conn_id_clone_tcp];
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
conn_family = NET_CONN_FAMILY_IP_V4_SOCK;
conn_protocol_ix = NET_CONN_LIST_IX_IP_V4_SOCK_TCP;
#else /* See Notes #4 & #6d. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
conn_id_clone = NetConn_Get(conn_family, conn_protocol_ix, &err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6b. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
/* --------------- SET CONN IDs --------------- */
pconn_clone->ID_Conn = conn_id_clone;
NetConn_ID_TransportSet((NET_CONN_ID) conn_id_clone,
(NET_CONN_ID) conn_id_clone_tcp,
(NET_ERR *)&err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6c. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
conn_id = pconn->ID_Conn;
conn_id_clone_app = NetConn_ID_AppGet((NET_CONN_ID) conn_id, /* Get half-conn's app conn id & ... */
(NET_ERR *)&err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6c. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
NetConn_ID_AppCloneSet((NET_CONN_ID) conn_id_clone, /* ... set as cloned conn's ... */
(NET_CONN_ID) conn_id_clone_app, /* ... app conn clone id (see Note #5a2A1). */
(NET_ERR *)&err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6c. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/*$PAGE*/
/* -------------- CFG CONN ADDRS -------------- */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
/* Cfg local addr as pkt dest addr. */
port_nbr = (NET_TCP_PORT_NBR)NET_UTIL_HOST_TO_NET_16(pbuf_hdr->TCP_UDP_PortDest);
addr_ip = (NET_IP_ADDR )NET_UTIL_HOST_TO_NET_32(pbuf_hdr->IP_AddrDest);
Mem_Copy((void *)&addr_local[NET_CONN_ADDR_IP_IX_PORT],
(void *)&port_nbr,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_PORT);
Mem_Copy((void *)&addr_local[NET_CONN_ADDR_IP_IX_ADDR],
(void *)&addr_ip,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
/* Cfg remote addr as pkt src addr. */
port_nbr = (NET_TCP_PORT_NBR)NET_UTIL_HOST_TO_NET_16(pbuf_hdr->TCP_UDP_PortSrc);
addr_ip = (NET_IP_ADDR )NET_UTIL_HOST_TO_NET_32(pbuf_hdr->IP_AddrSrc);
Mem_Copy((void *)&addr_remote[NET_CONN_ADDR_IP_IX_PORT],
(void *)&port_nbr,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_PORT);
Mem_Copy((void *)&addr_remote[NET_CONN_ADDR_IP_IX_ADDR],
(void *)&addr_ip,
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
#else /* See Notes #4 & #6d. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
NetConn_AddrLocalSet((NET_CONN_ID ) conn_id_clone,
(CPU_INT08U *)&addr_local[0],
(NET_CONN_ADDR_LEN) NET_CONN_CFG_ADDR_LEN,
(CPU_BOOLEAN ) DEF_NO,
(NET_ERR *)&err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6c. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
NetConn_AddrRemoteSet((NET_CONN_ID ) conn_id_clone,
(CPU_INT08U *)&addr_remote[0],
(NET_CONN_ADDR_LEN) NET_CONN_CFG_ADDR_LEN,
(CPU_BOOLEAN ) DEF_NO,
(NET_ERR *)&err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6c. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/* Add conn into server conn list. */
NetConn_ListAdd(conn_id_clone, NET_CONN_LIST_TYPE_SERVER, &err);
if ( err != NET_CONN_ERR_NONE) { /* See Note #6c. */
NetTCP_ConnClose(pconn_clone, pbuf_hdr, DEF_NO, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/* Copy half-conn state to full conn. */
NetTCP_ConnCopy(pconn_clone, pconn);
pconn_tx_sync = pconn_clone;
} else { /* Else conn to listen TCP conn (see Note #5b). */
pconn_tx_sync = pconn;
}
/*$PAGE*/
/* ------------- HANDLE RX'D SEG -------------- */
NetTCP_RxPktConnHandlerSeg(pconn_tx_sync, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
default: /* See Note #6d. */
NetTCP_ConnClose(pconn_tx_sync, pbuf_hdr, pconn_tx_sync->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' warning. */
}
/* ------------- UPDATE TCP CONN -------------- */
/* Cfg remote max seg size as advertised ... */
/* ... by remote host (see Note #7). */
pconn_tx_sync->MaxSegSizeRemote = (pbuf_hdr->TCP_MaxSegSize != NET_TCP_MAX_SEG_SIZE_NONE)
? pbuf_hdr->TCP_MaxSegSize
: NET_TCP_MAX_SEG_SIZE_DFLT_TX;
/* ------------- TX TCP CONN SYNC ------------- */
NetTCP_TxConnSync(pconn_tx_sync, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) { /* See Note #6d. */
NetTCP_ConnClose(pconn_tx_sync, pbuf_hdr, pconn_tx_sync->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
return;
}
/* ---------- UPDATE TCP CONN STATE ----------- */
pconn_tx_sync->ConnState = NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE;
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerSyncRxd()
*
* Description : (1) Handle TCP connection in SYN-RECEIVED state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2e
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Note #2d2A1
* (2) Update TCP connection state See Notes #2d2A1a & #2e4
* (3) Update TCP connection timer
*
* (c) Acknowledge TCP connection
* (1) Signal TCP/application connection complete
* (2) Handle TCP connection received data See Note #2d2A1
* (3) Transmit TCP connection data See Notes #2d2A2 & #2e3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data processed (see Note #2d2A1).
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_TX TCP transmit error.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) TCP connections in the SYN-RECEIVED state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2C.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit :
* SYN-RECEIVED STATE' states that "if the RST bit is set" and ...
*
* (1) "If this connection was initiated with a passive OPEN (i.e., came from
* the LISTEN state), then return this connection to the LISTEN state."
*
* (2) "If this connection was initiated with an active OPEN (i.e., came from
* the SYN-SENT state) then the connection was refused, signal the user
* 'connection refused' ... enter the CLOSED state."
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing'
* reiterates that "if the receiver ... of a RST ... was in SYN-RECEIVED state
* and had previously been in the LISTEN state, then the receiver returns to
* the LISTEN state, otherwise the receiver aborts the connection and goes to
* the CLOSED state".
*
* (C) However, since TCP connections opened from the LISTEN state are cloned from
* the original LISTEN-state TCP connection, it is NOT necessary to return ANY
* reset TCP connection from the SYN-RECEIVED state back to the LISTEN state.
*
* See also 'NetTCP_RxPktConnIsValidReset() Note #2a4B'.
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of
* a segment with the RST when in a synchronized state" to "provide some
* protection against ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? Although RFC Draft-IETF-TCPm-TCPSecure #00 explicitly states that this
* amendment applies only to the "handling of a ... RST ... when in a synchronized
* state", it is assumed that this should also apply to the SYN-RECEIVED state.
*
* See also 'NetTCP_RxPktConnIsValidReset() Note #2a5B'.
*
* (C) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*$PAGE*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) (A) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*
* (B) ???? Although RFC Draft-IETF-TCPm-TCPSecure #00 explicitly states that this
* amendment applies only to the "handling of a ... SYN ... in a synchronized
* state", it is assumed that this should also apply to the SYN-RECEIVED state.
*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field' states
* that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on [and in the] SYN-RECEIVED STATE" ...
*
* (A) (1) "If SND.UNA < SEG.ACK <= SND.NXT then" ...
*
* (a) "enter the ESTABLISHED state" ...
* (b) "and continue processing."
*
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT
* [State]' states to "send ... [any] data or controls which were queued
* for transmission" when the SYN-SENT state transitions to the ESTABLISHED
* state.
*
* Although this section is the only section to state that any data or
* controls should be sent when transitioning from the SYN-SENT state
* to the ESTABLISHED state, it is assumed that any data or controls
* should also be sent for the transition from the SYN-RECEIVED state
* to the ESTABLISHED state.
*
* (B) "If the segment acknowledgment is not acceptable, form a reset segment ...
* and send it."
*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) And the "SYN-RECEIVED STATE enter[s] the CLOSE-WAIT state".
*$PAGE*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*
* (c) (1) Once a TCP connection enters the connected state, most of its TCP connection
* timers should be reset.
*
* (2) However, the following timers MAY already have been allocated & initialized,
* & MUST NOT be reset :
*
* (A) Transmit Idle timer 'TxQ_IdleTmr'
* (B) Re-transmit timer 'ReTxQ_Tmr'
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerSyncRxd (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
NET_TCP_FREE_CODE free_code;
NET_TCP_CONN_STATE state;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2C). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b2Ab). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
default:
/* ... tx TCP conn reset (see Note #2d2B). */
NetTCP_TxConnReset(pconn, pbuf_hdr, NET_TCP_CONN_TX_RESET, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
state = pconn->ConnState;
if (pbuf_hdr->TCP_SegClose != DEF_YES) { /* If fin/close NOT rx'd, ... */
pconn->ConnState = NET_TCP_CONN_STATE_CONN; /* ... chng to conn'd state (see Note #2d2A1a). */
} else { /* Else chng to close-wait state (see Note #2e4). */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSE_WAIT;
}
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN;
/* ------------------- UPDATE TMRs -------------------- */
free_code = NET_TCP_CONN_FREE_TMR_ALL; /* See Note #3c1. */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_TX_IDLE); /* See Note #3c2A. */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_RE_TX); /* See Note #3c2B. */
NetTCP_ConnFreeTmr(pconn, free_code); /* Free TCP conn tmr(s) [see Note #3c]. */
/* Get TCP conn tmr. */
timeout_sec = pconn->TimeoutConn_sec; /* Start conn tmr (see Note #3b). */
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
/*$PAGE*/
/* ------------------- ACK TCP CONN ------------------- */
NetTCP_RxPktConnHandlerSignalConn(pconn, state, &err); /* Signal app conn (see Note #1c1). */
if ( err != NET_TCP_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
NetTCP_RxPktConnHandlerRxQ_AppData(pconn, &err); /* Handle TCP conn rx'd data (see Note #2d2A1). */
if ( err != NET_TCP_ERR_NONE) { /* #### On err, close TCP conn? */
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
if (pconn->ConnState == NET_TCP_CONN_STATE_CONN) { /* If conn'd, tx any tx data (see Note #1c3). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_NONE, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
} else { /* Else tx TCP conn ack (see Note #2e3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_IMMED, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerSyncTxd()
*
* Description : (1) Handle TCP connection in SYN-SENT state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Acknowledgement (ACK) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
*
* (b) Update TCP connection :
* (1) Configure TCP connection remote host maximum segment size See Note #3
* (2) Handle received TCP segment See Note #2c
* (3) Update TCP connection state See Notes #2c3A1 & #2c3B1
* (4) Update TCP connection timer
*
* (c) Acknowledge TCP connection
* (1) Signal TCP/application connection complete
* (2) Handle TCP connection received data See Note #2c3A3
* (3) Transmit TCP connection acknowledgement & data See Note #2c3A2
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_FIN_INVALID Received segment's finish/close flag is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled &
* valid data queued for processing
* (see Notes #2c3A3 & #2c3B3).
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_TX TCP transmit error.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State]' states to :
*
* (a) "First check the ACK bit[;] if the ACK bit is set" :
*
* (1) "If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless the RST bit is
* set) ... and discard the segment."
*
* (2) "If SND.UNA < SEG.ACK =< SND.NXT then the ACK is acceptable."
*
* See also 'NetTCP_RxPktConnIsValidAck() Note #1c1A'.
*
* (b) "Second check the RST bit[;] if the RST bit is set [and] if the ACK was acceptable
* then signal the user 'error: connection reset', drop the segment, [and] enter
* CLOSED state."
*
* See also 'NetTCP_RxPktConnIsValidReset() Notes #2a3 & #2a5C'.
*
* (c) "Fourth check the SYN bit[;] if the SYN bit is on and ... acceptable then" ...
*
* (1) "RCV.NXT is set to SEG.SEQ+1, IRS is set to SEG.SEQ."
* (A) See also Note #2c3B3a
*
* (2) (A) "SND.UNA should be advanced to equal SEG.ACK (if there is an ACK)" ...
*
* (B) "and any segments on the retransmission queue which are thereby acknowledged
* should be removed."
*
* (3) (A) "If SND.UNA > ISS (our SYN has been ACKed)," ...
*
* (1) "change the connection state to ESTABLISHED" ...
*
* (2) (a) "form an ACK segment ... and send it."
*
* (b) "Data or controls which were queued for transmission may be included."
*
* (3) "If there are other controls or text in the segment then continue processing."
*
* (4) RFC #1122, Section 4.2.2.20.(c) adds that "when the connection enters
* ESTABLISHED state, the following variables must be set" :
*
* (a) SND.WND <- SEG.WND
* (b) SND.WL1 <- SEG.SEQ
* (c) SND.WL2 <- SEG.ACK
*
* (B) "Otherwise" ...
*
* (1) "enter SYN-RECEIVED," ...
*
* (2) "form an SYN,ACK segment ... and send it."
*
* (3) "If there are other controls or text in the segment, queue them for later
* processing after the ESTABLISHED state has been reached."
*
* (a) If any control or text is queued for later processing, the next sequence
* octet to receive (RCV.NXT) MUST include the length of this received
* segment (SEG.LEN) :
*
* (1) RCV.NXT = SEG.SEQ + SEG.LEN + 1
*
* (d) "Fifth, if neither of the SYN or RST bits is set then drop the segment."
*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* to "not process the FIN if the state is CLOSED, LISTEN or SYN-SENT since the SEG.SEQ
* cannot be validated; drop the segment".
*$PAGE*
* (3) RFC #1122, Section 4.2.2.6 states that ... :
*
* (a) A "TCP SHOULD send an MSS (Maximum Segment Size) option in every SYN segment".
*
* (b) "If an MSS option is not received at connection setup, TCP MUST assume a default
* send MSS of 536."
*
* (4) (a) TCP connection timeout for SYN-SENT state is implemented by TCP connection retransmission
* function(s) (see 'NetTCP_TxConnReTxQ() Note #3c').
*
* (b) (1) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (2) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*
* (c) (1) Once a TCP connection enters the connected state, most of its TCP connection
* timers should be reset.
*
* (2) However, the following timers MAY already have been allocated & initialized,
* & MUST NOT be reset :
*
* (A) Transmit Idle timer 'TxQ_IdleTmr'
* (B) Re-transmit timer 'ReTxQ_Tmr'
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerSyncTxd (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
NET_TCP_FREE_CODE free_code;
NET_TCP_CONN_STATE state;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
NET_ERR err_rtn;
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose != DEF_NO) { /* If invalid fin/close rx'd, ... */
*perr = NET_TCP_ERR_CONN_SEQ_FIN_INVALID;
return; /* ... ignore TCP pkt (see Note #2e). */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (ack_code == NET_TCP_CONN_RX_ACK_INVALID) { /* If invalid ack rx'd, ... */
/* ... tx TCP conn reset (see Note #2a1). */
NetTCP_TxConnReset(pconn, pbuf_hdr, NET_TCP_CONN_TX_RESET, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return;
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, close TCP conn (see Note #2b). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID:
default:
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (seq_code != NET_TCP_CONN_RX_SEQ_SYNC) { /* If sync NOT rx'd, ... */
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* ... ignore TCP pkt (see Note #2d). */
}
/* Else sync avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_SYNC;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_SYNC;
/*$PAGE*/
/* ----------------- UPDATE TCP CONN ------------------ */
/* Cfg remote max seg size ... */
/* ... as advertised by remote host (see Note #3). */
pconn->MaxSegSizeRemote = (pbuf_hdr->TCP_MaxSegSize != NET_TCP_MAX_SEG_SIZE_NONE)
? pbuf_hdr->TCP_MaxSegSize
: NET_TCP_MAX_SEG_SIZE_DFLT_TX;
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
if (ack_code == NET_TCP_CONN_RX_ACK_VALID) { /* If valid ack rx'd (see Note #2a1), ... */
state = pconn->ConnState;
pconn->ConnState = NET_TCP_CONN_STATE_CONN; /* ... chng to conn'd state (see Note #2c3A1). */
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN;
} else { /* Else chng to sync rx'd state (see Note #2c3B1). */
pconn->ConnState = NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE;
}
/* ------------------- UPDATE TMRs -------------------- */
free_code = NET_TCP_CONN_FREE_TMR_ALL; /* See Note #4c1. */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_TX_IDLE); /* See Note #4c2A. */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_RE_TX); /* See Note #4c2B. */
NetTCP_ConnFreeTmr(pconn, free_code); /* Free TCP conn tmr(s) [see Note #4c]. */
if (pconn->ConnState == NET_TCP_CONN_STATE_CONN) { /* If conn'd, get TCP conn tmr. */
timeout_sec = pconn->TimeoutConn_sec; /* Start conn tmr (see Note #4b2). */
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
}
/*$PAGE*/
/* ------------------- ACK TCP CONN ------------------- */
if (pconn->ConnState == NET_TCP_CONN_STATE_CONN) { /* If conn'd, ... */
NetTCP_RxPktConnHandlerSignalConn(pconn, state, &err); /* ... signal app conn (see Note #1c1); ... */
if ( err != NET_TCP_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
NetTCP_RxPktConnHandlerRxQ_AppData(pconn, &err); /* ... handle TCP conn rx'd data (see Note #2d2A1); ... */
if ( err != NET_TCP_ERR_NONE) { /* #### On err, close TCP conn? */
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/* ... & tx ack & any tx data (see Note #1c3). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_IMMED, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
} else { /* Else tx TCP conn sync/ack (see Note #2c3B2). */
NetTCP_TxConnSync(pconn, pbuf_hdr, &err);
if ( err != NET_TCP_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_CLOSE;
return;
}
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerConn()
*
* Description : (1) Handle TCP connection in ESTABLISHED state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Update TCP connection state See Note #2f5
* (3) Update TCP connection timer See Note #3
*
* (c) Transmit TCP connection acknowledgement & data See Notes #2e2A & #2f3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
* NET_TCP_ERR_TX TCP transmit error.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) TCP connections in the ESTABLISHED state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit' states
* that in the "ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT" states that "if the
* RST bit is set then, any outstanding RECEIVEs and SEND[s] should receive 'reset'
* responses. All segment queues should be flushed. Users should also receive an
* unsolicited general 'connection reset' signal[, and] enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on [and in the] ESTABLISHED STATE" ...
*
* (A) "If SND.UNA < SEG.ACK <= SND.NXT then" ...
*
* (1) "set SND.UNA <- SEG.ACK."
*
* (2) "Any segments on the retransmission queue which are thereby entirely
* acknowledged are removed."
*
* (3) "the send window should be updated" :
*
* (a) (1) (A) "If ((SND.WL1 < SEG.SEQ) or" ...
*
* (B) (1) "(SND.WL1 = SEG.SEQ and" ...
* (2) "SND.WL2 <= SEG.ACK))," ...
*
* (2) (A) "set SND.WND <- SEG.WND," ...
* (B) "set SND.WL1 <- SEG.SEQ," ...
* (C) "set SND.WL2 <- SEG.ACK."
*
* (b) "Note that SND.WND is an offset from SND.UNA, that SND.WL1 records the
* sequence number of the last segment used to update SND.WND, and that
* SND.WL2 records the acknowledgment number of the last segment used to
* update SND.WND. The check here preveents using old segments to update
* the window."
*
* (B) (1) "If the ACK is a duplicate (SEG.ACK <= SND.UNA), it can be ignored."
*
* (2) RFC #1122, Section 4.2.2.20.(g) amends the transmit window update criteria
* for the segment's acknowledgement to include SND.UNA : "The window should
* updated if SND.UNA <= SEG.ACK <= SND.NXT."
*
* See also 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1b2'.
*
* (C) "If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK
* [and] drop the segment."
*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that for the "ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE ... it
* is possible to deliver segment text to user RECEIVE buffers" :
*
* (1) "If the segment ... carries [a] PUSH flag, then the user is informed [and] the
* buffer is returned."
*
* (2) (A) (1) "When the TCP takes responsibility for delivering the data to the user it
* must also acknowledge the receipt of the data."
*
* (2) "This acknowledgment should be piggybacked on a segment being transmitted
* if possible without incurring undue delay."
*
* (B) "Once the TCP takes responsibility for the data" ...
*
* (1) "it advances RCV.NXT over the data accepted," ...
*
* (2) "adjusts RCV.WND as appropriate to the current buffer availability" ...
*
* (3) (a) "The total of RCV.NXT and RCV.WND should not be reduced."
*
* (b) RFC #793, Section 3.7 'Data Communication : Managing the Window' &
* RFC #1122, Section 4.2.2.16 confirm that "a TCP receiver SHOULD NOT
* shrink the window"; i.e. "advertise a much smaller window without
* having accepted that much data".
*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) And the "ESTABLISHED STATE enter[s] the CLOSE-WAIT state".
*$PAGE*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerConn (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2C). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close rx'd, ... */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSE_WAIT; /* ... chng to close-wait state (see Note #2f5). */
}
/* -------------------- UPDATE TMR -------------------- */
timeout_sec = pconn->TimeoutConn_sec; /* Reset conn tmr (see Note #3b). */
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/*$PAGE*/
/* --------------- TX TCP CONN ACK/DATA --------------- */
ack_code = ((pbuf_hdr->TCP_SegAckTxReqCode == NET_TCP_CONN_TX_ACK_IMMED) ||
(pbuf_hdr->TCP_SegClose == DEF_YES)) /* See Note #2f3. */
? NET_TCP_CONN_TX_ACK_IMMED
: NET_TCP_CONN_TX_ACK;
/* Tx ack & any tx data (see Note #1c). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerFinWait1()
*
* Description : (1) Handle TCP connection in FIN-WAIT-1 state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Signal TCP/application connection close See Note #2d2B2
* (3) Update TCP connection state : See Notes #2f5A1, #2f5A2b1, & #2f5B
* (A) Configure TCP connection timeout value
* (B) Configure TCP connection timeout function
* (4) Update TCP connection timer(s) See Notes #2f5A1, #2f5A2b2, & #3
*
* (c) Transmit TCP connection acknowledgement & data See Notes #2e2A & #2f3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
* NET_TCP_ERR_TX TCP transmit error.
*
* - RETURNED BY NetTCP_RxPktConnHandlerSignalClose() : -
* NET_TCP_ERR_INVALID_CONN_ID Invalid application connection.
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*$PAGE*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*
* Note(s) : (2) TCP connections in the FIN-WAIT-1 state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit' states
* that in the "ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT" states that "if the
* RST bit is set then, any outstanding RECEIVEs and SEND[s] should receive 'reset'
* responses. All segment queues should be flushed. Users should also receive an
* unsolicited general 'connection reset' signal[, and] enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on" ...
*
* (A) And in the "ESTABLISHED STATE" ...
*
* (1) "If SND.UNA < SEG.ACK <= SND.NXT then" ...
*
* (a) "set SND.UNA <- SEG.ACK."
*
* (b) "Any segments on the retransmission queue which are thereby entirely
* acknowledged are removed."
*
* (c) "the send window should be updated" :
*
* (1) (A) (1) "If ((SND.WL1 < SEG.SEQ) or" ...
*
* (2) (a) "(SND.WL1 = SEG.SEQ and" ...
* (b) "SND.WL2 <= SEG.ACK))," ...
*
* (B) (1) "set SND.WND <- SEG.WND," ...
* (2) "set SND.WL1 <- SEG.SEQ," ...
* (3) "set SND.WL2 <- SEG.ACK."
*
* (2) "Note that SND.WND is an offset from SND.UNA, that SND.WL1 records the
* sequence number of the last segment used to update SND.WND, and that
* SND.WL2 records the acknowledgment number of the last segment used to
* update SND.WND. The check here preveents using old segments to update
* the window."
*
* (2) (a) "If the ACK is a duplicate (SEG.ACK <= SND.UNA), it can be ignored."
*
* (b) RFC #1122, Section 4.2.2.20.(g) amends the transmit window update criteria
* for the segment's acknowledgement to include SND.UNA : "The window should
* updated if SND.UNA <= SEG.ACK <= SND.NXT."
*
* See also 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1b2'.
*
* (3) "If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK
* [and] drop the segment."
*
* (B) (1) For the "FIN-WAIT-1 STATE" :
*
* (a) "in addition to the processing for the ESTABLISHED state" ...
* (b) "if our FIN is now acknowledged then" ...
* (1) "enter FIN-WAIT-2 [state] and continue processing in that state."
*
* (2) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* FIN-WAIT-2 STATE' states that "if the retransmission queue is empty, the user's
* CLOSE can be acknowledged".
*
* (b) However, a TCP connection transitions into the FIN-WAIT-2 state if & only if
* the TCP connection's close request was previously acknowledged while in the
* FIN-WAIT-1 state. Thus, the TCP connection's re-transmit queue should
* already be empty prior to entering the FIN-WAIT-2 state.
*
* ???? Therefore, a TCP connection in the FIN-WAIT-1 state should :
*
* (1) Signal the application layer that "the user's close [is] acknowledged"
* whenever its re-transmit queue becomes empty.
*
* (2) Close all unused timers (see also Note #2f5A1b).
*$PAGE*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that for the "ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE ... it
* is possible to deliver segment text to user RECEIVE buffers" :
*
* (1) "If the segment ... carries [a] PUSH flag, then the user is informed [and] the
* buffer is returned."
*
* (2) (A) (1) "When the TCP takes responsibility for delivering the data to the user it
* must also acknowledge the receipt of the data."
*
* (2) "This acknowledgment should be piggybacked on a segment being transmitted
* if possible without incurring undue delay."
*
* (B) "Once the TCP takes responsibility for the data" ...
*
* (1) "it advances RCV.NXT over the data accepted," ...
*
* (2) "adjusts RCV.WND as appropriate to the current buffer availability" ...
*
* (3) (a) "The total of RCV.NXT and RCV.WND should not be reduced."
*
* (b) RFC #793, Section 3.7 'Data Communication : Managing the Window' &
* RFC #1122, Section 4.2.2.16 confirm that "a TCP receiver SHOULD NOT
* shrink the window"; i.e. "advertise a much smaller window without
* having accepted that much data".
*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) For the "FIN-WAIT-1 STATE" :
*
* (A) "If our FIN has been ACKed (perhaps in this segment), then" ...
*
* (1) "enter TIME-WAIT [state]" ...
* (a) "start the time-wait timer, ...
* (1) A TCP connection should be closed WITHOUT fault following a TCP
* connection TIME-WAIT timeout.
*
* (b) "turn off the other timers;" ...
*
* (2) However, it is possible that some closing received data from the remote
* host is available but has NOT yet been received by the application layer.
*
* (a) Therefore, if the application receive queue is closed, then enter the
* TIME-WAIT state.
*
* (b) (1) But if the application receive queue is NOT closed, then enter the
* connection-closing-data-available state to allow the application
* layer to receive the remaining receive data.
*
* (2) (A) To satisfy the required time-wait timeout of two maximum segment
* lifetimes (see Note #2f5A1a), the time-wait timeout is intially
* used to provide the application layer sufficient time to receive
* the closing received data.
*
* (B) If after the time-wait timeout expires, the application receive
* queue is still not empty, the user connection timeout is used
* to provide the application layer additional time to receive the
* closing received data.
*
* See also Note #3.
*
* (B) "otherwise, enter the CLOSING state."
*$PAGE*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*
* (4) Since the mechanisms of TCP connection close are independent of the application layer
* close; any external application layer close error(s) are ignored.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerFinWait1 (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
CPU_BOOLEAN data_avail;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
CPU_FNCT_PTR timeout_fnct;
NET_TCP_FREE_CODE free_code;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2A3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
timeout_fnct = (CPU_FNCT_PTR)0;
if (pconn->TxQ_State == NET_TCP_TX_Q_STATE_CONN_CLOSED) { /* If local conn close ack'd (see Note #2f5A); ... */
/* Closing data avail for half-closed conns ONLY. */
data_avail = ((pconn->ConnCloseCode != NET_CONN_CLOSE_HALF ) ||
((pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) &&
(pconn->RxQ_App_Head == (NET_BUF *)0))) ? DEF_NO : DEF_YES;
/* ... signal app conn close (see Note #2d2B2b1); ... */
NetTCP_RxPktConnHandlerSignalClose(pconn, data_avail, &err);
switch (err) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_FAIL: /* Ignore any app conn close err(s) [see Note #4]. */
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_INVALID_CONN_ID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_CONN:
case NET_CONN_ERR_NOT_USED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
*perr = err;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* ... & if fin/close rx'd ... */
if (data_avail != DEF_YES) { /* ... & NO app data avail, ... */
/* ... chng to time-wait state (see Note #2f5A2a); ... */
pconn->ConnState = NET_TCP_CONN_STATE_TIME_WAIT;
pconn->ConnCloseTimeoutFaultFlag = DEF_NO; /* ... clr close timeout fault (see Note #2f5A1a1);... */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
} else { /* ... else chng to conn-closing-data-avail state ... */
/* ... (see Note #2f5A2b1);... */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL;
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnClosingTimeoutDataAvail;
}
/* ... & start time-wait tmr (see Notes #2f5A1a & ... */
/* ... #2f5A2b2A). */
timeout_sec = pconn->TimeoutMaxSeg_sec * NET_TCP_CONN_TIMEOUT_MAX_SEG_SCALAR;
} else {
pconn->ConnState = NET_TCP_CONN_STATE_FIN_WAIT_2; /* ... else chng to fin-wait-2 state (see Note #2d2B1b1)*/
timeout_sec = pconn->TimeoutConn_sec; /* ... & start conn close tmr (see Note #3b). */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
}
} else {
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* Else if fin/close rx'd, ... */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSING; /* ... chng to closing state (see Note #2f5B) ... */
timeout_sec = pconn->TimeoutConn_sec; /* ... & start conn close tmr (see Note #3b). */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
}
}
/* ------------------- UPDATE TMRs -------------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_TIME_WAIT: /* If in time-wait (see Note #2f5A1) ... */
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL: /* ... or closing state(s) [see Note #2d2B2b2], ... */
free_code = NET_TCP_CONN_FREE_TMR_ALL; /* ... free all TCP conn tmrs (see Note #2f5A1b). */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_TIMEOUT);
NetTCP_ConnFreeTmr(pconn, free_code);
break;
}
if (timeout_fnct != (CPU_FNCT_PTR)0) {
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) timeout_fnct,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) timeout_fnct,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
}
/*$PAGE*/
/* --------------- TX TCP CONN ACK/DATA --------------- */
ack_code = ((pbuf_hdr->TCP_SegAckTxReqCode == NET_TCP_CONN_TX_ACK_IMMED) ||
(pbuf_hdr->TCP_SegClose == DEF_YES)) /* See Note #2f3. */
? NET_TCP_CONN_TX_ACK_IMMED
: NET_TCP_CONN_TX_ACK;
if ((pconn->ConnState == NET_TCP_CONN_STATE_FIN_WAIT_1) || /* If TCP conn tx Q NOT closed, ... */
(pconn->ConnState == NET_TCP_CONN_STATE_CLOSING )) { /* ... tx ack & any tx data (see Note #1c). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
} else { /* Else tx TCP conn ack (see Note #2f3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, ack_code, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerFinWait2()
*
* Description : (1) Handle TCP connection in FIN-WAIT-2 state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Update TCP connection state : See Notes #2f5A & #2f5B2a
* (A) Configure TCP connection timeout value
* (B) Configure TCP connection timeout function
* (3) Update TCP connection timer(s) See Notes #2f5A, #2f5B2b, & #3
*
* (c) Transmit TCP connection acknowledgement See Notes #2e2A & #2f3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* -- RETURNED BY NetTCP_RxPktConnIsValidSeq() : --
* -- RETURNED BY NetTCP_RxPktConnIsValidAck() : --
* - RETURNED BY NetTCP_RxPktConnIsValidReset() : -
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* -- RETURNED BY NetTCP_RxPktConnHandlerSeg() : --
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
*
* ------- RETURNED BY NetTCP_TxConnAck() : -------
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) TCP connections in the FIN-WAIT-2 state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit' states
* that in the "ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT" states that "if the
* RST bit is set then, any outstanding RECEIVEs and SEND[s] should receive 'reset'
* responses. All segment queues should be flushed. Users should also receive an
* unsolicited general 'connection reset' signal[, and] enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on" ...
*
* (A) And in the "ESTABLISHED STATE" ...
*
* (1) "If SND.UNA < SEG.ACK <= SND.NXT then" ...
*
* (a) "set SND.UNA <- SEG.ACK."
*
* (b) "Any segments on the retransmission queue which are thereby entirely
* acknowledged are removed."
*
* (c) "the send window should be updated" :
*
* (1) (A) (1) "If ((SND.WL1 < SEG.SEQ) or" ...
*
* (2) (a) "(SND.WL1 = SEG.SEQ and" ...
* (b) "SND.WL2 <= SEG.ACK))," ...
*
* (B) (1) "set SND.WND <- SEG.WND," ...
* (2) "set SND.WL1 <- SEG.SEQ," ...
* (3) "set SND.WL2 <- SEG.ACK."
*
* (2) "Note that SND.WND is an offset from SND.UNA, that SND.WL1 records the
* sequence number of the last segment used to update SND.WND, and that
* SND.WL2 records the acknowledgment number of the last segment used to
* update SND.WND. The check here preveents using old segments to update
* the window."
*
* (2) (a) "If the ACK is a duplicate (SEG.ACK <= SND.UNA), it can be ignored."
*
* (b) RFC #1122, Section 4.2.2.20.(g) amends the transmit window update criteria
* for the segment's acknowledgement to include SND.UNA : "The window should
* updated if SND.UNA <= SEG.ACK <= SND.NXT."
*
* See also 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1b2'.
*
* (3) "If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK
* [and] drop the segment."
*
* (B) For the "FIN-WAIT-2 STATE" :
*
* (1) "in addition to the processing for the ESTABLISHED state" ...
* (2) "if the retransmission queue is empty," ...
*
* (a) (1) "the user's CLOSE can be acknowledged."
* (2) However, a TCP connection transitions into the FIN-WAIT-2 state if &
* only if the TCP connection's close request was previously acknowledged
* while in the FIN-WAIT-1 state. Thus, the TCP connection's re-transmit
* queue should already be empty prior to entering the FIN-WAIT-2 state.
*
* See also 'NetTCP_RxPktConnHandlerFinWait1() Note #2d2B2'.
*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that for the "ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE ... it
* is possible to deliver segment text to user RECEIVE buffers" :
*
* (1) "If the segment ... carries [a] PUSH flag, then the user is informed [and] the
* buffer is returned."
*
* (2) (A) "When the TCP takes responsibility for delivering the data to the user it
* must also acknowledge the receipt of the data."
*
* (B) "Once the TCP takes responsibility for the data" ...
*
* (1) "it advances RCV.NXT over the data accepted," ...
*
* (2) "adjusts RCV.WND as appropriate to the current buffer availability" ...
*
* (3) (a) "The total of RCV.NXT and RCV.WND should not be reduced."
*
* (b) RFC #793, Section 3.7 'Data Communication : Managing the Window' &
* RFC #1122, Section 4.2.2.16 confirm that "a TCP receiver SHOULD NOT
* shrink the window"; i.e. "advertise a much smaller window without
* having accepted that much data".
*$PAGE*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) For the "FIN-WAIT-2 STATE" :
*
* (A) "Enter the TIME-WAIT state" ...
* (1) "Start the time-wait timer," ...
* (a) A TCP connection should be closed WITHOUT fault following a TCP
* connection TIME-WAIT timeout.
*
* (2) "turn off the other timers."
*
* (B) However, it is possible that some closing received data from the remote
* host is available but has NOT yet been received by the application layer.
*
* (1) Therefore, if the application receive queue is closed, then enter the
* TIME-WAIT state.
*
* (2) (a) But if the application receive queue is NOT closed, then enter the
* connection-closing-data-available state to allow the application
* layer to receive the remaining receive data.
*
* (b) (1) To satisfy the required time-wait timeout of two maximum segment
* lifetimes (see Note #2f5A1a), the time-wait timeout is intially
* used to provide the application layer sufficient time to receive
* the closing received data.
*
* (2) If after the time-wait timeout expires, the application receive
* queue is still not empty, the user connection timeout is used
* to provide the application layer additional time to receive the
* closing received data.
*
* See also Note #3.
*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerFinWait2 (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
CPU_BOOLEAN data_avail;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
CPU_FNCT_PTR timeout_fnct;
NET_TCP_FREE_CODE free_code;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2A3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close rx'd, ... */
/* Closing data avail for half-closed conns ONLY. */
data_avail = ((pconn->ConnCloseCode != NET_CONN_CLOSE_HALF ) ||
((pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) &&
(pconn->RxQ_App_Head == (NET_BUF *)0))) ? DEF_NO : DEF_YES;
if (data_avail != DEF_YES) { /* ... & NO app data avail, ... */
/* ... chng to time-wait state (see Note #2f5B1); ... */
pconn->ConnState = NET_TCP_CONN_STATE_TIME_WAIT;
pconn->ConnCloseTimeoutFaultFlag = DEF_NO; /* ... clr close timeout fault (see Note #2f5A1a); ... */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
} else { /* ... else chng to conn-closing-data-avail state ... */
/* ... (see Note #2f5B2a); ... */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL;
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnClosingTimeoutDataAvail;
}
/* ... & start time-wait tmr (see Notes #2f5A1 & ... */
/* ... #2f5B2b1). */
timeout_sec = pconn->TimeoutMaxSeg_sec * NET_TCP_CONN_TIMEOUT_MAX_SEG_SCALAR;
} else {
timeout_sec = pconn->TimeoutConn_sec; /* Else start conn close tmr (see Note #3b). */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
}
/*$PAGE*/
/* ------------------- UPDATE TMRs -------------------- */
/* In time-wait or closing state(s) [see Note #2f5A], */
free_code = NET_TCP_CONN_FREE_TMR_ALL; /* ... free all TCP conn tmrs (see Note #2f5A2). */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_TIMEOUT);
NetTCP_ConnFreeTmr(pconn, free_code);
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) timeout_fnct,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) timeout_fnct,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/* ----------------- TC TCP CONN ACK ------------------ */
/* Tx TCP conn ack (see Notes #1c). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_IMMED, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerClosing()
*
* Description : (1) Handle TCP connection in CLOSING state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Update TCP connection state : See Note #2d2B2a1A
* (A) Configure TCP connection timeout value
* (B) Configure TCP connection timeout function
* (3) Update TCP connection timer(s) See Notes #2d2B2a1A, #2d2B2a1B2b,
* & #3
*
* (c) Transmit TCP connection acknowledgement & data See Notes #2d2B1 & #2f3
*
*$PAGE*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
* NET_TCP_ERR_TX TCP transmit error.
*
* - RETURNED BY NetTCP_RxPktConnHandlerSignalClose() : -
* NET_TCP_ERR_INVALID_CONN_ID Invalid application connection.
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*$PAGE*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*
* Note(s) : (2) TCP connections in the CLOSING state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* states that in the "CLOSING, LAST-ACK, TIME-WAIT" states that "if the RST bit
* is set then, enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on" ...
*
* (A) And in the "ESTABLISHED STATE" ...
*
* (1) "If SND.UNA < SEG.ACK <= SND.NXT then" ...
*
* (a) "set SND.UNA <- SEG.ACK."
*
* (b) "Any segments on the retransmission queue which are thereby entirely
* acknowledged are removed."
*
* (c) "the send window should be updated" :
*
* (1) (A) (1) "If ((SND.WL1 < SEG.SEQ) or" ...
*
* (2) (a) "(SND.WL1 = SEG.SEQ and" ...
* (b) "SND.WL2 <= SEG.ACK))," ...
*
* (B) (1) "set SND.WND <- SEG.WND," ...
* (2) "set SND.WL1 <- SEG.SEQ," ...
* (3) "set SND.WL2 <- SEG.ACK."
*
* (2) "Note that SND.WND is an offset from SND.UNA, that SND.WL1 records the
* sequence number of the last segment used to update SND.WND, and that
* SND.WL2 records the acknowledgment number of the last segment used to
* update SND.WND. The check here preveents using old segments to update
* the window."
*
* (2) (a) "If the ACK is a duplicate (SEG.ACK <= SND.UNA), it can be ignored."
*
* (b) RFC #1122, Section 4.2.2.20.(g) amends the transmit window update criteria
* for the segment's acknowledgement to include SND.UNA : "The window should
* updated if SND.UNA <= SEG.ACK <= SND.NXT."
*
* See also 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1b2'.
*
* (3) "If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK
* [and] drop the segment."
*$PAGE*
* (B) For the "CLOSING STATE" :
*
* (1) "in addition to the processing for the ESTABLISHED state" ...
*
* (2) (a) "if the ACK acknowledges our FIN then" ...
*
* (1) (A) "enter the TIME-WAIT state," ...
*
* (1) The following sections ... :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES :
* Check FIN Bit : FIN-WAIT-1 STATE'
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES :
* Check FIN Bit : FIN-WAIT-2 STATE'
*
* (2) ... generalize that when entering "the TIME-WAIT state" to ...
*
* (a) "Start the time-wait timer," ...
* (1) A TCP connection should be closed WITHOUT fault following
* a TCP connection TIME-WAIT timeout.
*
* (b) "turn off the other timers."
*
* (3) Although these sections are the only sections to state that these
* TCP connection timers should be updated when transitioning to the
* TIME-WAIT state, it is assumed that these timers should also be
* updated for the transition from the CLOSING state to the TIME-WAIT
* state.
*
* (B) However, it is possible that some closing received data from the remote
* host is available but has NOT yet been received by the application layer.
*
* (1) Therefore, if the application receive queue is closed, then enter the
* TIME-WAIT state.
*
* (2) (a) But if the application receive queue is NOT closed, then enter the
* connection-closing-data-available state to allow the application
* layer to receive the remaining receive data.
*
* (b) (1) To satisfy the required time-wait timeout of two maximum segment
* lifetimes (see Note #2f5A1a), the time-wait timeout is intially
* used to provide the application layer sufficient time to receive
* the closing received data.
*
* (2) If after the time-wait timeout expires, the application receive
* queue is still not empty, the user connection timeout is used
* to provide the application layer additional time to receive the
* closing received data.
*
* See also Note #3.
*
* (2) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check
* ACK Field : FIN-WAIT-2 STATE' states that "if the retransmission
* queue is empty, the user's CLOSE can be acknowledged".
*
* (B) Although this section is the only section to state that the TCP
* connection should acknowledge the user's close, it is assumed that
* a TCP connection should signal the application layer that "the
* user's close [is] acknowledged" whenever its re-transmit queue
* becomes empty.
*
* (b) (1) "otherwise ignore the segment."
*
* (2) However, it is possible that some but NOT all transmitted data has
* been received by the remote host. In other words, the remote host may
* have received some but NOT ALL transmitted data preceding this host's
* connection close request.
*
* ???? Therefore, acknowledgements validated by as within the transmit
* window MUST be received & processed as in connected states.
*
* See also 'NetTCP_RxPktConnIsValidAck() Note #1d'.
*
* See also Note #2e2.
*$PAGE*
* (e) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that in the "CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that "this should not occur, since a FIN has been received from the remote
* side. Ignore the segment text."
*
* (2) (A) However, it is possible that some but NOT all data has been received from
* the remote host. In other words, the remote host's connection close request
* may have received but ALL receive data preceding the connection close request
* may NOT have been received.
*
* ???? Therefore, receive data validated by sequence number as within the
* receive window MUST be received & processed as in connected states.
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment
* Text' states that "once in the ESTABLISHED state, it is possible to deliver
* segment text to user RECEIVE buffers".
*
* See also Note #2d2B2b.
*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) And the "CLOSING STATE ... remain[s] in the CLOSING state".
*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*
* (4) Since the mechanisms of TCP connection close are independent of the application layer
* close; any external application layer close error(s) are ignored.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerClosing (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
CPU_BOOLEAN data_avail;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
CPU_FNCT_PTR timeout_fnct;
NET_TCP_FREE_CODE free_code;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2A3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
if (pconn->TxQ_State == NET_TCP_TX_Q_STATE_CONN_CLOSED) { /* If local conn close ack'd (see Note #2d2B2a); .. */
/* Closing data avail for half-closed conns ONLY. */
data_avail = ((pconn->ConnCloseCode != NET_CONN_CLOSE_HALF ) ||
((pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) &&
(pconn->RxQ_App_Head == (NET_BUF *)0))) ? DEF_NO : DEF_YES;
/* .. signal app conn close (see Note #2d2B2a2B), .. */
NetTCP_RxPktConnHandlerSignalClose(pconn, data_avail, &err);
switch (err) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_FAIL: /* Ignore any app conn close err(s) [see Note #4]. */
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_INVALID_CONN_ID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_CONN:
case NET_CONN_ERR_NOT_USED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
*perr = err;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
if (data_avail != DEF_YES) { /* .. & if NO app data avail, .. */
/* .. chng to time-wait state (see Note #2d2B2a1B1); */
pconn->ConnState = NET_TCP_CONN_STATE_TIME_WAIT;
pconn->ConnCloseTimeoutFaultFlag = DEF_NO; /* .. clr close timeout fault (see Note #2d2B2a1A2a1); */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
} else { /* .. else chng to closing-data-avail state .. */
/* .. (see Note #2d2B2a1B2a); */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL;
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnClosingTimeoutDataAvail;
}
/* .. & start time-wait tmr (see Notes #2d2B2a1A2a & */
/* .. #2d2B2a1B2b1). */
timeout_sec = pconn->TimeoutMaxSeg_sec * NET_TCP_CONN_TIMEOUT_MAX_SEG_SCALAR;
} else {
timeout_sec = pconn->TimeoutConn_sec; /* Else start conn close tmr (see Note #3b). */
timeout_fnct = (CPU_FNCT_PTR)NetTCP_ConnCloseTimeout;
}
/*$PAGE*/
/* ------------------- UPDATE TMRs -------------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_TIME_WAIT: /* If in time-wait (see Note #2d2B2a1A) ... */
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL: /* ... or closing state(s) [see Note #2d2B2a1B], ... */
free_code = NET_TCP_CONN_FREE_TMR_ALL; /* ... free all TCP conn tmrs (see Note #2d2B2a1A2b). */
DEF_BIT_CLR(free_code, NET_TCP_CONN_FREE_TMR_TIMEOUT);
NetTCP_ConnFreeTmr(pconn, free_code);
break;
}
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) timeout_fnct,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) timeout_fnct,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/*$PAGE*/
/* --------------- TX TCP CONN ACK/DATA --------------- */
ack_code = ((pbuf_hdr->TCP_SegAckTxReqCode == NET_TCP_CONN_TX_ACK_IMMED) ||
(pbuf_hdr->TCP_SegClose == DEF_YES)) /* See Note #2f3. */
? NET_TCP_CONN_TX_ACK_IMMED
: NET_TCP_CONN_TX_ACK;
if (pconn->ConnState == NET_TCP_CONN_STATE_CLOSING) { /* If conn still closing, ... */
/* ... tx ack & any tx data (see Note #1c). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
} else { /* Else tx TCP conn ack (see Note #2f3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, ack_code, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerTimeWait()
*
* Description : (1) Handle TCP connection in TIME-WAIT state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Update TCP connection timer See Notes #2d2C2
*
* (c) Transmit TCP connection acknowledgement See Notes #2d2C1 & #2f3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* -- RETURNED BY NetTCP_RxPktConnIsValidSeq() : --
* -- RETURNED BY NetTCP_RxPktConnIsValidAck() : --
* - RETURNED BY NetTCP_RxPktConnIsValidReset() : -
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* -- RETURNED BY NetTCP_RxPktConnHandlerSeg() : --
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
*
* ------- RETURNED BY NetTCP_TxConnAck() : -------
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) TCP connections in the TIME-WAIT state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* states that in the "CLOSING, LAST-ACK, TIME-WAIT" states that "if the RST bit
* is set then, enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on" ...
*
* (A) "If the ACK is a duplicate (SEG.ACK <= SND.UNA), it can be ignored."
*
* (B) "If the ACK acks something not yet sent ... then send an ACK [and] drop the segment."
*
* (C) For the "TIME-WAIT STATE ... the only thing that can arrive in this state is a
* retransmission of the remote FIN" :
*
* (1) "Acknowledge it" ...
* (2) "restart the 2 MSL timeout."
*
* (e) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that in the "CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that "this should not occur, since a FIN has been received from the remote
* side. Ignore the segment text."
*
* (2) (A) However, it is possible that some but NOT all data has been received from
* the remote host. In other words, the remote host's connection close request
* may have received but ALL receive data preceding the connection close request
* may NOT have been received.
*
* ???? Therefore, receive data validated by sequence number as within the
* receive window MUST be received & processed as in connected states.
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment
* Text' states that "once in the ESTABLISHED state, it is possible to deliver
* segment text to user RECEIVE buffers".
*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) For the "TIME-WAIT STATE" :
*
* (A) "Remain in the TIME-WAIT state" ...
* (B) "Restart the 2 MSL time-wait timeout."
*
* (3) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : TIME-WAIT TIMEOUT' states
* that "if the time-wait timeout expires on a connection ... enter the CLOSED state".
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerTimeWait (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
(void)&pbuf_hdr->TCP_SegClose; /* Ignore any rx'd fin (see Note #2f5A). */
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
/* -------------------- UPDATE TMR -------------------- */
/* Reset time-wait tmr (see Note #2d2C2). */
timeout_sec = pconn->TimeoutMaxSeg_sec * NET_TCP_CONN_TIMEOUT_MAX_SEG_SCALAR;
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/* ----------------- TX TCP CONN ACK ------------------ */
/* Tx TCP conn ack (see Notes #1c). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_IMMED, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
break;
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerCloseWait()
*
* Description : (1) Handle TCP connection in CLOSE-WAIT state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Update TCP connection timer See Note #3
*
* (c) Transmit TCP connection acknowledgement & data See Notes #2d2B & #2f3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
* NET_TCP_ERR_TX TCP transmit error.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) TCP connections in the CLOSE-WAIT state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit' states
* that in the "ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT" states that "if the
* RST bit is set then, any outstanding RECEIVEs and SEND[s] should receive 'reset'
* responses. All segment queues should be flushed. Users should also receive an
* unsolicited general 'connection reset' signal[, and] enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on" ...
*
* (A) And in the "ESTABLISHED STATE" ...
*
* (1) "If SND.UNA < SEG.ACK <= SND.NXT then" ...
*
* (a) "set SND.UNA <- SEG.ACK."
*
* (b) "Any segments on the retransmission queue which are thereby entirely
* acknowledged are removed."
*
* (c) "the send window should be updated" :
*
* (1) (A) (1) "If ((SND.WL1 < SEG.SEQ) or" ...
*
* (2) (a) "(SND.WL1 = SEG.SEQ and" ...
* (b) "SND.WL2 <= SEG.ACK))," ...
*
* (B) (1) "set SND.WND <- SEG.WND," ...
* (2) "set SND.WL1 <- SEG.SEQ," ...
* (3) "set SND.WL2 <- SEG.ACK."
*
* (2) "Note that SND.WND is an offset from SND.UNA, that SND.WL1 records the
* sequence number of the last segment used to update SND.WND, and that
* SND.WL2 records the acknowledgment number of the last segment used to
* update SND.WND. The check here preveents using old segments to update
* the window."
*
* (2) (a) "If the ACK is a duplicate (SEG.ACK <= SND.UNA), it can be ignored."
*
* (b) RFC #1122, Section 4.2.2.20.(g) amends the transmit window update criteria
* for the segment's acknowledgement to include SND.UNA : "The window should
* updated if SND.UNA <= SEG.ACK <= SND.NXT."
*
* See also 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1b2'.
*
* (3) "If the ACK acks something not yet sent (SEG.ACK > SND.NXT) then send an ACK
* [and] drop the segment."
*
* (B) For the "CLOSE-WAIT STATE ... do the same processing as for the ESTABLISHED state".
*
* (e) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that in the "CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that "this should not occur, since a FIN has been received from the remote
* side. Ignore the segment text."
*
* (2) (A) However, it is possible that some but NOT all data has been received from the
* remote host. In other words, the remote host's close request may have been
* received but ALL receive data preceding the close request may NOT have been
* received.
*
* ???? Therefore, receive data validated by sequence number as within the receive
* window MUST be received & processed as in connected states.
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment
* Text' states that "once in the ESTABLISHED state, it is possible to deliver
* segment text to user RECEIVE buffers".
*
* See also Note #2d2B.
*$PAGE*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) And the "CLOSE-WAIT STATE ... remain[s] in the CLOSE-WAIT state".
*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) However, NO RFC specifies or suggests any mechanism to implement/handle user timeouts.
*
* ???? Therefore, it is assumed that ANY TCP connection that receives a valid TCP data
* or control segment should reset its user connection timer.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerCloseWait (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2A3). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
/* -------------------- UPDATE TMR -------------------- */
timeout_sec = pconn->TimeoutConn_sec; /* Reset conn close tmr (see Note #3b). */
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/*$PAGE*/
/* --------------- TX TCP CONN ACK/DATA --------------- */
ack_code = ((pbuf_hdr->TCP_SegAckTxReqCode == NET_TCP_CONN_TX_ACK_IMMED) ||
(pbuf_hdr->TCP_SegClose == DEF_YES)) /* See Note #2f3. */
? NET_TCP_CONN_TX_ACK_IMMED
: NET_TCP_CONN_TX_ACK;
/* Tx ack & any tx data (see Note #1c). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerLastAck()
*
* Description : (1) Handle TCP connection in LAST-ACK state :
*
* (a) Validate received TCP packet for current TCP connection state :
*
* (1) Sequence Number (SEQ) See Note #2a
* (2) Reset (RST) See Note #2b
* (3) Synchronization (SYN) See Note #2c
* (4) Acknowledgement (ACK) See Note #2d
* (5) Finish/Close (FIN) See Note #2f
*
* (b) Update TCP connection :
* (1) Handle received TCP segment See Notes #2d & #2e
* (2) Update TCP connection state : See Notes #2d2A1a & #2d2A1b2A
* (A) Configure TCP connection timeout value
* (3) Update TCP connection timer See Notes #2d2A1b2B & #3
*
* (c) Transmit TCP connection acknowledgement & data See Notes #2d2B & #2f3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_SEQ_SYNC_INVALID Received segment's synchronization is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_ACK_NONE Received segment's acknowledgement is
* NOT available.
* NET_TCP_ERR_CONN_ACK_INVALID Received segment's acknowledgement number is
* NOT valid for current TCP connection.
* NET_TCP_ERR_CONN_RESET_VALID Received segment's reset flag is valid
* for current TCP connection; i.e. reset
* the TCP connection.
* NET_TCP_ERR_CONN_RESET_INVALID Received segment's reset flag is NOT valid
* for current TCP connection.
*
* NET_TCP_ERR_CONN_CLOSED TCP connection successfully closed.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* ----- RETURNED BY NetTCP_RxPktConnIsValidSeq() : -----
* ----- RETURNED BY NetTCP_RxPktConnIsValidAck() : -----
* ---- RETURNED BY NetTCP_RxPktConnIsValidReset() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* ----- RETURNED BY NetTCP_RxPktConnHandlerSeg() : -----
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO
* data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid
* data queued for processing.
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s).
*
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
*
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
*
* ---------- RETURNED BY NetTCP_TxConnTxQ() : ----------
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandler().
*$PAGE*
* Note(s) : (2) TCP connections in the LAST-ACK state are handled as follows :
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that in the "SYN-RECEIVED, ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2
* STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT STATE" that ...
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) "If a segment's contents straddle the boundary between old and new, only the
* new parts should be processed."
*
* (4) (A) "If an incoming segment is not acceptable," ...
*
* (B) "an acknowledgment should be sent in reply" ...
*
* (C) "(unless the RST bit is set, if so drop the segment)".
*
* See also Notes #2b2Aa & #2b2B.
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #1d'.
*
* (b) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit' states
* that in the "ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT" states that "if the
* RST bit is set then, any outstanding RECEIVEs and SEND[s] should receive 'reset'
* responses. All segment queues should be flushed. Users should also receive an
* unsolicited general 'connection reset' signal[, and] enter the CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in any other state [other than LISTEN
* or SYN-RECEIVED], it aborts the connection and advises the user and goes to the
* CLOSED state".
*
* (2) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected
* window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset
* the connection"; it is assumed that this should read "if the RST bit is
* set and the sequence number is exactly the next expected sequence number,
* reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See also Note #2c2.
*
* (c) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that ...
*
* (A) "If the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment queues
* should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state."
*
* (B) But "if the SYN is not in the window this step would not have been reached
* and an ack would have been sent".
*
* (2) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the "handling
* of a segment with the SYN bit set in the synchronized state ... [by] handling
* ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that ... :
*
* (1) "If the ACK bit is off drop the segment."
*
* (2) "If the ACK bit is on [and in the] LAST-ACK STATE" ...
*
* (A) "The only thing that can arrive in this state is an acknowledgement of our FIN."
*
* (1) "If our FIN is now acknowledged" ...
*
* (a) "enter the CLOSED state."
*
* (b) However, it is possible that some closing received data from the remote
* host is available but has NOT yet been received by the application layer.
*
* (1) Therefore, if the application receive queue is closed, then close the
* TCP connection &/or enter the CLOSED state.
*
* (2) (A) But if the application receive queue is NOT closed, then enter the
* connection-closing-data-available state to allow the application
* layer to receive the remaining receive data.
*
* (B) To provide the application layer sufficient time to receive the
* closing received data, the user connection timeout is used as a
* connection closing timeout.
*
* See also Note #2e2.
*
* (2) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* FIN-WAIT-2 STATE' states that "if the retransmission queue is empty, the
* user's CLOSE can be acknowledged".
*
* (b) However, TCP connection should signal the application layer that "the user's
* close [is] acknowledged" whenever its re-transmit queue becomes &/or is
* empty :
*
* (1) Transition from LAST-ACK to CLOSED
*
* See also 'NetTCP_RxPktConnHandlerSignalClose() Note #1'.
*
* (B) However, it is possible that some but NOT all transmitted data has been received
* by the remote host. In other words, the remote host may have received some but
* NOT ALL receive data preceding this host's close request.
*
* ???? Therefore, acknowledgements validated as within the transmit window MUST be
* received & processed as in connected states.
*
* See also 'NetTCP_RxPktConnIsValidAck() Note #1d'.
*
* (e) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text'
* states that in the "CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE" that "this should not occur, since a FIN has been received from the remote
* side. Ignore the segment text."
*
* (2) (A) However, it is possible that some but NOT all data has been received from
* the remote host. In other words, the remote host's close request may have
* received but ALL receive data preceding the close request may NOT have been
* received.
*
* ???? Therefore, receive data validated by sequence number as within the
* receive window MUST be received & processed as in connected states.
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment
* Text' states that "once in the ESTABLISHED state, it is possible to deliver
* segment text to user RECEIVE buffers".
*
* See also Note #2d2A1b.
*
* (f) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set" ...
*
* (1) "signal the user 'connection closing' and return any pending RECEIVEs with
* same message," ...
*
* (2) "advance RCV.NXT over the FIN," ...
*
* (3) "send an acknowledgment for the FIN" ...
*
* (4) "FIN implies PUSH for any segment text not yet delivered to the user" ...
*
* (5) And the "LAST-ACK STATE ... remain[s] in the LAST-ACK state".
*$PAGE*
* (3) (a) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*
* (b) (1) However, a TCP connection enters the LAST-ACK state ONLY after the remote host
* has initiated an active close & enters the TIME-WAIT state, waiting for its
* time-wait timer to expire before closing its TCP connection.
*
* (2) ???? Therefore, a TCP connection in the LAST-ACK state should NOT wait for its
* last acknowledgement from the remote host in the TIME-WAIT state longer than
* the remote host's time-wait timeout of two TCP maximum segment lifetimes.
*
* (3) ???? Therefore, it is assumed that ANY TCP connection in the LAST-ACK state
* that receives a valid TCP data or control segment should reset its time-wait
* timer for two TCP maximum segment lifetimes.
*
* (4) Since the mechanisms of TCP connection close are independent of the application layer
* close; any external application layer close error(s) are ignored.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerLastAck (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEQ_CODE seq_code;
NET_TCP_ACK_CODE ack_code;
NET_TCP_RESET_CODE reset_code;
CPU_BOOLEAN data_avail;
CPU_BOOLEAN close_conn;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
NET_ERR err_rtn;
/*$PAGE*/
/* -------------- VALIDATE RX'D TCP PKT --------------- */
/* Chk for rx'd fin/close. */
if (pbuf_hdr->TCP_SegClose == DEF_YES) { /* If fin/close avail, update seg lens. */
pbuf_hdr->TCP_SegLenInit += NET_TCP_SEG_LEN_CLOSE;
pbuf_hdr->TCP_SegLen += NET_TCP_SEG_LEN_CLOSE;
}
/* Chk rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID:
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, ... */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
/* ... tx TCP conn ack (see Notes #2c2 & #2b2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_SEQ_SYNC_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #2a4A), ... */
default:
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* ... & reset NOT rx'd (see Note #2a4C), ... */
/* ... tx TCP conn ack (see Note #2a4B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
}
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd reset. */
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (reset_code) {
case NET_TCP_CONN_RX_RESET_NONE:
break;
case NET_TCP_CONN_RX_RESET_VALID: /* If valid reset rx'd, ... */
/* ... close TCP conn (see Note #2b1A). */
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_RESET_VALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_RESET_INVALID: /* If invalid reset rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2b2Ac). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* Chk for rx'd ack. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE: /* If NO ack rx'd, ... */
*perr = NET_TCP_ERR_CONN_ACK_NONE; /* ... ignore TCP pkt (see Note #2d1). */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_RX_ACK_INVALID: /* If invalid ack rx'd, ... */
default:
/* ... tx TCP conn ack (see Note #2d2B). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ----------------- HANDLE RX'D SEG ------------------ */
NetTCP_RxPktConnHandlerSeg(pconn, ack_code, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP: /* ???? Allow dup data to update TCP conn? */
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_RX_Q_FULL:
case NET_TCP_ERR_RX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_TX_Q_SIGNAL_FAULT:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ----------------- UPDATE TCP CONN ------------------ */
close_conn = DEF_NO;
if (pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) { /* If remote conn closed (see #2e2A) ... */
/* ... & local conn close ack'd (see #2d2A1) ... */
if (pconn->TxQ_State == NET_TCP_TX_Q_STATE_CONN_CLOSED) {
close_conn = DEF_YES;
}
}
if (close_conn == DEF_YES) {
/* Closing data avail for half-closed conns ONLY. */
data_avail = ((pconn->ConnCloseCode != NET_CONN_CLOSE_HALF ) ||
((pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) &&
(pconn->RxQ_App_Head == (NET_BUF *)0))) ? DEF_NO : DEF_YES;
/* ... signal app conn close (see Note #2d2A2b1); ... */
/* Ignore any app conn close err(s) [see Note #4]. */
NetTCP_RxPktConnHandlerSignalClose(pconn, data_avail, &err);
if (data_avail != DEF_YES) { /* ... & if NO app data avail, ... */
/* ... close TCP conn (see #2d2A1b1); ... */
NetTCP_ConnCloseHandler(pconn, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_CLOSED;
return;
}
/* ... else chng to closing-data-avail state ... */
/* ... (see Note #2d2A1b2A), ... */
pconn->ConnState = NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL;
timeout_sec = pconn->TimeoutUser_sec; /* ... & set user tmr (see Notes #2d2A1b2B). */
} else { /* Else start time-wait tmr (see Note #3b3). */
timeout_sec = pconn->TimeoutMaxSeg_sec * NET_TCP_CONN_TIMEOUT_MAX_SEG_SCALAR;
}
/*$PAGE*/
/* -------------------- UPDATE TMR -------------------- */
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Set((NET_TMR *) pconn->TimeoutTmr,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else {
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
/* --------------- TX TCP CONN ACK/DATA --------------- */
ack_code = ((pbuf_hdr->TCP_SegAckTxReqCode == NET_TCP_CONN_TX_ACK_IMMED) ||
(pbuf_hdr->TCP_SegClose == DEF_YES)) /* See Note #2f3. */
? NET_TCP_CONN_TX_ACK_IMMED
: NET_TCP_CONN_TX_ACK;
/* Tx ack & any tx data (see Note #1c). */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerSeg()
*
* Description : (1) Handle TCP connection's received segments :
*
* (a) Update TCP connection transmit remote window See Note #5
* (b) Update TCP connection controls on transition to connected state(s)
* (c) Handle TCP connection re-transmit queue See Notes #2b & #4
* (d) Update TCP connection transmit congestion controls See Note #6
* (e) Handle TCP connection receive queue(s) See Note #3
* (f) Handle TCP connection receive data See Notes #2a & #3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* ack_code Indicates the received segment's acknowledgement condition :
* --------
* NET_TCP_CONN_RX_ACK_NONE NO received acknowledgement number.
*
* NET_TCP_CONN_RX_ACK_INVALID Received acknowledgement number
* is invalid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_VALID Received acknowledgement number
* is valid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_DUP Received acknowledgement number
* is a duplicate for the
* TCP connection.
*
* NET_TCP_CONN_RX_ACK_PREV Received acknowledgement number
* is a previous duplicate for the
* TCP connection.
*
* Argument validated in NetTCP_RxPktConnHandler() functions.
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_ACK_INVALID Valid received segment acknowledgement NOT available.
*
* -- RETURNED BY NetTCP_RxPktConnHandlerTxWinRemote() : -
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* ---- RETURNED BY NetTCP_RxPktConnHandlerReTxQ() : -----
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
*
* - RETURNED BY NetTCP_TxConnWinSizeHandlerCongCtrl() : -
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
* NET_TCP_ERR_TX TCP transmit error.
*
* --- RETURNED BY NetTCP_RxPktConnHandlerRxQ_Sync() : ---
* --- RETURNED BY NetTCP_RxPktConnHandlerRxQ_Conn() : ---
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but NO data
* to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled & valid data
* queued for application.
*
* --- RETURNED BY NetTCP_RxPktConnHandlerRxQ_Conn() : ---
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment data;
* NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment data;
* NOT queued to receive queue(s).
*
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is NOT
* valid for current TCP connection.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* -- RETURNED BY NetTCP_RxPktConnHandlerRxQ_AppData() : -
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
* NET_TCP_ERR_RX_Q_SIGNAL_CLR TCP connection receive queue clear failed.
*
* Return(s) : none.
*
* Caller(s) : Various NetTCP_RxPktConnHandler() functions.
*$PAGE*
* Note(s) : (2) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that "segments are processed in sequence ... processing is done in SEG.SEQ
* order" (see also Note #3).
*
* (b) The following sections generalize that for the SYN-SENT & ESTABLISHED states that
* "any segments on the retransmission queue which are ... acknowledged should be
* removed" :
*
* (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit'
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* ESTABLISHED STATE'
*
* (3) TCP segments with receive data are sequenced into the appropriate TCP connection
* receive queue(s) to be made available & ready to be read by the application layer.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #3'
* & 'NetTCP_RxPktConnHandlerRxQ_AppData() Note #2'.
*
* (4) A TCP connection's re-transmit queue SHOULD be updated ONLY by valid received
* acknowledgement segments.
*
* See also 'NetTCP_RxPktConnHandlerReTxQ() Note #3'.
*
* (5) RFC #1122, Section 4.2.2.20 generalizes that "when ... SND.UNA < SEG.ACK <= SND.NXT,
* the send window should be updated".
*
* See also 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1'.
*
* (6) RFC #2581, Section 3.1 states that "the slow start and congestion avoidance algorithms
* ... [update] cwnd [TCP transmit congestion control window] for each ACK received that
* acknowledges new data".
*
* (a) A TCP connection's transmit window congestion controls SHOULD be updated :
*
* (1) After any possible updating of the TCP connection re-transmit queue.
* (2) Prior to any possible queuing of data segments onto the TCP connection
* receive queue(s).
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerSeg (NET_TCP_CONN *pconn,
NET_TCP_ACK_CODE ack_code,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_ERR err_rtn;
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN:
NetTCP_RxPktConnHandlerRxQ_Sync(pconn, pbuf, pbuf_hdr, &err_rtn);
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (ack_code != NET_TCP_CONN_RX_ACK_VALID) {
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return;
}
#endif
NetTCP_RxPktConnHandlerTxWinRemote(pconn, ack_code, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
NetTCP_RxPktConnHandlerCfgConn(pconn);
NetTCP_RxPktConnHandlerReTxQ(pconn, ack_code, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
NetTCP_TxConnWinSizeHandlerCongCtrl(pconn, pbuf_hdr, ack_code, 0, NET_TCP_CONN_TX_WIN_SEG_RXD, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_RE_TX_SEG_TH:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
NetTCP_RxPktConnHandlerRxQ_Conn(pconn, pbuf, pbuf_hdr, &err_rtn);
break;
case NET_TCP_CONN_STATE_SYNC_TXD:
if (ack_code == NET_TCP_CONN_RX_ACK_VALID) {
NetTCP_RxPktConnHandlerTxWinRemote(pconn, ack_code, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
NetTCP_RxPktConnHandlerCfgConn(pconn);
NetTCP_RxPktConnHandlerReTxQ(pconn, ack_code, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
NetTCP_TxConnWinSizeHandlerCongCtrl(pconn, pbuf_hdr, ack_code, 0, NET_TCP_CONN_TX_WIN_SEG_RXD, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_RE_TX_SEG_TH:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
NetTCP_RxPktConnHandlerRxQ_Conn(pconn, pbuf, pbuf_hdr, &err_rtn);
} else {
NetTCP_RxPktConnHandlerRxQ_Sync(pconn, pbuf, pbuf_hdr, &err_rtn);
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
break;
case NET_TCP_CONN_RX_ACK_NONE:
case NET_TCP_CONN_RX_ACK_INVALID:
default:
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
NetTCP_RxPktConnHandlerTxWinRemote(pconn, ack_code, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID: /* If valid ack, update re-tx Q (see Note #3). */
case NET_TCP_CONN_RX_ACK_DUP:
NetTCP_RxPktConnHandlerReTxQ(pconn, ack_code, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
break;
}
NetTCP_TxConnWinSizeHandlerCongCtrl(pconn, pbuf_hdr, ack_code, 0, NET_TCP_CONN_TX_WIN_SEG_RXD, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_RE_TX_SEG_TH:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
NetTCP_RxPktConnHandlerRxQ_Conn(pconn, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP:
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_LEN_SEG:
default:
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
NetTCP_RxPktConnHandlerRxQ_AppData(pconn, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
break;
case NET_TCP_CONN_RX_ACK_NONE:
case NET_TCP_CONN_RX_ACK_INVALID:
default:
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
NetTCP_RxPktConnHandlerRxQ_Conn(pconn, pbuf, pbuf_hdr, &err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_CONN_DATA_NONE:
case NET_TCP_ERR_CONN_DATA_VALID:
break;
case NET_TCP_ERR_CONN_DATA_DUP:
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_DATA_INVALID:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_LEN_SEG:
default:
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
NetTCP_RxPktConnHandlerRxQ_AppData(pconn, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
break;
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_CLOSED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = err_rtn;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerCfgConn()
*
* Description : (1) Configure TCP connection's controls on transition to connected state(s) :
*
* (a) Configure TCP connection maximum segment size control(s)
* (b) Configure TCP connection window size controls
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg().
*
* Note(s) : (2) During TCP connection initialization, some TCP connection controls were previously
* configured in NetTCP_ConnGet() when the TCP connection was allocated from the TCP
* connection pool. These TCP connection controls do NOT need to be re-configured
* but are shown for completeness.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerCfgConn (NET_TCP_CONN *pconn)
{
NET_TCP_CFG_CODE cfg_code;
/* Cfg conn (see Note #1). */
cfg_code = NET_TCP_CONN_CFG_NONE |
NET_TCP_CONN_CFG_MAX_SEG_SIZE_CONN |
NET_TCP_CONN_CFG_WIN_SIZE_ALL;
#if 0 /* Cfg'd in NetTCP_ConnGet() [see Note #2]. */
DEF_BIT_SET(cfg_code, NET_TCP_CONN_CFG_TX_RTT_RTO);
#endif
NetTCP_ConnCfg(pconn, cfg_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerRxQ_Sync()
*
* Description : (1) (a) Handle TCP connection's transport receive queue ... :
*
* (1) Update TCP connection initial receive sequence numbers See Note #2b
* (2) Queue received TCP segments onto transport receive queue See Note #3
* (3) Update TCP connection receive window
*
* (b) ... for the following connection-request/synchronization states :
*
* (1) LISTEN
* (2) SYN-SENT
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but
* NO data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled &
* data queued to receive queue(s)
* for later processing (see Note #2c).
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection receive queue
* state.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg().
*
* Note(s) : (2) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that "segments are processed in sequence ... processing is done in SEG.SEQ
* order."
*
* (b) The following sections generalize that for the LISTEN & SYN-SENT states that "if the
* SYN bit is on and ... acceptable then ... RCV.NXT is set to SEG.SEQ+1, IRS is set to
* SEG.SEQ" :
*
* (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for SYN'
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit'
*
* (c) (1) The following sections generalize that for the LISTEN & SYN-SENT states that "if
* there are other controls or text in the segment, queue them for later processing
* after the ESTABLISHED state has been reached" :
*
* (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for SYN'
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit'
*
* (2) If any control or text is queued for later processing, the next sequence octet to
* receive (RCV.NXT) MUST include the length of this received segment (SEG.LEN) :
*
* (A) RCV.NXT = SEG.SEQ + SEG.LEN + 1
* (3) TCP segments with receive data are sequenced into the appropriate TCP connection
* receive queue(s) to be made available & ready to be read by the application layer.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #3'
* & 'NetTCP_RxPktConnHandlerRxQ_AppData() Note #2'.
*
* (4) Some buffer controls were previously initialized in NetBuf_Get() when the buffer was
* allocated. These buffer controls do NOT need to be re-initialized but are shown for
* completeness.
*
* (5) RFC #793, Section 3.7 'Data Communication : Managing the Window' states that "the window
* sent in each segment indicates the range of sequence numbers the sender of the window
* (the data receiver) is currently prepared to accept. There is an assumption that this
* is related to the currently available data buffer space available for this connection
* ... One strategy would be to ... [update the] information when the window" changes.
*
* See also 'NetTCP_RxAppData() Note #7',
* 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #6',
* & 'NetTCP_RxConnWinSizeHandler() Note #2a'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerRxQ_Sync (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
NET_TCP_SEG_SIZE seg_len;
NET_TCP_SEG_SIZE seg_len_data;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------- VALIDATE RX Q CONN STATE ------------- */
switch (pconn->RxQ_State) {
case NET_TCP_RX_Q_STATE_CONN_CLOSED:
break;
case NET_TCP_RX_Q_STATE_NONE:
case NET_TCP_RX_Q_STATE_CLOSED:
case NET_TCP_RX_Q_STATE_CONN_SYNC:
case NET_TCP_RX_Q_STATE_CONN:
case NET_TCP_RX_Q_STATE_CONN_CLOSING:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* Update TCP conn rx seq nbrs (see Notes #2b & #2c2). */
pconn->RxSeqNbrSync = (NET_TCP_SEQ_NBR) pbuf_hdr->TCP_SeqNbr;
pconn->RxSeqNbrNext = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + pbuf_hdr->TCP_SegLen);
pconn->RxQ_State = NET_TCP_RX_Q_STATE_CONN_SYNC;
seg_len = (NET_TCP_SEG_SIZE)pbuf_hdr->TCP_SegLen;
if (seg_len > NET_TCP_SEG_LEN_SYNC) { /* If rx'd seg len > sync seg len, ... */
/* ... Q seg to TCP conn rx Q (see Notes #3 & #2c1). */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NetTCP_ConnFreeBufQ(&pconn->RxQ_Transport_Head, &pconn->RxQ_Transport_Tail);
#endif
pconn->RxQ_Transport_Head = (NET_BUF *)pbuf;
pconn->RxQ_Transport_Tail = (NET_BUF *)pbuf;
#if 0 /* Init'd in NetBuf_Get() [see Note #4]. */
pbuf_hdr->PrevPrimListPtr = (void *)0;
pbuf_hdr->NextPrimListPtr = (void *)0;
#endif
/* Dec TCP conn's rx win size (see Note #5). */
seg_len_data = (NET_TCP_SEG_SIZE)pbuf_hdr->TCP_SegLenData;
NetTCP_RxConnWinSizeHandler((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)pbuf_hdr,
(NET_TCP_WIN_SIZE)seg_len_data,
(NET_TCP_WIN_CODE)NET_TCP_CONN_RX_WIN_DEC);
*perr = NET_TCP_ERR_CONN_DATA_VALID;
} else {
*perr = NET_TCP_ERR_CONN_DATA_NONE;
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerRxQ_Conn()
*
* Description : (1) (a) Handle TCP connection's transport receive queue ... :
*
* (1) Update TCP connection receive sequence numbers See Notes #2c & #2e
* (2) Insert received TCP segments in sequence order See Notes #3 & #4
* (3) Update TCP connection receive window
*
* (b) ... for the following connected states :
*
* (1) SYN-RECEIVED See Notes #1bA & #2b2
* (2) SYN-SENT See Notes #1bA & #2b1
* (3) ESTABLISHED See Note #1bB
* (4) FIN-WAIT-1 See Note #1bB
* (5) FIN-WAIT-2 See Note #1bB
* (6) CLOSING See Note #1bC
* (7) TIME-WAIT See Note #1bC
* (8) CLOSE-WAIT See Note #1bC
* (9) LAST-ACK See Note #1bC
*
*
* (A) For synchronization-to-connected state transitions, segments are queued to
* the TCP connection's transport receive queue, but NOT to the TCP connection's
* application receive queue, until the application layer is signaled that the
* transport layer connection is complete.
*
* See also 'NetTCP_RxPktConnHandlerSyncRxd() Note #1c1'
* & 'NetTCP_RxPktConnHandlerSyncTxd() Note #1c1'.
*
* (B) For connected states, segments are queued to the TCP connection's
* transport &/or application receive queue(s) as appropriate (see Note #3).
*
* (C) For closing states; closing segments are queued to the TCP connection's
* transport &/or application receive queue(s) as for connected states.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* pbuf Pointer to network buffer that received TCP packet.
* ---- Argument checked in NetTCP_Rx().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_CONN_DATA_NONE Received packet successfully handled; but
* NO data to queue to receive queue(s).
* NET_TCP_ERR_CONN_DATA_VALID Received packet successfully handled &
* data queued to receive queue(s)
* for later processing (see Note #3).
* NET_TCP_ERR_CONN_DATA_INVALID Received packet contains invalid segment
* data; NOT queued to receive queue(s).
* NET_TCP_ERR_CONN_DATA_DUP Received packet contains duplicate segment
* data; NOT queued to receive queue(s)
* (see Note #2a2).
*
* NET_TCP_ERR_CONN_SEQ_INVALID Received segment's sequence number is NOT
* valid for current TCP connection.
*
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection receive queue state.
*
* - RETURNED BY NetTCP_RxPktConnIsValidSeq() : -
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg().
*$PAGE*
* Note(s) : (2) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence Number'
* states that ... :
*
* (1) "Segments are processed in sequence ... processing is done in SEG.SEQ order."
*
* (A) Assumes received segment's sequences previously validated.
*
* (2) "Initial tests on arrival are used to discard old duplicates."
*
* (3) (A) (1) "If a segment's contents straddle the boundary between old and new,
* only the new parts should be processed."
*
* (2) "One could tailor actual segments to ... the idealized segment that
* begins at RCV.NXT and does not exceed the window ... by trimming off
* any portions that lie outside the window (including SYN and FIN),
* and only processing further if the segment then begins at RCV.NXT.
* Segments with higher beginning sequence numbers may be held for later
* processing."
*
* (B) (1) Sequencing received segments with duplicate data that overlaps
* multiple previously-received segments' non-contiguous sequence numbers
* is data intensive/expensive.
*
* (2) Therefore, any received segment with duplicate data that overlaps
* multiple previously-received segments' non-contiguous sequence numbers
* is trimmed of duplicate data starting from the end of the received
* segment's data.
*
* In other words, only the first contiguous, non-duplicate data sequence
* starting from the start of the received segment's data is sequenced
* into the TCP connection's receive queue(s).
*
* (C) RFC #1122, Section 4.2.2.20 states that "a TCP SHOULD be capable of queueing
* out-of-order TCP segments".
*
* (b) The following sections generalize that in the "SYN-SENT [or] ... SYN-RECEIVED
* STATE[s], ... [that] if the ACK bit is on [and] our SYN has been ACKed ...
* then enter the ESTABLISHED state and continue processing" :
*
* (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit'
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* SYN-RECEIVED STATE'
*
* (c) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit' states that "if the SYN bit is on and ... acceptable then ...
* RCV.NXT is set to SEG.SEQ+1, IRS is set to SEG.SEQ".
*
* (d) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit' states that "if there are other controls or text in the segment,
* queue them for later processing after the ESTABLISHED state has been reached"
* (see also Note #2b).
*
* (2) If any control or text is queued for later processing, the next sequence octet to
* receive (RCV.NXT) MUST include the length of this received segment (SEG.LEN) :
*
* (A) RCV.NXT = SEG.SEQ + SEG.LEN + 1
*
* (e) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set ... advance RCV.NXT over the FIN".
*
* (2) However, the next octet to receive is NOT updated with the sequence number of the
* last octet to receive. Instead, the generic sequence algorithm maintains & updates
* BOTH the next & last octets to receive for the closing TCP connection.
*$PAGE*
* (3) TCP segments with receive data are sequenced first into the TCP connection's transport
* receive queue to be made available & ready to be read by the application layer from the
* TCP connection's application receive queue (see 'NetTCP_RxPktConnHandlerRxQ_AppData()
* Note #2').
*
* (a) Received TCP segments are inserted into a doubly-linked Transport Receive Queue,
* sorted by their sequence number(s).
*
* (1) 'RxQ_Transport_Head' points to the head of the Transport Receive Queue;
* 'RxQ_Transport_Tail' points to the tail of the Transport Receive Queue.
*
* (2) Segment buffers' 'PrevPrimListPtr' & 'NextPrimListPtr' doubly-link each
* segment to form the Transport Receive Queue.
*
* (3) Fragmented segment buffer's 'PrevBufPtr' & 'NextBufPtr' doubly-link each
* fragmented segment (see also 'net_ip.c NetIP_RxPktFragReasm() Note #2b3').
*
* (b) Typically & most-frequently, TCP segments will be received in sequence-order.
* Therefore, the sequence sort algorithm starts at the tail of the Transport
* Receive Queue.
*
* (c) As segments are inserted into the Transport Receive Queue, segments migrate to
* the head of the Transport Receive Queue. Queued segments with sequence numbers
* that are contiguous from the next expected receive sequence number are ready to
* be read by the application layer, so are immediately moved from the Transport
* Receive Queue to the Application Receive Queue.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_AppData() Note #2'.
*
*
* | |
* |<-- TCP Connection Transport Receive Queue --->|
* | (see Note #3) |
*
* Segments Moved Segments Sequenced
* to Application into Transport
* Receive Queue Receive Queue
* starting at head starting at tail
* (see Note #3c) (see Note #3b)
*
* | NextPrimListPtr |
* | (see Note #3a2) |
* v | v
* |
* Head of ------- ------- v ------- ------- (see Note #3a1)
* Receive ---->| |------>| |------>| |------>| |
* Queue | | | | | | | | Tail of
* | |<------| |<------| |<------| |<---- Receive
* (see Note #3a1) | | | | ^ | | | | Queue
* | | | | | | | | |
* ------- ------- | ------- -------
* | ^ | | ^
* | | PrevPrimListPtr | |
* v | (see Note #3a2) v |
* ------- -------
* | | | |
* | | | |
* | | | |
* | | | |
* | | | |
* ------- -------
* | ^ | ^
* NextBufPtr ---> | | <--- PrevBufPtr | |
* (see Note #3a3) v | (see Note #3a3) v |
* ------- -------
* | | | |
* | | | |
* | | -------
* | |
* | |
* -------
*
*$PAGE*
* (4) RFC #793 does NOT provide nor suggest any logic to determine/handle sequence number
* comparisons for sequence number windows that overflow the sequence number space.
*
* (a) For example, the next sequence octet to receive (RCV.NXT) is typically less than
* or equal to the next received sequence octet (SEG.SEQ) :
*
* (1) RCV.NXT <= SEG.SEQ
*
* SEG.SEQ itself is also typically less than RCV.NXT plus the current receive window
* size (RCV.WND) :
*
* (2) SEG.SEQ < RCV.NXT + RCV.WND
*
* However, if (RCV.NXT + RCV.WND) or SEG.SEQ overflows the sequence number space,
* these values will be MUCH less than SEG.SEQ or RCV.NXT, respectively, until
* SEG.SEQ & RCV.NXT also overflow :
*
* (3) RCV.NXT + RCV.WND << RCV.NXT
* << SEG.SEQ
*
* (4) SEG.SEQ << RCV.NXT
*
* (b) Therefore, in order to determine if a received segment's sequence value precedes any
* previously received segment(s) in the TCP connection's receive queue(s), the following
* unsigned arithmetic comparisons MUST be checked :
*
* (1) RxQCur.SeqNbr - (SEG.SEQ + 1) < RX.WIN
*
* (2) RX.NXT - (SEG.SEQ + 1) < SEG.LEN
*
* Note that these comparisons bound any received segment's sequence within limits set
* by the TCP connection's receive window size & next expected receive octet.
*
* (c) In order to determine if a received segment's sequence value overlaps any previously
* received segment(s) in the TCP connection's receive queue, the following unsigned
* arithmetic comparisons MUST be checked :
*
* (1) ( SEG.SEQ + SEG.LEN ) - (RxQNext.SeqNbr + 1) < SEG.LEN
*
* (2) (RxQCur.SeqNbr + RxQCur.SegLen) - (SEG.SEQ + 1) < RxQCur.SegLen
*
* See also 'NetTCP_RxPktConnIsValidSeq() Note #2'.
*
* (5) (a) RFC #2581, Section 3.2 states that "a TCP receiver SHOULD send an immediate ACK" :
*
* (1) "When an out-of-order segment arrives. The purpose of this ACK is to inform
* the sender that a segment was received out-of-order and which sequence number
* is expected."
*
* (2) "In addition, ... when the incoming segment fills in all or part of a gap in
* the sequence space."
*
* See also 'NetTCP_TxConnAck() Note #4a5'.
*
* (b) Since segments are typically received in sequence order (see Notes #5a1 & #3b) &
* since segments received in sequential order are immediately made available & ready
* to be read by the application layer (see Note #3c), received segments are out-of-
* order AND/OR fill in sequence number gaps whenever :
*
* (1) A TCP connection's Transport Receive Queue is initially non-empty;
* OR
* (2) A TCP connection's Transport Receive Queue's head segment's sequence number
* does NOT equal the TCP connection's next expected receive sequence number.
*
* (c) However, since a TCP connection's next expected receive sequence numbers are NOT
* updated until both of the TCP connection's transport & application receive queues
* have been handled (see 'NetTCP_RxPktConnHandlerRxQ_AppData() Note #1a3'), the
* transmission of any immediate acknowledgement MUST follow the handling of BOTH
* of the TCP connection's receive queues.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_AppData() Notes #1a3 & #4'.
*
* (6) RFC #793, Section 3.7 'Data Communication : Managing the Window' states that "the window
* sent in each segment indicates the range of sequence numbers the sender of the window
* (the data receiver) is currently prepared to accept. There is an assumption that this
* is related to the currently available data buffer space available for this connection
* ... One strategy would be to ... [update the] information when the window" changes.
*
* See also 'NetTCP_RxAppData() Note #7',
* 'NetTCP_RxPktConnHandlerRxQ_Sync() Note #5',
* & 'NetTCP_RxConnWinSizeHandler() Note #2a'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerRxQ_Conn (NET_TCP_CONN *pconn,
NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_SEQ_CODE seq_code;
#endif
NET_BUF *pbuf_q;
NET_BUF *pbuf_q_head;
NET_BUF *pbuf_q_prev;
NET_BUF *pbuf_q_next;
NET_BUF_HDR *pbuf_q_hdr;
NET_BUF_HDR *pbuf_q_hdr_head;
NET_BUF_HDR *pbuf_q_hdr_next;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR seq_nbr_next;
NET_TCP_SEQ_NBR seq_nbr_dup;
NET_TCP_SEQ_NBR seq_nbr_delta;
NET_TCP_SEQ_NBR seq_nbr_win;
CPU_BOOLEAN seq_srch_done;
CPU_BOOLEAN seq_unordered_prev;
CPU_BOOLEAN seq_unordered_cur;
CPU_BOOLEAN seq_unordered;
/* ----------- UPDATE TCP CONN RX SEQ NBRS ------------ */
if (pconn->ConnState == NET_TCP_CONN_STATE_SYNC_TXD) {
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
switch (pconn->RxQ_State) {
case NET_TCP_RX_Q_STATE_CONN_CLOSED:
break;
case NET_TCP_RX_Q_STATE_NONE:
case NET_TCP_RX_Q_STATE_CLOSED:
case NET_TCP_RX_Q_STATE_CONN_SYNC:
case NET_TCP_RX_Q_STATE_CONN:
case NET_TCP_RX_Q_STATE_CONN_CLOSING:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* Init SYN-SENT state (see Notes #2c & #2d2). */
pconn->RxSeqNbrSync = (NET_TCP_SEQ_NBR) pbuf_hdr->TCP_SeqNbr;
pconn->RxSeqNbrNext = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + pbuf_hdr->TCP_SegLen);
pconn->RxQ_State = NET_TCP_RX_Q_STATE_CONN_SYNC;
} else {
switch (pconn->RxQ_State) {
case NET_TCP_RX_Q_STATE_CONN_SYNC:
break;
case NET_TCP_RX_Q_STATE_CONN:
/* Chk TCP conn closing (see Note #2e). */
if (pbuf_hdr->TCP_SegClose == DEF_YES) {
pconn->RxSeqNbrLast = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + pbuf_hdr->TCP_SegLen);
pconn->RxSeqNbrClose = (NET_TCP_SEQ_NBR)(pconn->RxSeqNbrLast - NET_TCP_SEG_LEN_CLOSE);
pconn->RxQ_State = NET_TCP_RX_Q_STATE_CONN_CLOSING;
}
/* 'break' intentionally omitted; do NOT move from the */
/* .. following case : 'NET_TCP_RX_Q_STATE_CONN_CLOSED'.*/
case NET_TCP_RX_Q_STATE_CONN_CLOSED:
case NET_TCP_RX_Q_STATE_CONN_CLOSING:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* Chk valid rx'd seq nbr. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (seq_code != NET_TCP_CONN_RX_SEQ_VALID) {
*perr = NET_TCP_ERR_CONN_SEQ_INVALID;
return;
}
#endif
break;
case NET_TCP_RX_Q_STATE_NONE:
case NET_TCP_RX_Q_STATE_CLOSED:
default:
*perr = NET_TCP_ERR_CONN_DATA_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
/*$PAGE*/
if (pbuf_hdr->TCP_SegLenData < 1) { /* If seg data len < 1, AND ... */
/* ... NOT in rx conn closing state OR ... */
if ((pconn->RxQ_State != NET_TCP_RX_Q_STATE_CONN_CLOSING) ||
(pbuf_hdr->TCP_SegClose != DEF_YES)) { /* ... fin/close NOT rx'd; ... */
*perr = NET_TCP_ERR_CONN_DATA_NONE; /* ... rtn data NOT avail. */
return;
} /* Else seq & handle closing-ctrl seg. */
}
/* ------- INSERT SEG INTO SEQ'D TRANSPORT RX Q ------- */
pbuf_q = (NET_BUF *)pconn->RxQ_Transport_Tail; /* Start seq insert alg from rx Q tail (see Note #3b). */
pbuf_q_next = (NET_BUF *)0;
seq_srch_done = DEF_NO;
/* Chk init'l rx Q seq order (see Note #5b1). */
seq_unordered_prev = (pconn->RxQ_Transport_Head != (NET_BUF *)0)
? DEF_YES : DEF_NO;
while (seq_srch_done == DEF_NO) { /* Srch rx Q to insert rx'd seg into seq nbr position. */
if (pbuf_q != (NET_BUF *)0) { /* While NOT @ rx Q head, chk if seg ... */
pbuf_q_hdr = (NET_BUF_HDR *)&pbuf_q->Hdr;
pbuf_q_prev = (NET_BUF *) pbuf_q_hdr->PrevPrimListPtr;
/* ... before or after cur rx Q seg (see Note #2a1). */
seq_nbr_next = (NET_TCP_SEQ_NBR) pbuf_q_hdr->TCP_SeqNbr;
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + 1);
seq_nbr_delta = (NET_TCP_SEQ_NBR)(seq_nbr_next - seq_nbr);
seq_nbr_win = (NET_TCP_SEQ_NBR) pconn->RxWinSizeCfgdActual;
if (seq_nbr_delta < seq_nbr_win) { /* If seg's seq nbr < cur rx Q's seq nbr (see Note #4b1)*/
/* ... adv to prev rx Q seg; but chk ... */
/* ... for dup seqs in next rx Q seg. */
seq_nbr_next = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + pbuf_hdr->TCP_SegLen);
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_q_hdr->TCP_SeqNbr + 1);
seq_nbr_delta = (NET_TCP_SEQ_NBR)(seq_nbr_next - seq_nbr);
seq_nbr_win = (NET_TCP_SEQ_NBR) pbuf_hdr->TCP_SegLen;
if (seq_nbr_delta < seq_nbr_win) { /* If seg overlaps next rx Q seqs (see Note #4c1), ... */
seq_nbr_dup = seq_nbr_delta + 1; /* ... trim dup seqs from seg (see Note #2a3); ... */
if (pbuf_hdr->TCP_SegLenData > (CPU_INT16U)seq_nbr_dup) {
pbuf_hdr->TCP_SegLenData -= (CPU_INT16U)seq_nbr_dup;
pbuf_hdr->TCP_SegLen -= (CPU_INT16U)seq_nbr_dup;
} else { /* ... else discard ALL dup seqs (see Note #2a2). */
*perr = NET_TCP_ERR_CONN_DATA_DUP;
return;
}
}
/* Adv to prev rx Q seg. */
pbuf_q_next = (NET_BUF *)pbuf_q;
pbuf_q = (NET_BUF *)pbuf_q_prev;
} else { /* Else insert seg between cur/next rx Q segs. */
/* Chk for dup seqs in cur rx Q seg. */
seq_nbr_next = (NET_TCP_SEQ_NBR)(pbuf_q_hdr->TCP_SeqNbr + pbuf_q_hdr->TCP_SegLen);
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + 1);
seq_nbr_delta = (NET_TCP_SEQ_NBR)(seq_nbr_next - seq_nbr);
seq_nbr_win = (NET_TCP_SEQ_NBR) pbuf_q_hdr->TCP_SegLen;
if (seq_nbr_delta < seq_nbr_win) { /* If seg overlaps prev'ly rx'd seqs (see Note #4c2), */
seq_nbr_dup = seq_nbr_delta + 1; /* ... trim dup seqs from seg (see Note #2a3); ... */
if (pbuf_hdr->TCP_SegLenData > (CPU_INT16U)seq_nbr_dup) {
pbuf_hdr->TCP_SegLenData -= (CPU_INT16U)seq_nbr_dup;
pbuf_hdr->TCP_SegLen -= (CPU_INT16U)seq_nbr_dup;
pbuf_hdr->TCP_SeqNbr = (CPU_INT32U)seq_nbr_next;
} else { /* ... else discard ALL dup seqs (see Note #2a2). */
*perr = NET_TCP_ERR_CONN_DATA_DUP;
return;
}
}
seq_srch_done = DEF_YES;
}
/*$PAGE*/
} else { /* Else if @ head of rx Q, entire rx Q srch'd; ... */
/* ... chk for dup seqs prior to TCP conn's ... */
/* ... next expected rx octet. */
seq_nbr_next = (NET_TCP_SEQ_NBR) pconn->RxSeqNbrNext;
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + 1);
seq_nbr_delta = (NET_TCP_SEQ_NBR)(seq_nbr_next - seq_nbr);
seq_nbr_win = (NET_TCP_SEQ_NBR) pbuf_hdr->TCP_SegLen;
if (seq_nbr_delta < seq_nbr_win) { /* If seg overlaps prev'ly rx'd seqs (see Note #4b2), */
seq_nbr_dup = seq_nbr_delta + 1; /* ... trim dup seqs from seg (see Note #2a3); */
if (pbuf_hdr->TCP_SegLenData > (CPU_INT16U)seq_nbr_dup) {
pbuf_hdr->TCP_SegLenData -= (CPU_INT16U)seq_nbr_dup;
pbuf_hdr->TCP_SegLen -= (CPU_INT16U)seq_nbr_dup;
pbuf_hdr->TCP_SeqNbr = (CPU_INT32U)seq_nbr_next;
} else { /* ... else discard ALL dup seqs (see Note #2a2). */
*perr = NET_TCP_ERR_CONN_DATA_DUP;
return;
}
}
seq_srch_done = DEF_YES;
}
}
/* Insert rx'd seg between cur/next rx Q segs. */
pbuf_hdr->PrevPrimListPtr = (void *)pbuf_q;
if (pbuf_q != (NET_BUF *)0) { /* If avail, insert rx'd seg after cur rx Q seg. */
pbuf_q_hdr->NextPrimListPtr = (void *)pbuf;
} else { /* Else insert rx'd seg @ rx Q head. */
pconn->RxQ_Transport_Head = (NET_BUF *)pbuf;
}
pbuf_hdr->NextPrimListPtr = (void *)pbuf_q_next;
if (pbuf_q_next != (NET_BUF *)0) { /* If avail, insert rx'd seg before next rx Q seg. */
pbuf_q_hdr_next = (NET_BUF_HDR *)&pbuf_q_next->Hdr;
pbuf_q_hdr_next->PrevPrimListPtr = (void *) pbuf;
} else { /* Else insert rx'd seg @ rx Q tail. */
pconn->RxQ_Transport_Tail = (NET_BUF *) pbuf;
}
/* Chk rx'd out-of-order seg(s) [see Note #5a]. */
if (pconn->RxQ_Transport_Head != (NET_BUF *)0) {
pbuf_q_head = (NET_BUF *) pconn->RxQ_Transport_Head;
pbuf_q_hdr_head = (NET_BUF_HDR *)&pbuf_q_head->Hdr;
/* Chk cur rx Q seq order (see Note #5b2). */
seq_unordered_cur = ((NET_TCP_SEQ_NBR)pbuf_q_hdr_head->TCP_SeqNbr
!= (NET_TCP_SEQ_NBR)pconn->RxSeqNbrNext)
? DEF_YES : DEF_NO;
}
seq_unordered = ((seq_unordered_prev == DEF_YES) ||
(seq_unordered_cur == DEF_YES)) ? DEF_YES : DEF_NO;
if (seq_unordered != DEF_NO) { /* If out-of-order seg(s) rx'd (see Note #5a) ... */
if (pconn->RxQ_State != NET_TCP_RX_Q_STATE_CONN_SYNC) { /* ... in non-sync state, ... */
/* ... req immed TCP conn ack tx (see Note #5c). */
pbuf_hdr->TCP_SegAckTxReqCode = NET_TCP_CONN_TX_ACK_IMMED;
}
}
/* ----------- UPDATE TCP CONN RX WIN SIZE ------------ */
/* Dec TCP conn's rx win size (see Note #6). */
NetTCP_RxConnWinSizeHandler((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)pbuf_hdr,
(NET_TCP_WIN_SIZE)pbuf_hdr->TCP_SegLenData,
(NET_TCP_WIN_CODE)NET_TCP_CONN_RX_WIN_DEC);
*perr = NET_TCP_ERR_CONN_DATA_VALID;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerRxQ_AppData()
*
* Description : (1) (a) Handle TCP connection's application receive queue ... :
*
* (1) Remove segments from TCP connection's transport receive queue See Note #3b1B
* (2) Update TCP connection transport receive queue
* (3) Update TCP connection receive sequence numbers
* (4) Move segments onto TCP connection's application receive queue See Note #2
* (5) Update TCP connection receive window See Note #6
*
* (b) ... for the following connected states :
*
* (1) SYN-RECEIVED See Note #1bA
* (2) SYN-SENT See Note #1bA
* (3) ESTABLISHED See Note #1bB
* (4) FIN-WAIT-1 See Note #1bB
* (5) FIN-WAIT-2 See Note #1bB
* (6) CLOSING See Note #1bC
* (7) TIME-WAIT See Note #1bC
* (8) CLOSE-WAIT See Note #1bC
* (9) LAST-ACK See Note #1bC
*
*
* (A) For synchronization-to-connected state transitions, segments are queued to
* the TCP connection's transport receive queue, but NOT to the TCP connection's
* application receive queue, until the application layer is signaled that the
* transport layer connection is complete.
*
* See also 'NetTCP_RxPktConnHandlerSyncRxd() Note #1c1'
* & 'NetTCP_RxPktConnHandlerSyncTxd() Note #1c1'.
*
* (B) For connected states, segments are queued to the TCP connection's application
* receive queue as appropriate (see Notes #2 & #3b).
*
* (C) For closing states; closing segments are queued to the TCP connection's
* transport &/or application receive queue(s) as for connected states.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection's application receive queue
* successfully handled.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection receive queue state.
*
* ---- RETURNED BY NetOS_TCP_RxQ_Signal() : ----
* NET_TCP_ERR_RX_Q_FULL TCP connection receive queue full.
* NET_TCP_ERR_RX_Q_SIGNAL_FAULT TCP connection receive queue signal fault.
*
* ----- RETURNED BY NetOS_TCP_RxQ_Clr() : ------
* NET_TCP_ERR_RX_Q_SIGNAL_CLR TCP connection receive queue clear failed.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg(),
* NetTCP_RxPktConnHandlerSyncRxd(),
* NetTCP_RxPktConnHandlerSyncTxd().
*$PAGE*
* Note(s) : (2) TCP segments with receive data that are available & ready to be read by the application
* layer are linked in a TCP connection's application receive queue.
*
* (a) Received TCP segments are moved from the doubly-linked Transport Receive Queue,
* sorted by their sequence number(s), onto the Application Receive Queue.
*
* (1) 'RxQ_App_Head' points to the head of the Application Receive Queue;
* 'RxQ_App_Tail' points to the tail of the Application Receive Queue.
*
* (2) Segment buffers' 'PrevPrimListPtr' & 'NextPrimListPtr' doubly-link each
* segment to form the Application Receive Queue.
*
* (3) Fragmented segment buffer's 'PrevBufPtr' & 'NextBufPtr' doubly-link each
* fragmented segment (see also 'net_ip.c NetIP_RxPktFragReasm() Note #2b3').
*
* (b) TCP segments are appended in sequence order from the head of a TCP connection's
* Transport Receive Queue to the tail of the TCP connection's Application Receive
* Queue.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #3'.
*
* (c) Application data is read from segments starting from the head of the Application
* Receive Queue. Segments that are read by the application layer are removed from
* the Application Receive Queue.
*
*
* | |
* |<- TCP Connection Application Receive Queue -->|
* | (see Note #2) |
*
* Segments Read by Segments Appended to
* Application Layer Application Receive Queue
* starting at head starting at tail
* (see Note #2c) (see Note #2b)
*
* | NextPrimListPtr |
* | (see Note #2a2) |
* v | v
* |
* Head of ------- ------- v ------- ------- (see Note #2a1)
* Receive ---->| |------>| |------>| |------>| |
* Queue | | | | | | | | Tail of
* | |<------| |<------| |<------| |<---- Receive
* (see Note #2a1) | | | | ^ | | | | Queue
* | | | | | | | | |
* ------- ------- | ------- -------
* | ^ | | ^
* | | PrevPrimListPtr | |
* v | (see Note #2a2) v |
* ------- -------
* | | | |
* | | | |
* | | | |
* | | | |
* | | | |
* ------- -------
* | ^ | ^
* NextBufPtr ---> | | <--- PrevBufPtr | |
* (see Note #2a3) v | (see Note #2a3) v |
* ------- -------
* | | | |
* | | | |
* | | -------
* | |
* | |
* -------
*
*$PAGE*
* (3) (a) (1) RFC #793, Section 3.8 'Interfaces : User/TCP Interface : TCP User Commands :
* Receive' states that :
*
* (A) "If enough data arrive [sic] to fill the buffer before a PUSH is seen,
* the PUSH flag will not be set in the response to the RECEIVE. The
* buffer will be filled with as much data as it can hold."
*
* (B) "If the PUSH is seen before the buffer is filled the buffer will be
* returned partially filled and PUSH indicated."
*
* See Notes #3b1B & #3b1B.
*
* (2) RFC #1122, Section 4.2.2.2 states that :
*
* (A) (1) "At the receiver, the PSH bit forces buffered data to be delivered to
* the application (even if less than a full buffer has been received)."
*
* (2) (a) "Conversely, the lack of a PSH bit can be used to avoid unnecessary
* wakeup calls to the application process; this can be an important
* performance optimization for large timesharing hosts."
*
* (b) "When a series of segments is received without the PSH bit, a TCP
* MAY queue the data internally without passing it to the receiving
* application."
*
* (B) (1) "Passing the PSH bit to the receiving application allows an ...
* optimization within the application."
*
* (2) "RFC-793 ... erroneously implies that a received PSH flag must be passed
* to the application layer. Passing a received PSH flag to the application
* layer is now OPTIONAL."
*
* (C) "The PSH bit is not a record marker and is independent of segment boundaries."
*
* (b) (1) (A) (1) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 20.5, Page 284
* states that "Berkeley-derived implementations ignore a received PUSH flag
* because they normally never delay the delivery of received data to the
* application".
*
* (2) Therefore, for TCP connections in any connected state, received TCP segment
* data is made available to the application receive queue as soon as it is
* enqueued to the application receive queue.
*
* (B) Thus, for TCP connections in any connected state, TCP segments are moved from
* a TCP connection's transport receive queue to its application receive queue
* whenever the transport receive queue's enqueued TCP segments are consecutively
* sequenced starting from the TCP connection's next expected receive octet.
*
* (2) Thus, TCP application-receive PUSH feature is obsoleted & NOT implemented.
*
* See also 'NetTCP_TxConnAck() Note #4a4'.
*
* (4) A TCP connection's next expected receive sequence numbers are NOT updated until
* both of the TCP connection's transport & application receive queues have been
* handled. Thus, the transmission of any TCP connection data or acknowledgements
* MUST follow the handling of BOTH of the TCP connection's receive queues.
*
* See also Note #1a3 & 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #5c'.
*
* (5) Stream-type connections receive all data octets in one or more non-distinct
* packets. In other words, the application data is NOT bounded by any specific
* packet(s); rather, it is contiguous & sequenced from one packet to the next.
*
* Therefore, the TCP connection receive queue is signaled ONLY when data is received
* for a connection where data was previously unavailable.
*$PAGE*
* (6) (a) RFC #793, Section 3.7 'Data Communication : Managing the Window' states that
* "the window sent in each segment indicates the range of sequence numbers the
* sender of the window (the data receiver) is currently prepared to accept.
* There is an assumption that this is related to the currently available data
* buffer space available for this connection".
*
* (b) (1) A TCP connection's advertised receive window MUST NEVER be decreased to zero
* if NO receive data is available & ready to be read by the application layer.
*
* In other words, if NO received data starting from the next expected receive
* sequence number(s) is queued, then NO data is available to be read by the
* application layer. Therefore, the receive window size MUST NOT be decreased
* to zero, otherwise the receive window would deadlock since the application
* layer would NOT be able to read & extract any data from the receive window
* & the TCP connection would NOT be able to receive any more data into the
* receive window.
*
* (2) (A) In case the advertised receive window size has decreased to zero, ...
* (B) & NO data is available to be read by the application layer; ...
* (C) then remove & free the last received TCP segment from the tail
* of the TCP connection's transport receive queue, ...
* (D) & increase the advertised receive window size by this freed
* segment's length.
*
* This is permissible because removing the last received TCP segment from
* the TCP connection's transport receive queue does NOT interfere with TCP
* communications since the next expected receive sequence number(s) remains
* unchanged.
*
* (3) (A) A TCP connection's receive window SHOULD NOT become deadlocked during
* correct operation of TCP communication. However, these TCP receive
* zero-sized window cases are included as an extra precaution in the
* case that TCP communication is incorrectly handled &/or corrupted.
*
* (B) A deadlocked TCP connection with a receive window of zero-size with
* absolutely NO buffers queued in the TCP connection's transport receive
* queue SHOULD NEVER occur. However, the TCP receive window size reset
* case is included as an extra precaution in the case that a TCP connection
* receive window is incorrectly handled &/or corrupted.
*
* See also 'NetTCP_RxConnWinSizeHandler() Note #2a1'.
*********************************************************************************************************
*/
static void NetTCP_RxPktConnHandlerRxQ_AppData (NET_TCP_CONN *pconn,
NET_ERR *perr)
{
NET_BUF *pbuf;
NET_BUF *pbuf_head;
NET_BUF *pbuf_tail;
NET_BUF *pbuf_q_head;
NET_BUF *pbuf_q_tail;
NET_BUF_HDR *pbuf_hdr;
NET_BUF_HDR *pbuf_hdr_head;
NET_BUF_HDR *pbuf_hdr_tail;
NET_BUF_HDR *pbuf_hdr_q_head;
NET_BUF_HDR *pbuf_hdr_q_tail;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR seq_nbr_inc;
CPU_BOOLEAN done;
/*$PAGE*/
/* ---- REMOVE RX'D SEG(S) FROM TRANSPORT RX Q ---- */
switch (pconn->RxQ_State) { /* Cfg starting seq nbr. */
case NET_TCP_RX_Q_STATE_CONN_SYNC:
if (pconn->RxQ_Transport_Head == (NET_BUF *)0) { /* If sync seg NOT q'd with rx'd data, ... */
seq_nbr = pconn->RxSeqNbrNext; /* ... start rx seq move from next rx seq. */
} else { /* Else sync seg possibly q'd with rx'd data. */
pbuf_q_head = (NET_BUF *) pconn->RxQ_Transport_Head;
pbuf_hdr_q_head = (NET_BUF_HDR *)&pbuf_q_head->Hdr;
/* If sync seg q'd, ... */
seq_nbr = (pbuf_hdr_q_head->TCP_SegSync == DEF_YES)
? pconn->RxSeqNbrSync /* ... start rx seq move from sync rx seq; ... */
: pconn->RxSeqNbrNext; /* ... else start rx seq move from next rx seq. */
}
pconn->RxQ_State = NET_TCP_RX_Q_STATE_CONN;
break;
case NET_TCP_RX_Q_STATE_CONN:
case NET_TCP_RX_Q_STATE_CONN_CLOSING:
seq_nbr = pconn->RxSeqNbrNext;
break;
case NET_TCP_RX_Q_STATE_CONN_CLOSED:
*perr = NET_TCP_ERR_NONE;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_RX_Q_STATE_NONE:
case NET_TCP_RX_Q_STATE_CLOSED:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
pbuf = (NET_BUF *)pconn->RxQ_Transport_Head;
pbuf_head = (NET_BUF *)pbuf;
pbuf_tail = (NET_BUF *)0;
done = DEF_NO;
while (done == DEF_NO) { /* Srch for ALL segs with consecutive seq nbrs ... */
/* ... from next expected rx seq. */
if (pbuf != (NET_BUF *)0) {
pbuf_hdr = (NET_BUF_HDR *)&pbuf->Hdr;
if (pbuf_hdr->TCP_SeqNbr == seq_nbr) { /* If seq consecutive from next expected rx seq, .. */
seq_nbr_inc = (NET_TCP_SEQ_NBR)pbuf_hdr->TCP_SegLen;
seq_nbr += (NET_TCP_SEQ_NBR)seq_nbr_inc; /* .. update next expected rx seq. */
pbuf_tail = (NET_BUF *)pbuf;
pbuf = (NET_BUF *)pbuf_hdr->NextPrimListPtr;
} else {
done = DEF_YES;
}
} else {
done = DEF_YES;
}
}
/* -------- UPDATE TCP CONN TRANSPORT RX Q -------- */
if (pbuf != (NET_BUF *)0) { /* If transport rx Q NOT empty, update .. */
/* .. transport rx Q head. */
pbuf_hdr->PrevPrimListPtr = (void *)0;
pconn->RxQ_Transport_Head = (NET_BUF *)pbuf;
} else { /* Else clr transport rx Q. */
pconn->RxQ_Transport_Head = (NET_BUF *)0;
pconn->RxQ_Transport_Tail = (NET_BUF *)0;
}
pconn->RxSeqNbrNext = seq_nbr; /* Update next expected rx seq. */
if (pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSING) {
if (pconn->RxSeqNbrNext == pconn->RxSeqNbrLast) { /* If last seq rx'd, close TCP conn rx. */
pconn->RxQ_State = NET_TCP_RX_Q_STATE_CONN_CLOSED;
}
}
/*$PAGE*/
/* -------- MOVE RX'D SEG(S) ONTO APP RX Q -------- */
if (pbuf_tail != (NET_BUF *)0) { /* If avail, move rx'd seg(s) from transport rx Q */
/* ... onto app rx Q (see Note #3b1B). */
pbuf_hdr_head = (NET_BUF_HDR *)&pbuf_head->Hdr;
pbuf_hdr_tail = (NET_BUF_HDR *)&pbuf_tail->Hdr;
pbuf_hdr_head->PrevPrimListPtr = (void *) pconn->RxQ_App_Tail;
pbuf_hdr_tail->NextPrimListPtr = (void *) 0;
if (pconn->RxQ_App_Tail != (NET_BUF *)0) { /* If app rx Q NOT empty, ... */
/* ... append seg(s) @ Q tail (see Note #2b). */
pbuf_q_tail = (NET_BUF *) pconn->RxQ_App_Tail;
pbuf_hdr_q_tail = (NET_BUF_HDR *)&pbuf_q_tail->Hdr;
pbuf_hdr_q_tail->NextPrimListPtr = (void *) pbuf_head;
pconn->RxQ_App_Tail = (NET_BUF *) pbuf_tail;
} else { /* Else add seg(s) to empty app rx Q ... */
pconn->RxQ_App_Head = (NET_BUF *) pbuf_head;
pconn->RxQ_App_Tail = (NET_BUF *) pbuf_tail;
NetOS_TCP_RxQ_Signal(pconn->ID, perr); /* ... & signal non-empty app rx Q (see Note #5). */
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
} else { /* --------------- CHK RX WIN SIZE ---------------- */
if (pconn->RxWinSizeActual < 1) { /* If avail rx win size zero (see Note #6b2A) ... */
if (pconn->RxQ_App_Head == (NET_BUF *)0) { /* ... & NO avail app rx data (see Note #6b2B); ... */
/* ... inc rx win size (see Note #6b). */
pbuf = pconn->RxQ_Transport_Tail;
if (pbuf != (NET_BUF *)0) { /* If transport rx Q NOT empty; ... */
/* ... remove last q'd seg (see Note #6b2C), ... */
pbuf_hdr = (NET_BUF_HDR *)&pbuf->Hdr;
pbuf_q_tail = (NET_BUF *) pbuf_hdr->PrevPrimListPtr;
if (pbuf_q_tail != (NET_BUF *)0) {
pconn->RxQ_Transport_Tail = (NET_BUF *) pbuf_q_tail;
pbuf_hdr_q_tail = (NET_BUF_HDR *)&pbuf_q_tail->Hdr;
pbuf_hdr_q_tail->NextPrimListPtr = (void *) 0;
} else {
pconn->RxQ_Transport_Head = (NET_BUF *) 0;
pconn->RxQ_Transport_Tail = (NET_BUF *) 0;
NetOS_TCP_RxQ_Clr(pconn->ID, perr);
if (*perr != NET_TCP_ERR_NONE) {
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
return;
}
}
/* ... inc win size by seg's len (see Note #6b2D), */
NetTCP_RxConnWinSizeHandler((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_WIN_SIZE)pbuf_hdr->TCP_SegLenData,
(NET_TCP_WIN_CODE)NET_TCP_CONN_RX_WIN_SET);
NetTCP_RxPktFree(pbuf); /* ... & free seg (see Note #6b2C). */
} else { /* Else reset TCP conn rx win size (see Note #6b3B).*/
NetTCP_RxConnWinSizeHandler((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_WIN_SIZE)0,
(NET_TCP_WIN_CODE)NET_TCP_CONN_RX_WIN_RESET);
}
}
}
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerTxWinRemote()
*
* Description : Handle TCP connection's transmit remote host window update.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* ack_code Indicates the received segment's acknowledgement condition :
* --------
* NET_TCP_CONN_RX_ACK_VALID Received acknowledgement number is
* valid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_DUP Received acknowledgement number is a
* duplicate for the TCP
* connection.
*
* NET_TCP_CONN_RX_ACK_PREV Received acknowledgement number is a
* previous duplicate for the TCP
* connection.
*
* Argument validated in NetTCP_RxPktConnHandler() functions.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection's transmit remote host
* window successfully handled.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg().
*$PAGE*
* Note(s) : (1) (a) (1) The following sections ... :
*
* (A) RFC #1122, Section 4.2.2.20.(c)
* (B) RFC #1122, Section 4.2.2.20.(f)
*
* (2) ... generalize that "when the connection enters ESTABLISHED STATE, the following
* variables should be set" :
*
* (A) SND.WND <- SEG.WND
* (B) SND.WL1 <- SEG.SEQ
* (C) SND.WL2 <- SEG.ACK
*
* (b) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* ESTABLISHED STATE' generalizes ...
*
* (A) ... that for the following connected states ... :
*
* (1) ESTABLISHED
* (2) FIN-WAIT-1
* (3) CLOSING
* (4) CLOSE-WAIT
* (5) LAST-ACK
* (a) See 'NetTCP_RxPktConnHandlerLastAck() Notes #2d2B'.
*
* (B) ... that "if SND.UNA < SEG.ACK <= SND.NXT, the send window should be updated" :
*
* (1) If ...
*
* (a) ((SND.WL1 < SEG.SEQ) or
* (b) ((SND.WL1 == SEG.SEQ) and
* (c) (SND.WL2 <= SEG.ACK)) ...
*
* (2) ... [then] set ...
*
* (a) SND.WND <- SEG.WND
* (b) SND.WL1 <- SEG.SEQ
* (c) SND.WL2 <- SEG.ACK
*
* (2) (A) RFC #1122, Section 4.2.2.20.(g) amends the transmit window update criteria
* for the segment's acknowledgement to include SND.UNA : "The window should
* updated if SND.UNA <= SEG.ACK <= SND.NXT."
*
* This permits received segments that exactly acknowledge the TCP connection's
* last acknowledged transmit sequence octet to update the transmit window in
* case the remote host's receive window size is increasing or decreasing.
*
* (B) However, it does NOT seem reasonable to update a TCP connection's remote
* transmit window for any received duplicate acknowledgement segment ; i.e.
* an acknowledgement with the exact same sequence numbers & receive window
* size advertisement. Otherwise, each received duplicate acknowledgement
* would incorrectly update the TCP connection's remote transmit window size.
*
* Therefore, it seems reasonable & is assumed that the transmit window MUST
* be updated for received acknowledgements that exactly acknowledge the TCP
* connection's last acknowledged transmit sequence octet, if & only if the
* received segment's receive window size advertisement has increased or
* decreased since the last received acknowledgement segment.
*
* See also RFC #1122, Section 4.2.2.16 & 'NetTCP_TxConnAck() Note #4b1B1'.
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #3'.
*$PAGE*
* (2) RFC #793 does NOT provide nor suggest any logic to determine/handle sequence number
* comparisons for sequence number windows that overflow the sequence number space.
*
* (a) (1) For example, in order to update the transmit window, a received segment's
* acknowledgement value (SEG.ACK) MUST be greater than or equal to the last
* received acknowledgement number that updated the transmit window (SND.WL2)
* [see Note #1b1B1c] :
*
* (A) SEG.ACK >= SND.WL2
*
* However, if SEG.ACK overflows the sequence number space, it will be MUCH
* less than SND.WL2 until SND.WL2 also overflows :
*
* (B) SEG.ACK << SND.WL2
*
* (2) Therefore, in order to validate a received segment's acknowledgement number
* as valid for updating the TCP connection's transmit window, the following
* unsigned arithmetic comparison MUST be true :
*
* (A) (SND.NXT - SEG.ACK) <= (SND.NXT - SND.WL2)
*
* (b) (1) Alternatively, to update the transmit window, a received segment's sequence
* number (SEG.SEQ) MUST be greater than or equal to the last received sequence
* number that updated the transmit window (SND.WL1) [see Notes #1b1B1a & #1b1B1b] :
*
* (A) SEG.SEQ >= SND.WL1
*
* (2) Therefore, in order to validate a received segment's sequence number as valid
* for updating the TCP connection's transmit window, the following unsigned
* arithmetic comparison MUST be true :
*
* (A) (RCV.NXT + RCV.WND) - SEG.SEQ < (RCV.NXT + RCV.WND) - SND.WL1
*
* See also 'NetTCP_RxPktConnIsValidAck() Note #3'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerTxWinRemote (NET_TCP_CONN *pconn,
NET_TCP_ACK_CODE ack_code,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_BOOLEAN tx_win_update;
NET_TCP_SEQ_NBR ack_delta_next;
NET_TCP_SEQ_NBR ack_delta_win_update;
NET_TCP_SEQ_NBR seq_win;
NET_TCP_SEQ_NBR seq_win_delta;
NET_TCP_SEQ_NBR seq_win_update_delta;
/* ------ VALIDATE TCP CONN TX REMOTE WIN UPDATE ------ */
tx_win_update = DEF_NO;
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* Validate TCP conn tx Q state. */
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
tx_win_update = DEF_YES; /* Update tx win ctrls (see Note #1a2). */
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* Validate TCP conn tx Q state. */
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* Chk tx win ctrls update (see Note #1b1B1). */
/* If seq = last win update seq (see Note #1b1B1b), .. */
if (pbuf_hdr->TCP_SeqNbr == pconn->TxWinUpdateSeqNbr) {
ack_delta_next = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pbuf_hdr->TCP_AckNbr);
ack_delta_win_update = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pconn->TxWinUpdateAckNbr);
if (ack_delta_next <= ack_delta_win_update) { /* .. (next - ack) <= (next - last win update ack), .. */
/* .. & rx'd ack OR win != last rx'd ack or win, .. */
/* .. update tx win (see Notes #1b1B1c, #1b2B, & #2a2A);*/
tx_win_update = ((pbuf_hdr->TCP_AckNbr != pconn->TxWinUpdateAckNbr ) ||
(pbuf_hdr->TCP_WinSize != pconn->TxWinUpdateWinSize)) ? DEF_YES : DEF_NO;
}
} else {
seq_win = (NET_TCP_SEQ_NBR)(pconn->RxSeqNbrNext + pconn->RxWinSizeActual);
seq_win_delta = (NET_TCP_SEQ_NBR)(seq_win - pbuf_hdr->TCP_SeqNbr);
seq_win_update_delta = (NET_TCP_SEQ_NBR)(seq_win - pconn->TxWinUpdateSeqNbr);
if (seq_win_delta < seq_win_update_delta) { /* .. else if [(next + win) - seq] < .. */
/* .. [(next + win) - last win update seq], .. */
tx_win_update = DEF_YES; /* .. update tx win (see Notes #1b1B1a & #2b2A). */
}
}
break;
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_CLOSED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ---------- UPDATE TCP CONN TX REMOTE WIN ----------- */
if (tx_win_update == DEF_YES) { /* Update tx win ctrls (see Notes #1a2 & #1b1B2). */
NetTCP_TxConnWinSizeHandlerCongCtrl(pconn, pbuf_hdr, ack_code, 0, NET_TCP_CONN_TX_WIN_REMOTE_UPDATE, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerReTxQ()
*
* Description : (1) Handle received valid acknowledgement segments :
*
* (a) Update TCP connection re-transmit queue :
*
* (1) Update TCP connection's unacknowledged transmit sequences See Note #2c1
* (2) Remove acknowledged TCP segments from a TCP See Note #2c2
* connection's re-transmit queue
* (3) Update TCP connection's round-trip time calculations
* (see 'NetTCP_TxConnRTT_RTO_Calc() Note #2a1')
* (4) Update TCP connection's re-transmit timeout See Note #8b
* (5) Free TCP packet buffer(s)
* (6) Start TCP connection's transmit idle timer
* (see 'NetTCP_TxConnTxQ_TimeoutIdleSet() Note #2a1')
*
* (b) Update TCP connection's transmit window(s) :
*
* (1) Increment TCP connection's configured transmit window size
* (2) Increment TCP connection's congetion control transmit window size
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandler().
*
* ack_code Indicates the received segment's acknowledgement condition :
* --------
* NET_TCP_CONN_RX_ACK_VALID Received acknowledgement number is
* valid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_DUP Received acknowledgement number is a
* duplicate for the TCP connection.
*
* Argument validated in NetTCP_RxPktConnHandler() functions.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection's re-transmit queue
* successfully handled.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* NET_TCP_ERR_CONN_ACK_INVALID Invalid received segment acknowledgement.
* NET_TCP_ERR_CONN_DATA_INVALID TCP connection re-transmit queue contains
* invalid or improperly sequenced data.
*
* -- RETURNED BY NetTCP_TxConnReTxQ_TimeoutSet() : --
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
*
* - RETURNED BY NetTCP_TxConnWinSizeHandlerCfgd() : -
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg().
*$PAGE*
* Note(s) : (2) (a) The following sections ... :
*
* (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit'
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* ESTABLISHED STATE'
*
* (b) ... generalize that for ...
*
* (1) ... the following synchronization-to-connected state transitions ... :
*
* (A) SYN-RECEIVED to ESTABLISHED
* (B) SYN-SENT to ESTABLISHED
*
* (2) ... & for the following connected states ... :
*
* (A) ESTABLISHED
* (B) FIN-WAIT-1
* (C) CLOSING
* (D) CLOSE-WAIT
* (E) LAST-ACK
* (1) See 'NetTCP_RxPktConnHandlerLastAck() Notes #2d2B'.
*
* (c) ... that ...
*
* (1) "If SND.UNA < SEG.ACK <= SND.NXT, SND.UNA should be advanced to equal SEG.ACK" :
*
* (A) SND.UNA <- SEG.ACK
*
* (2) "Any segments on the retransmission queue which are thereby entirely acknowledged
* are removed."
*
* (3) A TCP connection's re-transmit queue SHOULD be updated ONLY by valid, non-duplicate
* received acknowledgement segments.
*
* (4) Since valid received acknowledgement segments update a TCP connection's last
* unacknowledged transmit sequence number ('TxSeqNbrUnackd'), any controls &/or
* calculations based on the TCP connection's last unacknowledged transmit sequence
* number MUST use the saved/previous value of the TCP connection's last unacknowledged
* transmit sequence number ('TxSeqNbrUnackdPrev').
*
* (5) Since segments enqueued to a TCP connection's re-transmit queue have already been
* transmitted to the remote host & reported to the application layer as having been
* transmitted, any TCP connection whose re-transmit queue becomes corrupted MUST be
* closed to prevent the further transmit of corrupted data.
*
* (6) Although network packets are NOT required to ensure that network packet headers or
* data will locate on CPU word-aligned addresses; many processors may be more efficient
* & may even REQUIRE that memory transfers occur on CPU word-aligned addresses [e.g.
* processors or NICs with direct memory access (DMA) capability].
*
* Therefore, to ensure appropriate CPU word alignment; any segment in a TCP connection's
* re-transmit queue whose transmit sequences are partially acknowledged MUST acknowledge
* an exact number of sequences such that the remaining sequences are aligned on a CPU
* word-aligned address.
*
* (a) Since RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check
* Sequence Number' states that in the "SYN-RECEIVED, ESTABLISHED STATE,
* FIN-WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSE-WAIT STATE, CLOSING STATE,
* LAST-ACK STATE, TIME-WAIT STATE" that "if a segment's contents straddle
* the boundary between old and new, only the new parts should be processed";
* any data segments partially acknowledged in a TCP connections' re-transmit
* queue may be re-transmitted in full or in part since the retransmission of
* previously received data is not processed.
*$PAGE*
* (7) (a) RFC #1122, Section 4.2.3.5 states that "excessive retransmission of the same
* segment by TCP indicates some failure of the remote host or the Internet path
* ... When the number of transmissions of the same segment reaches a threshold
* ... close the connection."
*
* (b) However, any segment in a TCP connection's re-transmit queue whose transmit
* sequences are partially acknowledged SHOULD NOT be considered the same segment
* for purposes of excessive retransmission.
*
* Therefore, it seems reasonable that whenever a TCP connection's re-transmit
* queue segment's transmit sequences are partially acknowledged; that segment's
* re-transmit counter should be reset.
*
* See also 'NetTCP_TxConnReTxQ() Note #3'.
*
* (8) (a) (1) (A) RFC #793, Section 3.7 'Data Communication : Retransmission Timeout' states
* that "the Round Trip Time (RTT) ... [is] the elapsed time between" :
*
* (1) "sending a data octet with a particular sequence number and" ...
* (2) "receiving an acknowledgment that covers that sequence number" ...
* (3) "(segments sent do not have to match segments received)".
*
* (B) (1) RFC #2988, Section 3 adds that :
*
* (a) "Traditionally, TCP implementations have taken one RTT measurement at
* a time (typically once per RTT)."
*
* (2) RFC #2988, Section 1 states that "in some situations it may be beneficial
* for a TCP sender to be more conservative than the algorithms detailed in
* this document allow. However, a TCP MUST NOT be more aggressive than the
* ... algorithms allow".
*
* See also 'NetTCP_TxConnRTT_RTO_Calc() Note #2a2'.
*
* (2) RFC #2988, Section 3 states that "TCP MUST use Karn's algorithm ... for taking
* RTT samples. That is, RTT samples MUST NOT be made using segments that were
* retransmitted (and thus for which it is ambiguous whether the reply was for
* the first instance of the packet or a later instance)".
*
* (A) (1) To determine if any segment(s) from a TCP connection's re-transmit queue
* have been re-transmitted (i.e. transmitted more than once), the TCP
* connection's transmit unacknowledged & un-re-transmitted sequence numbers
* are compared :
*
* (a) If NO sequences in the TCP connection's re-transmit queue have been
* re-transmitted, the TCP connection's transmit unacknowledged &
* un-re-transmitted sequence numbers will be equal.
*
* (b) If ANY sequences in the TCP connection's re-transmit queue have been
* re-transmitted, the TCP connection's transmit unacknowledged
* sequence number will be less than the un-re-transmitted sequence
* number.
*
* (2) If a received acknowledgement fully acknowledges ALL re-transmitted
* segment(s) from a TCP connection's re-transmit queue, the TCP connection
* advances its un-re-transmitted sequence number to the received segment's
* acknowledgement sequence number.
*
* (B) Although RTT measurements could be calculated for ALL transmitted segments;
* to simplify implementation of Karn's algorithm :
*
* (1) Only a single RTT measurement is calculated, ... See Note #8a1B1a
* (2) (a) per TCP acknowledgement received ... See Note #8a1A2
* AND
* (b) the segment at the head of a TCP connection's
* re-transmit queue. See Note #8a1A1
*
* See also 'NetTCP_TxConnReTxQ() Note #4'.
*
* (b) RFC #2988, Section 5 states that "the following is the RECOMMENDED algorithm for
* managing the retransmission timer" :
*
* (2) "When all outstanding data has been acknowledged, turn off the retransmission
* timer."
*
* (3) "When an ACK is received that acknowledges new data, restart the retransmission
* timer so that it will expire after RTO seconds (for the current value of RTO)."
*
* See also 'NetTCP_TxConnReTxQ() Note #2b1A'.
*$PAGE*
* (9) RFC #793 does NOT provide nor suggest any logic to determine/handle sequence number
* comparisons for sequence number windows that overflow the sequence number space.
*
* (a) For example, the next sequence octet to transmit (SND.NXT) is typically greater
* than or equal to any received segment's acknowledgement number (SEG.ACK) :
*
* (1) SND.NXT >= SEG.ACK
*
* However, if SND.NXT overflows the sequence number space, it will be MUCH less
* than SEG.ACK until SEG.ACK also overflows :
*
* (2) SND.NXT << SEG.ACK
*
* (b) (1) Therefore, in order to determine if a received segment's acknowledgement value
* fully acknowledges previously transmitted segment(s) in the TCP connection's
* re-transmit queue, the following unsigned arithmetic comparison MUST be checked :
*
* (A) (SND.NXT - SEG.ACK) <= SND.NXT - (ReTxQCur.SeqNbr + ReTxQCur.SegLen)
*
* See also 'NetTCP_RxPktConnIsValidAck() Note #3a2'.
*
* (2) In order to determine if a received segment's acknowledgement partially
* acknowledges a previously received segment in the TCP connection's re-
* transmit queue, the following unsigned arithmetic comparison MUST be checked :
*
* (A) (ReTxQCur.SeqNbr + ReTxQCur.SegLen) - SEG.ACK < ReTxQCur.SegLen
*
* See also 'NetTCP_RxPktConnHandlerRxQ_Conn() Note #4c2'.
*
* (3) In order to determine if a received segment's acknowledgement should
* advance the TCP connection's un-re-transmitted sequence number(s), the
* following unsigned arithmetic comparison MUST be true :
*
* (A) (SEG.ACK - ReTxQ.UnReTxdSeqNbr) <= (SND.NXT - ReTxQ.UnReTxdSeqNbr)
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerReTxQ (NET_TCP_CONN *pconn,
NET_TCP_ACK_CODE ack_code,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_SEQ_NBR seq_nbr_cur;
NET_TCP_SEQ_NBR seq_nbr_delta;
NET_TCP_SEQ_NBR seq_nbr_next_qd;
#endif
NET_TCP_SEQ_NBR ack_delta_seq;
NET_TCP_SEQ_NBR ack_delta_seq_align;
NET_TCP_SEQ_NBR ack_delta_seq_align_offset;
NET_TCP_SEQ_NBR ack_delta_unretxd;
NET_TCP_SEQ_NBR ack_delta_next;
NET_TCP_SEQ_NBR seq_delta_unretxd;
NET_TCP_SEQ_NBR seq_delta_next;
NET_TCP_SEQ_NBR seq_nbr_next;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEG_SIZE seg_len;
NET_TCP_SEG_SIZE seg_len_tot;
NET_TCP_SEG_SIZE seg_len_data;
NET_TCP_SEG_SIZE seg_len_data_tot;
NET_TCP_TX_RTT_TS_MS seg_rtt_ts_txd_ms;
NET_TCP_TX_RTT_TS_MS seg_rtt_ts_rxd_ms;
CPU_BOOLEAN segs_re_txd;
CPU_BOOLEAN seqs_ackd;
CPU_BOOLEAN done;
CPU_BOOLEAN tmr_update;
NET_BUF *pbuf_q;
NET_BUF *pbuf_q_head;
NET_BUF *pbuf_q_prev;
NET_BUF *pbuf_q_next;
NET_BUF_HDR *pbuf_q_hdr;
NET_BUF_HDR *pbuf_q_head_hdr;
NET_BUF_HDR *pbuf_q_prev_hdr;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE TCP CONN ----------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
break;
case NET_TCP_CONN_RX_ACK_NONE:
case NET_TCP_CONN_RX_ACK_INVALID:
case NET_TCP_CONN_RX_ACK_DUP:
case NET_TCP_CONN_RX_ACK_PREV:
default:
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
case NET_TCP_CONN_RX_ACK_DUP:
break;
case NET_TCP_CONN_RX_ACK_NONE:
case NET_TCP_CONN_RX_ACK_INVALID:
case NET_TCP_CONN_RX_ACK_PREV:
default:
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_CLOSED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/*$PAGE*/
/* ------------- UPDATE UNACK'D TX SEQ(S) ------------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
seq_nbr_cur = (NET_TCP_SEQ_NBR)pconn->TxSeqNbrUnAckd;
seq_nbr_delta = (NET_TCP_SEQ_NBR)pconn->TxSeqNbrUnAckdAlignDelta;
#endif
/* Save prev tx unack'd seq nbr (see Note #4). */
pconn->TxSeqNbrUnAckdPrev = (NET_TCP_SEQ_NBR)pconn->TxSeqNbrUnAckd;
/* Ack prev'ly unack'd tx segs (see Note #2c1). */
pconn->TxSeqNbrUnAckd = (NET_TCP_SEQ_NBR)pbuf_hdr->TCP_AckNbr;
if (pconn->TxQ_State == NET_TCP_TX_Q_STATE_CONN_CLOSING) {
if (pconn->TxSeqNbrUnAckd == pconn->TxSeqNbrLast) { /* If last tx'd seq ack'd, close TCP conn tx. */
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN_CLOSED;
}
}
/* --------- REMOVE ACK'D SEG(S) FROM RE-TX Q --------- */
if (ack_code != NET_TCP_CONN_RX_ACK_VALID) { /* If ack NOT valid, non-dup ack; ... */
*perr = NET_TCP_ERR_NONE; /* ... do NOT update re-tx Q (see Note #3). */
return;
}
pbuf_q_head = (NET_BUF *)pconn->ReTxQ_Head;
pbuf_q_prev = (NET_BUF *)0;
pbuf_q = (NET_BUF *)pbuf_q_head;
seg_len_tot = 0;
seg_len_data_tot = 0;
/* Chk re-tx'd seg(s) [see Notes #8a2A1 & #4]. */
segs_re_txd = (pconn->TxSeqNbrUnAckdPrev == pconn->TxSeqNbrUnReTxd)
? DEF_NO : DEF_YES;
seqs_ackd = DEF_NO;
done = DEF_NO;
while ((pbuf_q != (NET_BUF *)0) && /* While NOT @ re-tx Q tail, ... */
(done == DEF_NO)) { /* ... srch for ack'd tx segs to remove (see Note #2c2).*/
pbuf_q_hdr = (NET_BUF_HDR *)&pbuf_q->Hdr;
pbuf_q_next = (NET_BUF *) pbuf_q_hdr->NextPrimListPtr;
seq_nbr = (NET_TCP_SEQ_NBR ) pbuf_q_hdr->TCP_SeqNbr;
seg_len = (NET_TCP_SEG_SIZE) pbuf_q_hdr->TCP_SegLen;
seg_len_data = (NET_TCP_SEG_SIZE) seg_len;
if (pbuf_q_hdr->TCP_SegSync == DEF_YES) { /* If sync seg ... */
if (seg_len_data >= NET_TCP_SEG_LEN_SYNC) { /* ... & seg len >= sync seg len, ... */
seg_len_data -= NET_TCP_SEG_LEN_SYNC; /* ... dec data seg len by sync seg len. */
}
}
if (pbuf_q_hdr->TCP_SegClose == DEF_YES) { /* If close seg ... */
if (seg_len_data >= NET_TCP_SEG_LEN_CLOSE) { /* ... & seg len >= close seg len, ... */
seg_len_data -= NET_TCP_SEG_LEN_CLOSE; /* ... dec data seg len by close seg len. */
}
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
seq_nbr_next_qd = seq_nbr + pconn->TxSeqNbrUnAckdAlignDelta;
if (seq_nbr_cur != seq_nbr_next_qd) { /* If next q'd seg's seq nbr NOT consecutive, ... */
/* ... close TCP conn (see Note #5). */
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_DATA_INVALID;
return;
}
#endif
/* Chk if rx'd seg acks cur re-tx Q seg. */
ack_delta_next = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pbuf_hdr->TCP_AckNbr);
seq_nbr_next = (NET_TCP_SEQ_NBR)(seq_nbr + seg_len);
seq_delta_next = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - seq_nbr_next);
if (ack_delta_next <= seq_delta_next) { /* If seg fully acks cur re-tx Q seg (see Note #9b1A), */
pbuf_q_prev = pbuf_q;
pbuf_q = pbuf_q_next; /* ... adv to next re-tx Q seg. */
pconn->TxSeqNbrUnAckdAlignDelta = 0;
seg_len_tot += seg_len;
seg_len_data_tot += seg_len_data;
seqs_ackd = DEF_YES;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
seq_nbr_cur += (NET_TCP_SEQ_NBR)(seg_len - seq_nbr_delta);
seq_nbr_delta = (NET_TCP_SEQ_NBR) 0;
#endif
/*$PAGE*/
} else { /* Else chk partial re-tx Q seg ack (see Note #9b2A) : */
ack_delta_seq = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_AckNbr - seq_nbr);
if (ack_delta_seq == 0) { /* If NO seqs ack'd for cur re-tx Q seg, ... */
; /* ... do NOT update seg. */
} else if (ack_delta_seq < seg_len) { /* If SOME seqs ack'd for cur re-tx Q seg, ... */
/* Align partial ack to word boundary (see Note #6). */
ack_delta_seq_align_offset = (NET_TCP_SEQ_NBR )(ack_delta_seq % sizeof(CPU_ALIGN));
ack_delta_seq_align = (NET_TCP_SEQ_NBR )(ack_delta_seq - ack_delta_seq_align_offset);
pconn->TxSeqNbrUnAckdAlignDelta = (NET_TCP_SEQ_NBR ) ack_delta_seq_align_offset;
/* ... update cur seg's seq nbr & seg len ... */
pbuf_q_hdr->TCP_SeqNbr += (CPU_INT32U ) ack_delta_seq_align;
pbuf_q_hdr->TCP_SegLen -= (CPU_INT16U ) ack_delta_seq_align;
pbuf_q_hdr->TCP_SegLenData -= (CPU_INT16U ) ack_delta_seq_align;
seg_len_tot += (NET_TCP_SEG_SIZE) ack_delta_seq_align;
seg_len_data_tot += (NET_TCP_SEG_SIZE) ack_delta_seq_align;
/* ... & update TCP tx buf ctrls. */
pbuf_q_hdr->DataIx += (CPU_INT16U ) ack_delta_seq_align;
pbuf_q_hdr->DataLen -= (NET_BUF_SIZE ) ack_delta_seq_align;
pbuf_q_hdr->TotLen -= (NET_BUF_SIZE ) ack_delta_seq_align;
pbuf_q_hdr->TCP_SegReTxCtr = 0; /* Reset re-tx ctr (see Note #7b). */
seqs_ackd = DEF_YES;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
} else { /* Else fully-ack'd-seg chk failed?; close TCP conn? */
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
*perr = NET_TCP_ERR_CONN_DATA_INVALID;
return;
#endif
}
done = DEF_YES;
}
}
/* --------------- UPDATE TCP CONN RTO ---------------- */
if (seqs_ackd == DEF_YES) { /* If ANY re-tx Q seq(s) ack'd .. */
if (segs_re_txd == DEF_NO) { /* .. & NO re-tx Q seg(s) re-tx'd (see Note #8a2); .. */
/* .. get tx'd seg RTT ts (see Note #8a1A1) .. */
pbuf_q_head_hdr = (NET_BUF_HDR *)&pbuf_q_head->Hdr;
seg_rtt_ts_txd_ms = (NET_TCP_TX_RTT_TS_MS) pbuf_q_head_hdr->TCP_RTT_TS_Txd_ms;
/* .. get rx'd ack RTT ts (see Note #8a1A2) .. */
seg_rtt_ts_rxd_ms = (NET_TCP_TX_RTT_TS_MS) pbuf_hdr->TCP_RTT_TS_Rxd_ms;
/* .. & calc/update RTT/RTO (see Note #1a3). */
NetTCP_TxConnRTT_RTO_Calc(pconn, NET_TCP_CONN_TX_RTT_CALC, seg_rtt_ts_txd_ms, seg_rtt_ts_rxd_ms);
}
ack_delta_unretxd = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_AckNbr - pconn->TxSeqNbrUnReTxd);
seq_delta_unretxd = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pconn->TxSeqNbrUnReTxd);
if (ack_delta_unretxd <= seq_delta_unretxd) { /* If (ack - un-re-tx'd) < (next - un-re-tx'd), ... */
/* ... acks ALL re-tx'd seg(s) [see Note #9b3A]; */
pconn->TxSeqNbrUnReTxd = pbuf_hdr->TCP_AckNbr; /* ... adv un-re-tx'd seq(s) to ack (see Note #8a2A2).*/
}
}
/*$PAGE*/
/* ------------- UPDATE TCP CONN RE-TX Q -------------- */
tmr_update = seqs_ackd; /* Update re-tx Q tmr if ANY re-tx Q seqs ack'd ... */
/* ... (see Note #8b3). */
if (pbuf_q != pbuf_q_head) { /* If ANY re-tx Q segs fully ack'd, update re-tx Q. */
if (pbuf_q != (NET_BUF *)0) { /* If re-tx Q still NOT empty, . .. */
pbuf_q_prev_hdr = (NET_BUF_HDR *)&pbuf_q_prev->Hdr;
pbuf_q_prev_hdr->NextPrimListPtr = (void *) 0;
/* ... update re-tx Q head. */
pconn->ReTxQ_Head = (NET_BUF *) pbuf_q;
pbuf_q_hdr->PrevPrimListPtr = (void *) 0;
} else { /* Else clr re-tx Q. */
pconn->ReTxQ_Head = (NET_BUF *)0;
pconn->ReTxQ_Tail = (NET_BUF *)0;
if (pconn->ReTxQ_Tmr != (NET_TMR *)0) { /* Free re-tx Q tmr (see Note #8b2). */
NetTmr_Free(pconn->ReTxQ_Tmr);
}
pconn->ReTxQ_Tmr = (NET_TMR *)0;
tmr_update = DEF_NO;
NetTCP_TxConnTxQ_TimeoutIdleSet(pconn); /* Start tx Q idle tmr (see Note #1a6). */
}
NetTCP_TxPktFree(pbuf_q_head); /* Free ALL fully ack'd seg pkt buf(s). */
}
if (tmr_update == DEF_YES) { /* Update re-tx Q tmr. */
NetTCP_TxConnReTxQ_TimeoutSet(pconn, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
/* ----------- UPDATE TCP CONN TX WIN SIZES ----------- */
/* Inc TCP conn's tx win sizes (see Note #1b). */
NetTCP_TxConnWinSizeHandlerCfgd((NET_TCP_CONN *)pconn,
(NET_TCP_WIN_SIZE)seg_len_data_tot,
(NET_TCP_WIN_CODE)NET_TCP_CONN_TX_WIN_INC,
(NET_ERR *)perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
NetTCP_TxConnWinSizeHandlerCongCtrl((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_ACK_CODE)NET_TCP_CONN_RX_ACK_NONE,
(NET_TCP_WIN_SIZE)seg_len_data_tot,
(NET_TCP_WIN_CODE)NET_TCP_CONN_TX_WIN_INC,
(NET_ERR *)perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerListenQ_IsAvail()
*
* Description : Check if application layer listen queue is available to queue a new connection.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandlerListen().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Application layer listen queue successfully
* checked; check return value for listen
* queue availablity.
*
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_ID Invalid application connection.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
*
* ---- RETURNED BY NetConn_ID_AppGet() : ----
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* Return(s) : DEF_YES, if application connection's listen queue is available to queue a new connection.
*
* DEF_NO, otherwise.
*
* Caller(s) : NetTCP_RxPktConnHandlerListen().
*
* Note(s) : (1) (a) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 18.11, Pages 257-258 states
* that :
*
* (1) "Each listening end point has a fixed length queue of connections that have been
* accepted by TCP (i.e., the three-way handshake is complete), but not yet accepted
* by the application."
*
* (2) "The application specifies a limit to this queue, commonly called the backlog" :
*
* (A) "This backlog must be between 0 and 5, inclusive."
* (B) "(Most applications specify the maximum value of 5.)"
*
* (3) "When a connection request arrives (i.e., the SYN segment), ... the current number
* of connections already queued for this listening end point [is checked] to see
* whether to accept the connection or not."
*
* (4) "If there is room on this listening end point's queue for this new connection, ...
* the TCP module ACKs the SYN and completes the connection."
*
* (5) "If there is not room on the queue for the new connection" ... :
*
* (A) "TCP just ignores the received SYN."
* (B) "Nothing is sent back (i.e., no RST segment)."
*
* (b) (A) Wright/Stevens, TCP/IP Illustrated, Volume 2, 3rd Printing, Section 15.9, Page 455
* reiterates that :
*
* (2) A "listen ... socket ... specifies a limit on the number of connections that can
* be queued on the socket," ...
*
* (5) "after which the socket layer refuses to queue additional connection requests.
* When this occurs, TCP ignores incoming connection requests."
*
* (B) Wright/Stevens, TCP/IP Illustrated, Volume 2, 3rd Printing, Section 28.2, Page 930
* also states that :
*
* (5) (A) "By silently dropping the segment" ...
* (B) "and not replying with an RST," ...
* (C) "The client's connection request should time out, causing the client to
* retransmit the SYN."
*
* (C) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 18.11, Pages 259-260
* summarizes that :
*
* (5) (A) "TCP ignores the incoming SYN when the queue is full," ...
* (B) "and doesn't respond with an RST," ...
*
* (C) (1) "because ... this condition could change in a short while ... [and] by
* ignoring the SYN, the server forces the client TCP to re-transmit the
* SYN later, hoping that the queue will then have room for the new
* connection".
*
* (2) Whereas page 259-260 counters that "if the server's TCP responded with
* a reset, the client's active open would abort".
*
* See also 'net_sock.c NetSock_ListenQ_IsAvail() Note #2'.
*
* (2) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
* since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
* is configured with an appropriate family type value (see 'net_conn.h CONFIGURATION ERRORS').
* The 'else'-conditional code is included for completeness & as an extra precaution in case
* 'net_conn.h' is incorrectly modified.
*********************************************************************************************************
*/
/*$PAGE*/
static CPU_BOOLEAN NetTCP_RxPktConnHandlerListenQ_IsAvail (NET_TCP_CONN *pconn,
NET_ERR *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_app;
CPU_BOOLEAN q_avail;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------- VALIDATE TCP CONN STATE -------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (DEF_NO); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN:
break;
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return (DEF_NO); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (DEF_NO); /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
conn_id = pconn->ID_Conn;
conn_id_app = NetConn_ID_AppGet(conn_id, perr); /* Get TCP listen conn's app conn id. */
if (*perr != NET_CONN_ERR_NONE) {
return (DEF_NO);
}
if (conn_id_app == NET_CONN_ID_NONE) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return (DEF_NO);
}
/* -------------- CHK APP LISTEN Q AVAIL -------------- */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
q_avail = NetSock_ListenQ_IsAvail((NET_SOCK_ID) conn_id_app,
(NET_ERR *)&err);
#else /* See Note #2. */
(void)&q_avail; /* Prevent compiler warnings. */
(void)&err;
*perr = NET_CONN_ERR_INVALID_FAMILY;
return (DEF_NO);
#endif
*perr = NET_TCP_ERR_NONE;
return (q_avail);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerSignalConn()
*
* Description : (1) Signal application layer that TCP/transport layer connection's state is now connected :
*
* (a) From passive SYN-RECEIVED state, signal application layer that
* connection request received; connection accept now available.
*
* (b) From active SYN-RECEIVED or SYN-SENT states, signal application layer that
* connection request complete.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandlerSyncRxd(),
* NetTCP_RxPktConnHandlerSyncTxd().
*
* state Current TCP connection state.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Application layer successfully signaled.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAIL Application layer signal failed.
* NET_TCP_ERR_INVALID_CONN_ID Invalid application connection.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
*
* --- RETURNED BY NetConn_ID_AppGet() : ----
* - RETURNED BY NetConn_ID_AppCloneGet() : -
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSyncRxd(),
* NetTCP_RxPktConnHandlerSyncTxd().
*
* Note(s) : (2) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
* since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
* is configured with an appropriate family type value (see 'net_conn.h CONFIGURATION ERRORS').
* The 'else'-conditional code is included for completeness & as an extra precaution in case
* 'net_conn.h' is incorrectly modified.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerSignalConn (NET_TCP_CONN *pconn,
NET_TCP_CONN_STATE state,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_app;
NET_ERR err;
CPU_BOOLEAN err_conn;
conn_id = pconn->ID_Conn;
/* ------------------- SIGNAL CONN -------------------- */
switch (state) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE: /* See Note #1a. */
/* Get app conn id clone. */
conn_id_app = NetConn_ID_AppCloneGet(conn_id, perr);
if (*perr != NET_CONN_ERR_NONE) {
return;
}
if (conn_id_app == NET_CONN_ID_NONE) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
/* Signal app conn accept. */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
NetSock_ConnSignalAccept((NET_SOCK_ID) conn_id_app,
(NET_CONN_ID) conn_id,
(NET_ERR *)&err);
*perr = (err != NET_SOCK_ERR_NONE) ? NET_TCP_ERR_CONN_FAIL
: NET_TCP_ERR_NONE;
#else /* See Note #2. */
(void)&err; /* Prevent compiler warning. */
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
if (*perr != NET_TCP_ERR_NONE) {
return;
}
break;
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE: /* See Note #1b. */
case NET_TCP_CONN_STATE_SYNC_TXD:
/* Get app conn id. */
conn_id_app = NetConn_ID_AppGet(conn_id, perr);
if (*perr != NET_CONN_ERR_NONE) {
return;
}
if (conn_id_app == NET_CONN_ID_NONE) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
/* Signal app conn req. */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
NetSock_ConnSignalReq((NET_SOCK_ID) conn_id_app,
(NET_ERR *)&err);
*perr = (err != NET_SOCK_ERR_NONE) ? NET_TCP_ERR_CONN_FAIL
: NET_TCP_ERR_NONE;
#else /* See Note #2. */
(void)&err; /* Prevent compiler warning. */
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
if (*perr != NET_TCP_ERR_NONE) {
return;
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Notes #1a & #1b. */
/* Get app conn id. */
err_conn = DEF_NO;
conn_id_app = NetConn_ID_AppGet(conn_id, perr);
if (*perr != NET_CONN_ERR_NONE) {
err_conn = DEF_YES;
}
if (conn_id_app == NET_CONN_ID_NONE) {
err_conn = DEF_YES;
}
if (err_conn == DEF_YES) { /* If app conn id get failed, get app conn id clone. */
conn_id_app = NetConn_ID_AppCloneGet(conn_id, perr);
if (*perr != NET_CONN_ERR_NONE) {
return;
}
if (conn_id_app == NET_CONN_ID_NONE) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
}
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
/* Signal app conn req. */
NetSock_ConnSignalReq((NET_SOCK_ID) conn_id_app,
(NET_ERR *)&err);
*perr = (err != NET_SOCK_ERR_NONE) ? NET_TCP_ERR_CONN_FAIL
: NET_TCP_ERR_NONE;
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* Signal app conn accept. */
NetSock_ConnSignalAccept((NET_SOCK_ID) conn_id_app,
(NET_CONN_ID) conn_id,
(NET_ERR *)&err);
*perr = (err != NET_SOCK_ERR_NONE) ? NET_TCP_ERR_CONN_FAIL
: NET_TCP_ERR_NONE;
#else /* See Note #2. */
(void)&err; /* Prevent compiler warning. */
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
if (*perr != NET_TCP_ERR_NONE) {
return;
}
break;
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnHandlerSignalClose()
*
* Description : Signal application layer that TCP/transport layer connection's state is now closed.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnReqClose(),
* NetTCP_RxPktConnHandlerFinWait1(),
* NetTCP_RxPktConnHandlerClosing(),
* NetTCP_RxPktConnHandlerLastAck().
*
* data_avail Indicate whether application data is still available on the TCP connection's
* application receive queue :
*
* DEF_YES Application data is available on the
* closing TCP connection's application
* receive queue.
* DEF_NO Application data is NOT available for the
* closing TCP connection's application
* receive queue.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Application layer successfully signaled.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAIL Application layer signal failed.
* NET_TCP_ERR_INVALID_CONN_ID Invalid application connection.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_CONN_ERR_INVALID_FAMILY Invalid network connection family.
*
* -- RETURNED BY NetConn_ID_AppGet() : ---
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_CONN_ERR_INVALID_CONN Invalid network connection number.
* NET_CONN_ERR_NOT_USED Network connection NOT currently used.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnReqClose(),
* NetTCP_RxPktConnHandlerFinWait1(),
* NetTCP_RxPktConnHandlerClosing(),
* NetTCP_RxPktConnHandlerLastAck().
*
* Note(s) : (1) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* FIN-WAIT-2 STATE' states that "if the retransmission queue is empty, the user's
* CLOSE can be acknowledged".
*
* (b) However, TCP connection should signal the application layer that "the user's close
* [is] acknowledged" whenever its re-transmit queue becomes &/or is empty :
*
* (1) Transition from LISTEN to CLOSED
* (2) Transition from SYN-SENT to CLOSED
*
* (3) Transition from FIN-WAIT-1 to ... See also 'NetTCP_RxPktConnHandlerFinWait1()
* Note #2d2B2'
* (A) FIN-WAIT-2
* (B) TIME-WAIT
*
* (4) Transition from CLOSING to TIME-WAIT See also 'NetTCP_RxPktConnHandlerClosing()
* Note #2d2B2a2'
*
* (5) Transition from LAST-ACK to CLOSED
*
* (2) Once an application connection has been signaled of its close, the application connection is
* responsible for closing its remaining connection(s).
*
* See also 'NetTCP_ConnCloseHandler() Note #2b1B'.
*
* (3) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
* since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
* is configured with an appropriate family type value (see 'net_conn.h CONFIGURATION ERRORS').
* The 'else'-conditional code is included for completeness & as an extra precaution in case
* 'net_conn.h' is incorrectly modified.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_RxPktConnHandlerSignalClose (NET_TCP_CONN *pconn,
CPU_BOOLEAN data_avail,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_CONN_ID conn_id;
NET_CONN_ID conn_id_app;
NET_ERR err;
/* Get conn id's. */
conn_id = pconn->ID_Conn;
conn_id_app = NetConn_ID_AppGet(conn_id, perr);
if (*perr != NET_CONN_ERR_NONE) {
return;
}
if (conn_id_app == NET_CONN_ID_NONE) {
*perr = NET_TCP_ERR_INVALID_CONN_ID;
return;
}
/* ------------- VALIDATE TCP CONN STATE -------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #1b1. */
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #1b2. */
case NET_TCP_CONN_STATE_FIN_WAIT_1: /* See Note #1b3. */
case NET_TCP_CONN_STATE_CLOSING: /* See Note #1b4. */
case NET_TCP_CONN_STATE_LAST_ACK: /* See Note #1b5. */
break;
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_CLOSED:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ------------------- SIGNAL CLOSE ------------------- */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
/* Signal app conn close. */
NetSock_ConnSignalClose((NET_SOCK_ID) conn_id_app,
(CPU_BOOLEAN) data_avail,
(NET_ERR *)&err);
*perr = (err != NET_SOCK_ERR_NONE) ? NET_TCP_ERR_CONN_FAIL
: NET_TCP_ERR_NONE;
#else /* See Note #3. */
(void)&data_avail; /* Prevent compiler warnings. */
(void)&err;
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* Clr app close flag; ... */
pconn->ConnCloseAppFlag = DEF_NO; /* ... app closes rem'ing conn(s) [see Note #2]. */
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnIsValidSeq()
*
* Description : Validate a received segment's sequence number with current TCP connection.
*
* Argument(s) : pconn Pointer to a TCP connection.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Sequence number successfully validated;
* check return value.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* Return(s) : NET_TCP_CONN_RX_SEQ_INVALID, if received sequence number invalid for the TCP connection.
*
* NET_TCP_CONN_RX_SEQ_VALID, if received sequence number valid for the TCP connection.
*
* NET_TCP_CONN_RX_SEQ_SYNC_INVALID, if received sequence number is an invalid synchronization
* for the TCP connection.
*
* NET_TCP_CONN_RX_SEQ_SYNC, if received sequence number is a valid synchronization
* for the TCP connection.
*
* Caller(s) : various.
*
* Note(s) : (1) Validate received TCP connection sequence numbers :
*
* (A) Some TCP receive sequence number validation logic implemented in previous
* functions; include duplicate validation logic in NetTCP_RxPktConnIsValidSeq()
* only if debug/validation code is enabled (i.e. NET_ERR_CFG_ARG_CHK_DBG_EN is
* DEF_ENABLED in 'net_cfg.h').
*
* (a) RFC #793, Section 3.4 'Establishing a Connection : Reset Generation : 1' states
* that "if [a] connection [is] ... CLOSED then a reset is sent in response to any
* incoming segment". Thus, ALL received segments are invalid.
*
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State]' :
*
* (1) "If the SYN bit is set ... the connection state should be changed to SYN-
* RECEIVED ... and any other control or text should be queued for processing
* later ... Note that any other incoming control or data ... will be processed
* in the SYN-RECEIVED state."
*
* Therefore, the ONLY TCP segment data that may be queued in the LISTEN state
* MUST be received in a TCP connection request segment.
*
* (2) Otherwise "any other control or text-bearing segment (not containing SYN)
* must have an ACK and thus would be discarded by the ACK processing ...
* [so] drop the segment".
*
* (c) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit' :
*
* (1) "If ... our SYN has been ACKed ... change the connection state to
* ESTABLISHED ... [and] if there are other controls or text in the
* segment then continue processing" as for the ESTABLISHED state
* (see Note #1d).
*
* (2) "Otherwise enter SYN-RECEIVED ... [and] if there are other controls or
* text in the segment, queue them for processing after the ESTABLISHED
* state has been reached."
*
* (3) Otherwise "if neither the SYN or RST bits is set then drop the segment".
*
* Therefore, the ONLY TCP segment data that may be queued in the SYN-SENT
* state MUST be received in a TCP connection request segment.
*$PAGE*
* (d) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence
* Number' states that for the "SYN-RECEIVED STATE, ESTABLISHED STATE, FIN-
* WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK
* STATE, TIME-WAIT STATE ... there are four cases for the acceptability test
* for an incoming segment :
*
* Local
* Segment Receive
* Length Window Test
* ------- ------- -------------------------------------------------------
*
* (1) 0 0 SEG.SEQ = RCV.NXT
*
* (2) 0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT + RCV.WND
*
* (3) >0 0 not acceptable
*
* (4) >0 >0 RCV.NXT =< SEG.SEQ < RCV.NXT + RCV.WND
* or RCV.NXT =< SEG.SEQ + SEG.LEN - 1 < RCV.NXT + RCV.WND
*
*
* If the RCV.WND is zero, no segments will be acceptable, but special allowance
* should be made to accept valid ACKs ... and RSTs.
*
* If an incoming segment is not acceptable, an acknowledgment should be sent in
* reply".
*
* See also Note #2.
*
* (e) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN Bit'
* states that in the "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT STATE-1,
* FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-WAIT
* STATE ... if the SYN is in the window it is an error, send a reset, any
* outstanding RECEIVEs and SEND[s] should receive 'reset' responses, all segment
* queues should be flushed, the user should also receive an unsolicited general
* 'connection reset' signal[, and] enter the CLOSED state".
*
* (2) RFC #793 does NOT provide nor suggest any logic to determine/handle sequence number
* comparisons for sequence number windows that overflow the sequence number space.
*
* (a) For example, the next sequence octet to receive (RCV.NXT) is typically less than
* or equal to the next received sequence octet (SEG.SEQ) :
*
* (1) RCV.NXT <= SEG.SEQ
*
* SEG.SEQ itself is also typically less than RCV.NXT plus the current receive window
* size (RCV.WND) :
*
* (2) SEG.SEQ < (RCV.NXT + RCV.WND)
*
* However, if (RCV.NXT + RCV.WND) or SEG.SEQ overflows the sequence number space,
* these values will be MUCH less than SEG.SEQ or RCV.NXT, respectively, until
* SEG.SEQ & RCV.NXT also overflow :
*
* (3) RCV.NXT + RCV.WND << RCV.NXT
* << SEG.SEQ
*
* (4) SEG.SEQ << RCV.NXT
*
* (b) Therefore, in order to validate a received segment's sequence value as within the
* TCP connection's current receive window, one of the following unsigned arithmetic
* comparisons MUST be true :
*
* (1) (A) (RCV.NXT + RCV.WND) - SEG.SEQ <= (RCV.NXT + RCV.WND) - RCV.NXT
*
* (B) (RCV.NXT + RCV.WND) - SEG.SEQ <= RCV.WND
*
* (C) (RCV.NXT + RCV.WND) - SEG.SEQ - 1 < RCV.WND
*
* (D) (RCV.NXT + RCV.WND) - (SEG.SEQ + 1) < RCV.WND
*
* (a) Comparison #2b1C's left-hand side decremented by one to modify the
* conditional test from less-than-or-equal-to to just less-than in
* order to satisfy the exact boundary conditions shown in the incoming
* segment acceptability test comparisons (see Notes #1d2 & #1d4).
*
* (2) Substituting (SEG.SEQ + SEG.LEN - 1) into SEG.SEQ :
*
* (A) (RCV.NXT + RCV.WND) - (SEG.SEQ + SEG.LEN - 1 + 1) < RCV.WND
*
* (B) (RCV.NXT + RCV.WND) - (SEG.SEQ + SEG.LEN) < RCV.WND
*
* (c) In order to determine if a received segment's sequence value is within but NOT
* following a closing TCP connection's last valid receive sequence numbers, the
* following unsigned arithmetic comparison MUST be checked :
*
* (1) RX.LAST - (SEG.SEQ + SEG.LEN) <= (RX.LAST - RX.NXT)
*********************************************************************************************************
*/
/*$PAGE*/
static NET_TCP_SEQ_CODE NetTCP_RxPktConnIsValidSeq (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_ACK_CODE ack_code;
#endif
NET_TCP_SEQ_CODE seq_code;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR seq_win;
NET_TCP_SEQ_NBR seq_win_next;
NET_TCP_SEQ_NBR seq_win_delta;
*perr = NET_TCP_ERR_NONE;
seq_code = NET_TCP_CONN_RX_SEQ_INVALID;
if (pconn != (NET_TCP_CONN *)0) {
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (NET_TCP_CONN_RX_SEQ_INVALID); /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #1a. */
break;
case NET_TCP_CONN_STATE_LISTEN: /* See Note #1b. */
if (pbuf_hdr->TCP_SegSync == DEF_YES) { /* If sync rx'd, .. */
seq_code = NET_TCP_CONN_RX_SEQ_SYNC; /* .. sync's seq nbr valid (see Note #1b1). */
}
break;
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #1c. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #1A. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return (NET_TCP_CONN_RX_SEQ_INVALID);
}
if (ack_code != NET_TCP_CONN_RX_ACK_VALID) {
return (NET_TCP_CONN_RX_SEQ_INVALID);
}
#endif
if (pbuf_hdr->TCP_SegSync == DEF_YES) { /* If valid sync rx'd, .. */
seq_code = NET_TCP_CONN_RX_SEQ_SYNC; /* .. sync's seq nbr valid. */
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Notes #1d & #1e. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
if (pbuf_hdr->TCP_SegSync != DEF_NO) { /* If sync rx'd, ... */
return (NET_TCP_CONN_RX_SEQ_SYNC_INVALID); /* ... rtn invalid sync (see Note #1e). */
}
if (pconn->RxWinSizeActual > 0) { /* If rx win size > 0, ... */
/* ... chk for seg seq within rx win. */
switch (pconn->RxQ_State) {
case NET_TCP_RX_Q_STATE_CONN_SYNC:
case NET_TCP_RX_Q_STATE_CONN:
seq_win_next = (NET_TCP_SEQ_NBR)(pconn->RxSeqNbrNext + pconn->RxWinSizeActual);
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + 1);
seq_win_delta = (NET_TCP_SEQ_NBR)(seq_win_next - seq_nbr);
/* If [(next + win) - seq ] < win size, */
if (seq_win_delta < pconn->RxWinSizeActual) {
seq_code = NET_TCP_CONN_RX_SEQ_VALID; /* .. seq nbr within rx win (see Note #1d2). */
} else if (pbuf_hdr->TCP_SegLen > 0) {
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + pbuf_hdr->TCP_SegLen);
seq_win_delta = (NET_TCP_SEQ_NBR)(seq_win_next - seq_nbr);
/* If [(next + win) - (seq + len)] < win size, */
if (seq_win_delta < pconn->RxWinSizeActual) {
/* .. seq nbr within rx win (see Note #1d4). */
seq_code = NET_TCP_CONN_RX_SEQ_VALID;
}
}
break;
case NET_TCP_RX_Q_STATE_CONN_CLOSED:
case NET_TCP_RX_Q_STATE_CONN_CLOSING:
seq_win_next = (NET_TCP_SEQ_NBR) pconn->RxSeqNbrLast;
seq_nbr = (NET_TCP_SEQ_NBR)(pbuf_hdr->TCP_SeqNbr + pbuf_hdr->TCP_SegLen);
seq_win_delta = (NET_TCP_SEQ_NBR)(seq_win_next - seq_nbr);
seq_win = (NET_TCP_SEQ_NBR)(pconn->RxSeqNbrLast - pconn->RxSeqNbrNext);
if (seq_win_delta <= seq_win) { /* If [last - (seq + len)] <= [last - next], .. */
seq_code = NET_TCP_CONN_RX_SEQ_VALID; /* .. seq nbr within close win (see Note #2c1). */
}
break;
case NET_TCP_RX_Q_STATE_NONE:
case NET_TCP_RX_Q_STATE_CLOSED:
default:
return (NET_TCP_CONN_RX_SEQ_INVALID);
}
} else { /* Else chk for valid, zero-len seg. */
if (pbuf_hdr->TCP_SegLen > 0) { /* If seg len > 0, ... */
*perr = NET_TCP_ERR_INVALID_LEN_SEG; /* ... rtn invalid seg len (see Note #1d3). */
return (NET_TCP_CONN_RX_SEQ_INVALID);
}
if (pbuf_hdr->TCP_SeqNbr == pconn->RxSeqNbrNext) { /* If seq nbr equals next rx seq expected, .. */
seq_code = NET_TCP_CONN_RX_SEQ_VALID; /* .. seq nbr valid (see Note #1d1). */
}
}
break;
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (NET_TCP_CONN_RX_SEQ_INVALID); /* Prevent 'break NOT reachable' warning. */
}
}
return (seq_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnIsValidAck()
*
* Description : Validate a received segment's acknowledgement number with current TCP connection.
*
* Argument(s) : pconn Pointer to a TCP connection.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Acknowledgement number successfully
* validated; check return value.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
*
* Return(s) : NET_TCP_CONN_RX_ACK_INVALID, if received acknowledgement number invalid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_VALID, if received acknowledgement number valid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_NONE, if NO received acknowledgement number.
*
* NET_TCP_CONN_RX_ACK_DUP, if received acknowledgement number is a duplicate for the
* TCP connection.
*
* NET_TCP_CONN_RX_ACK_PREV, if received acknowledgement number is a previous duplicate for the
* TCP connection.
*
* Caller(s) : various.
*
* Note(s) : (1) Validate received TCP connection acknowledgements :
*
* (a) RFC #793, Section 3.4 'Establishing a Connection : Reset Generation : 1' states
* that "if [a] connection [is] ... CLOSED then a reset is sent in response to any
* incoming segment". Thus, ALL received segments, including acknowledgement
* segments, are invalid.
*
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for ACK' states that "any acknowledgment is bad if it arrives on a
* connection still in the LISTEN state".
*
* (c) (1) The following sections generalize that "if SND.UNA < SEG.ACK =< SND.NXT then
* the ACK is acceptable", whereas "if SEG.ACK =< SND.UNA, or SEG.ACK > SND.NXT"
* then the acknowledgement is unacceptable :
*
* (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT
* [State] : Check ACK Bit'
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK
* Field : SYN-RECEIVED STATE'
* (C) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK
* Field : ESTABLISHED STATE'
*
* Including states with similar "processing as for the ESTABLISHED STATE" (see
* RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field') :
*
* (D) FIN-WAIT-1 STATE
* (E) FIN-WAIT-2 STATE
* (F) CLOSING STATE
* (G) CLOSE-WAIT STATE
*
* See also Note #3a.
*
* (2) However, RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT
* [State] : Check SYN Bit' also states to "check the SYN bit ... if the ACK is
* ok, or there is no ACK".
*
* Therefore, the lack of an acknowledgement in the SYN-SENT state is acceptable.
*
* (3) However, RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check
* ACK Field : ESTABLISHED STATE' also states that in the "ESTABLISHED STATE"
* or any state with similar "processing as for the ESTABLISHED STATE ... if
* the ACK is a duplicate (SEG.ACK =< SND.UNA), it can be ignored".
*
* See also Note #3b.
*
* (d) (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* TIME-WAIT STATE' states that "the only thing that can arrive in this state is
* a retransmission of the remote FIN".
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* LAST-ACK STATE' states that "the only thing that can arrive in this state is
* an acknowledgement of our FIN".
*
* (2) However, it is possible that some but NOT all transmitted data has been received
* by the remote host. In other words, the remote host may have received some but
* NOT ALL transmitted data preceding this host's connection close request.
*
* ???? Therefore, acknowledgements validated by as within the transmit window MUST
* be received & processed as in connected states.
*$PAGE*
* (2) ???? RFC #793 contains multiple errors/inconsistencies regarding the boundary conditions
* of TCP sequence/acknowledgement inequalities -- i.e. some of the expressions incorrectly
* include or exclude the equality condition.
*
* RFC #1122, Section 4.2.2.20 corrects some but NOT all of these errors/inconsistencies.
*
* (3) RFC #793 does NOT provide nor suggest any logic to determine/handle sequence number
* comparisons for sequence number windows that overflow the sequence number space.
*
* (a) (1) For example, the next sequence octet to transmit (SND.NXT) is typically greater
* than or equal to the last unacknowledged transmit sequence octet (SND.UNA) :
*
* (A) SND.NXT >= SND.UNA
*
* However, when SND.NXT overflows the sequence number space, it will be MUCH less
* than SND.UNA until SND.UNA also overflows :
*
* (B) SND.NXT << SND.UNA
*
* (2) Therefore, in order to validate a received segment's acknowledgement value
* (SEG.ACK) as within the TCP connection's current transmit acknowledgement
* window, the following unsigned arithmetic comparison MUST be true :
*
* (A) (SND.NXT - SEG.ACK) < (SND.NXT - SND.UNA)
*
* (b) (1) Typically, duplicate acknowledgements are less than or equal to the last
* unacknowledged transmit sequence octet (SND.UNA) :
*
* (A) SEG.ACK <= SND.UNA
*
* However, when SND.UNA overflows the sequence number space, it will be MUCH less
* than duplicate acknowledgements until these duplicates also overflow :
*
* (B) SEG.ACK >> SND.UNA
*
* (2) Therefore, in order to validate SEG.ACK as a recent duplicate acknowledgement
* for the TCP connection's current transmit acknowledgement window, the following
* unsigned arithmetic comparison MUST be true :
*
* (A) (SND.UNA - SEG.ACK) <= (WIN_SIZE_SCALE * TxWinSizeRemote)
*
* where
*
* WIN_SIZE_SCALE is some window-size scalar multiplier
* TxWinSizeRemote is the remote host's last-advertised
* receive window size, which is this
* host's transmit remote window size
*********************************************************************************************************
*/
static NET_TCP_ACK_CODE NetTCP_RxPktConnIsValidAck (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_ACK_CODE ack_code;
NET_TCP_SEQ_NBR ack_delta_next;
NET_TCP_SEQ_NBR ack_delta_unackd;
NET_TCP_SEQ_NBR ack_win;
NET_TCP_SEQ_NBR ack_dup_win;
/*$PAGE*/
*perr = NET_TCP_ERR_NONE;
ack_code = NET_TCP_CONN_RX_ACK_INVALID;
if (pconn != (NET_TCP_CONN *)0) {
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (NET_TCP_CONN_RX_ACK_INVALID); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #1a. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #1b. */
if (pbuf_hdr->TCP_SegAck != DEF_NO) { /* If ack rx'd, ... */
return (NET_TCP_CONN_RX_ACK_INVALID); /* ... rtn invalid ack. */
}
ack_code = NET_TCP_CONN_RX_ACK_NONE;
break;
case NET_TCP_CONN_STATE_SYNC_TXD:
if (pbuf_hdr->TCP_SegAck == DEF_NO) { /* If NO ack rx'd, ... */
return (NET_TCP_CONN_RX_ACK_NONE); /* ... rtn valid ack (see Note #1c2). */
}
/* 'break' intentionally omitted; do NOT move .. */
/* .. from the following case (see Note #1c1A) : .. */
/* .. 'NET_TCP_CONN_STATE_SYNC_RXD'. */
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #1c1B. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
if (pbuf_hdr->TCP_SegAck != DEF_YES) { /* If NO ack rx'd, ... */
return (NET_TCP_CONN_RX_ACK_NONE); /* ... rtn NO ack. */
}
ack_delta_next = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pbuf_hdr->TCP_AckNbr);
ack_win = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pconn->TxSeqNbrUnAckd);
if (ack_delta_next < ack_win) { /* If (next - ack) < ack win, ... */
ack_code = NET_TCP_CONN_RX_ACK_VALID; /* ... ack is within ack win (see Note #3a2A). */
}
break;
case NET_TCP_CONN_STATE_CONN: /* See Note #1c1C. */
case NET_TCP_CONN_STATE_FIN_WAIT_1: /* See Note #1c1D. */
case NET_TCP_CONN_STATE_FIN_WAIT_2: /* See Note #1c1E. */
case NET_TCP_CONN_STATE_CLOSING: /* See Note #1c1F. */
case NET_TCP_CONN_STATE_CLOSE_WAIT: /* See Note #1c1G. */
case NET_TCP_CONN_STATE_TIME_WAIT: /* See Note #1d2. */
case NET_TCP_CONN_STATE_LAST_ACK: /* See Note #1d2. */
if (pbuf_hdr->TCP_SegAck != DEF_YES) { /* If NO ack rx'd, ... */
return (NET_TCP_CONN_RX_ACK_NONE); /* ... rtn NO ack. */
}
ack_delta_next = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pbuf_hdr->TCP_AckNbr);
ack_win = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrNext - pconn->TxSeqNbrUnAckd);
if (ack_delta_next < ack_win) { /* If (next - ack) < ack win, ... */
ack_code = NET_TCP_CONN_RX_ACK_VALID; /* ... ack is within ack win (see Note #3a2A). */
} else {
ack_delta_unackd = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrUnAckd - pbuf_hdr->TCP_AckNbr);
if (ack_delta_unackd == 0) { /* If (unackd - ack) = 0, ... */
ack_code = NET_TCP_CONN_RX_ACK_DUP; /* ... ack is dup ack. */
/* ... (see Note #1c3). */
} else {
ack_dup_win = (NET_TCP_SEQ_NBR)(NET_TCP_ACK_NBR_DUP_WIN_SIZE_SCALE * pconn->TxWinSizeRemote);
if (ack_delta_unackd <= ack_dup_win) { /* If (unackd - ack) <= dup ack win, ... */
ack_code = NET_TCP_CONN_RX_ACK_PREV; /* ... ack is recent dup ack ... */
/* ... (see Notes #1c3 & #3b2A). */
}
}
}
break;
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (NET_TCP_CONN_RX_ACK_INVALID); /* Prevent 'break NOT reachable' compiler warning. */
}
}
return (ack_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktConnIsValidReset()
*
* Description : Validate a received segment's reset flag, if any, with current TCP connection.
*
* Argument(s) : pconn Pointer to a TCP connection.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Received segment's reset flag successfully
* validated; check return value.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
*
* - RETURNED BY NetTCP_RxPktConnIsValidSeq() : -
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* Return(s) : NET_TCP_CONN_RX_RESET_INVALID, if received reset flag invalid for the TCP connection.
*
* NET_TCP_CONN_RX_RESET_VALID, if received reset flag valid for the TCP connection;
* i.e. reset the TCP connection.
*
* NET_TCP_CONN_RX_RESET_NONE, if NO received reset flag.
*
* Caller(s) : various.
*
* Note(s) : (1) See the following RFC's for TCP reset validation summary :
*
* (a) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing'
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES'
* (c) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2
*
* (2) Validate received TCP connection resets :
*
* (A) Some TCP receive reset validation logic implemented in previous functions; include
* duplicate validation logic in NetTCP_RxPktConnIsValidReset() only if debug/validation
* code is enabled (i.e. NET_ERR_CFG_ARG_CHK_DBG_EN is DEF_ENABLED in 'net_cfg.h').
*
* (a) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : CLOSED [State]' states
* that "if the state is CLOSED ... an incoming segment containing a RST is discarded".
*
* (2) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State]'
* states that if "the state is LISTEN ... an incoming RST should be ignored".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "if the receiver ... of a RST ... was in the LISTEN state, it ignores it".
*
* (3) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check RST Bit' states that "if the RST bit is set [and] if the ACK was
* acceptable then ... enter CLOSED state".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' reiterates
* that "in the SYN-SENT state (a RST received in response to an initial SYN), the
* RST is acceptable if the ACK field acknowledges the SYN".
*
* (1) However, since receiving a TCP connection request/synchronization segment
* with no acknowledgement number in the SYN-SENT state is permitted, then
* a received TCP reset segment with no acknowledgement number MUST also be
* acceptable.
*
* See also Note #2a5C.
*$PAGE*
* (4) (A) (1) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing'
* summarizes that "in all states except SYN-SENT, all reset (RST) segments
* are validated by checking their SEQ-fields. A reset is valid if its
* sequence number is in the window".
*
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* reiterates that the received segment's reset is valid if and only if its
* sequence number is valid since it follows RFC #793, Section 3.9 'Event
* Processing : SEGMENT ARRIVES : Check Sequence Number'.
*
* (3) RFC #793, Section 3.3 states "that when the receive window is zero no
* segments should be acceptable except ACK segments ... However, even when
* the receive window is zero, a TCP must process the RST ... fields of all
* incoming segments".
*
* However, this contradicts the following sections which state that a
* "received segment's reset is valid if and only if its sequence number if
* valid" & that "if an incoming segment is not acceptable ... [and] the RST
* bit is set, ... drop the segment" :
*
* (a) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing'
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check
* Sequence Number'
*
* See also Note #2a5B.
*
* (B) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* states that in the "SYN-RECEIVED STATE" that "if the RST bit is set [and]
* this connection was initiated with a passive OPEN (i.e., came from the
* LISTEN state), then return this connection to the LISTEN state ... If this
* connection was initiated with an active OPEN (i.e., came from SYN-SENT state)
* then the connection was refused, ... enter the CLOSED state".
*
* (2) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing'
* reiterates that "if the receiver ... of a RST ... was in SYN-RECEIVED state
* and had previously been in the LISTEN state, then the receiver returns to
* the LISTEN state, otherwise the receiver aborts the connection and goes to
* the CLOSED state".
*
* (3) However, since TCP connections opened from the LISTEN state are cloned from
* the original LISTEN-state TCP connection, it is NOT necessary to return ANY
* reset TCP connection from the SYN-RECEIVED state back to the LISTEN state.
*
* See also Note #2a5A.
*
* (C) (1) RFC #793, Section 3.4 'Establishing a Connection : Reset Processing' states
* that "if the receiver ... of a RST ... was in any other state [other than
* LISTEN or SYN-RECEIVED], it aborts the connection and advises the user and
* goes to the CLOSED state".
*
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* states that in the "ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT" states
* that "if the RST bit is set then, any outstanding RECEIVEs and SEND[s] should
* receive 'reset' responses. All segment queues should be flushed. Users
* should also receive an unsolicited general 'connection reset' signal[, and]
* enter the CLOSED state".
*
* (3) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* states that in the "CLOSING STATE, LAST-ACK STATE, TIME-WAIT" states that
* "if the RST bit is set then, enter the CLOSED state".
*
* See also Note #2a5A.
*$PAGE*
* (5) (A) RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling of a segment
* with the RST bit when in a synchronized state" to "provide some protection against
* ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the expected window,
* silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic], reset the
* connection"; it is assumed that this should read "if the RST bit is set and
* the sequence number is exactly the next expected sequence number, reset the
* connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly match
* the next expected sequence value, yet is within the acceptable window
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send an acknowledgment."
*
* (B) ???? Although RFC Draft-IETF-TCPm-TCPSecure #00 explicitly states that this
* amendment applies only to the "handling of a ... RST ... when in a synchronized
* state", it is assumed that this should also apply to the SYN-RECEIVED state.
*
* (C) (1) ???? In addition, it is assumed that a similar validation should also
* apply to the SYN-SENT state. Since the SYN-SENT state validates a
* received TCP reset segment based only on the segment's acknowledgement,
* a similar validation could require that the acknowledgement "exactly
* match the next expected sequence value" -- i.e. the initial connection
* synchronization sequence number plus one.
*
* (2) However, a specific check for the exact acknowledgement is NOT necessary
* since NO data is transmitted from the SYN-SENT state. Therefore, the ONLY
* value to be acknowledged is the initial connection synchronization sequence
* number.
*
* (D) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a precedence
* priority for handling TCP segments received with BOTH the RST & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* (b) RFC #1122, Section 4.2.2.12 states that "a TCP SHOULD allow a received RST segment
* to include data".
*********************************************************************************************************
*/
static NET_TCP_RESET_CODE NetTCP_RxPktConnIsValidReset (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_ACK_CODE ack_code;
NET_TCP_SEQ_CODE seq_code;
#endif
NET_TCP_RESET_CODE reset_code;
/*$PAGE*/
*perr = NET_TCP_ERR_NONE;
if (pbuf_hdr->TCP_SegReset != DEF_YES) { /* If NO reset rx'd, ... */
return (NET_TCP_CONN_RX_RESET_NONE); /* ... rtn NONE. */
}
reset_code = NET_TCP_CONN_RX_RESET_INVALID;
if (pconn != (NET_TCP_CONN *)0) {
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return (NET_TCP_CONN_RX_RESET_INVALID); /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #2a1. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #2a2. */
break;
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #2a3. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #2A. */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return (NET_TCP_CONN_RX_RESET_INVALID);
}
if (ack_code == NET_TCP_CONN_RX_ACK_INVALID) {
return (NET_TCP_CONN_RX_RESET_INVALID);
}
#endif
reset_code = NET_TCP_CONN_RX_RESET_VALID;
break;
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Notes #2a4B & #2a5B. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN: /* See Notes #2a4C & #2a5A. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #2A. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return (NET_TCP_CONN_RX_RESET_INVALID);
}
if (seq_code != NET_TCP_CONN_RX_SEQ_VALID) {
return (NET_TCP_CONN_RX_RESET_INVALID);
}
#endif
if (pbuf_hdr->TCP_SeqNbr == pconn->RxSeqNbrNext) { /* If seq nbr equals next rx seq expected ... */
reset_code = NET_TCP_CONN_RX_RESET_VALID; /* ... (see Note #2a5Ab), rtn valid reset. */
}
break;
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return (NET_TCP_CONN_RX_RESET_INVALID); /* Prevent 'break NOT reachable' warning. */
}
}
return (reset_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxPktFree()
*
* Description : Free network buffer(s).
*
* Argument(s) : pbuf_q Pointer to network buffer queue.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxAppData(),
* NetTCP_RxPktConnHandler(),
* NetTCP_RxPktConnHandlerRxQ_AppData().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_RxPktFree (NET_BUF *pbuf_q)
{
NetBuf_FreeBufQ_PrimList((NET_BUF *)pbuf_q,
(NET_CTR *)0);
}
/*
*********************************************************************************************************
* NetTCP_RxPktDiscard()
*
* Description : On any TCP Receive errors, discard TCP packet(s) & buffer(s).
*
* Argument(s) : pbuf Pointer to network buffer.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_ERR_RX Receive error; packet discarded.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_Rx(),
* NetTCP_RxPktConnHandler().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_RxPktDiscard (NET_BUF *pbuf,
NET_ERR *perr)
{
NET_CTR *pctr;
#if (NET_CTR_CFG_ERR_EN == DEF_ENABLED)
pctr = (NET_CTR *)&NetTCP_ErrRxPktDiscardedCtr;
#else
pctr = (NET_CTR *) 0;
#endif
NetBuf_FreeBufQ_PrimList((NET_BUF *)pbuf,
(NET_CTR *)pctr);
*perr = NET_ERR_RX;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxConnWinSizeCfg()
*
* Description : (1) Configure TCP connection's receive window controls :
*
* (a) Configure TCP connection's receive window update threshold
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnCfg().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnCfg(),
* NetTCP_ConnCfgRxWinSize().
*
* Note(s) : (2) A TCP connection's receive window controls should NOT be updated until after the
* following TCP connection control(s) have been configured :
*
* (a) TCP connection's configured receive window size ('RxWinSizeCfgd')
* [see 'NetTCP_RxConnWinSizeCfgUpdateTh() Note #2a']
*
* (b) TCP connection's connection maximum segment size ('MaxSegSizeConn')
* [see 'NetTCP_RxConnWinSizeCfgUpdateTh() Note #2b']
*********************************************************************************************************
*/
static void NetTCP_RxConnWinSizeCfg (NET_TCP_CONN *pconn)
{
NetTCP_RxConnWinSizeCfgUpdateTh(pconn);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxConnWinSizeCfgUpdateTh()
*
* Description : Configure TCP connection's receive window update threshold.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxConnWinSizeCfg().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxConnWinSizeCfg().
*
* Note(s) : (1) RFC #1122, Section 4.2.3.3 states that "the suggested SWS avoidance algorithm for
* the receiver is ... to avoid advancing the right window edge RCV.NXT+RCV.WND ...
* until the reduction satisfies" :
*
* (a) RCV.BUFF - RCV.USER - RCV.WND >= min(Fr * RCV.BUFF, Eff.snd.MSS)
*
* where
* (1) RCV.BUFF Total receive buffer space
* (2) RCV.USER Data received but not yet consumed
* (3) RCV.WND Space advertised to sender
* (4) Fr Fraction whose recommended value is 1/2
* (5) Eff.snd.MSS Effective send MSS for the connection
*
* (2) A TCP connection's receive window update threshold should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's configured receive window size ('RxWinSizeCfgd')
* [see 'NetTCP_ConnClr() Note #4']
*
* (b) TCP connection's connection maximum segment size ('MaxSegSizeConn')
* [see 'NetTCP_ConnCfgMaxSegSize() Note #1']
*********************************************************************************************************
*/
static void NetTCP_RxConnWinSizeCfgUpdateTh (NET_TCP_CONN *pconn)
{
NET_TCP_WIN_SIZE rx_win_size_th;
/* Cfg silly win min th (see Note #1a). */
rx_win_size_th = (NET_TCP_WIN_SIZE)(((CPU_INT32U)pconn->RxWinSizeCfgd * NET_TCP_RX_SILLY_WIN_NUMER)
/ NET_TCP_RX_SILLY_WIN_DENOM);
pconn->RxWinSizeUpdateTh = DEF_MIN(pconn->MaxSegSizeConn,
rx_win_size_th);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_RxConnWinSizeHandler()
*
* Description : (1) Handle TCP connection's receive window :
*
* (a) Handle TCP connection receive window See Notes #2 & #3
* (b) Transmit TCP connection acknowledgement See Note #4
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxAppData(),
* NetTCP_RxPktConnHandlerRxQ_Sync(),
* NetTCP_RxPktConnHandlerRxQ_Conn(),
* NetTCP_RxPktConnHandlerRxQ_AppData().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
*
* win_update_size Size to update TCP connection's receive window (in octets).
*
* win_update_code Indicate how to update TCP connection receive window :
*
* NET_TCP_CONN_RX_WIN_RESET Reset TCP connection's available
* receive window size.
* NET_TCP_CONN_RX_WIN_SET Set TCP connection's available
* receive window size.
* NET_TCP_CONN_RX_WIN_INC Increment TCP connection's available
* receive window size.
* NET_TCP_CONN_RX_WIN_DEC Decrement TCP connection's available
* receive window size.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxAppData(),
* NetTCP_RxPktConnHandlerRxQ_Sync(),
* NetTCP_RxPktConnHandlerRxQ_Conn(),
* NetTCP_RxPktConnHandlerRxQ_AppData().
*
* Note(s) : (2) RFC #793, Section 3.7 'Data Communication : Managing the Window' states that ... :
*
* (a) "The window sent in each segment indicates the range of sequence numbers the
* sender of the window (the data receiver) is currently prepared to accept.
* There is an assumption that this is related to the currently available data
* buffer space available for this connection."
*
* (1) A TCP connection's advertised receive window MUST NEVER be decreased to zero
* if NO receive data is available & ready to be read by the application layer.
*
* In other words, if NO received data starting from the next expected receive
* sequence number(s) is queued, then NO data is available to be read by the
* application layer. Therefore, the receive window size MUST NOT be decreased
* to zero, otherwise the receive window would deadlock since the application
* layer would NOT be able to read & extract any data from the receive window
* & the TCP connection would NOT be able to receive any more data into the
* receive window.
*
* See also 'NetTCP_RxPktConnHandlerRxQ_AppData() Note #6b'.
*
* (b) "The mechanisms provided allow a TCP to advertise a large window and to
* subsequently advertise a much smaller window without having accepted that
* much data. This ... 'shrinking the window' is strongly discouraged. The
* robustness principle dictates that TCPs will not shrink the window ... but
* will be prepared for such behavior on the part of other TCPs."
*
* (c) "Note that ... acknowledgments should not be delayed or unnecessary
* retransmissions will result. One strategy would be to send an acknowledgment
* when a small segment arrives (with out [sic] updating the window information),
* and then to send another acknowledgment with new window information when the
* window is larger."
*
* (1) However, the following sections retract this delayed acknowledgement
* prohibition & state that "a TCP SHOULD implement a delayed ACK" :
*
* (A) RFC # 813, Section 5
* (B) RFC #1122, Section 4.2.3.2
* (C) RFC #2581, Section 4.2
*
* See also Note #4 & 'NetTCP_TxConnAck() Note #6'.
*$PAGE*
* (3) (a) RFC #813, Section 2 states that "a bad implementation of the window algorithm
* can lead to extremely poor performance ... This particular phenomenon ... has
* been given the name of Silly Window Syndrome, or SWS".
*
* Section 3 elaborates that "SWS is a degeneration in the throughput which develops
* ... whenever the acknowledgement of a small segment ... cause[s] another segment
* of the same small size to be sent, until ... the network ... becomes clogged with
* many small segments, and an equal number of acknowledgements".
*
* (b) (1) RFC #813, Section 4 states that "the receiver of data can take a very simple
* step to eliminate SWS. When it disposes of a small amount of data, it can
* artificially reduce the offered window in subsequent acknowledgements, so
* that the useable window computed by the sender does not permit the sending
* of any further data.
*
* At some later time, when the receiver has processed a substantially larger
* amount of incoming data, the artificial limitation on the offered window
* can be removed all at once, so that the sender computes a sudden large jump
* rather than a sequence of small jumps in the useable window.
*
* For a simple implementation, ... artificially reduce the offered window until
* the reduction constitutes one half of the available space ... [or] at least
* permit one reasonably large segment".
*
* (2) RFC #1122, Section 4.2.3.3 reiterates that "a TCP MUST include a SWS avoidance
* algorithm in the receiver ... This algorithm combines with the delayed ACK
* algorithm ... to determine when an ACK segment containing the current window
* will really be sent to the receiver [sic]".
*
* "The solution to receiver SWS is to avoid advancing the right window edge
* RCV.NXT+RCV.WND in small increments, even if data is received from the
* network in small segments ... The suggested SWS avoidance algorithm for
* the receiver is to keep RCV.NXT+RCV.WND fixed until the reduction satisfies :
*
* (A) RCV.BUFF - RCV.USER - RCV.WND >= min(Fr * RCV.BUFF, Eff.snd.MSS)
*
* where
* (1) RCV.BUFF Total receive buffer space
* (2) RCV.USER Data received but not yet consumed
* (3) RCV.WND Space advertised to sender
* (4) Fr Fraction whose recommended value is 1/2
* (5) Eff.snd.MSS Effective send MSS for the connection
*
*
* Note that the general effect of this algorithm is to advance RCV.WND in
* increments of the Eff.snd.MSS."
*
* (4) (a) RFC #813, Section 5 states that "the receiver of data will refrain from
* sending an acknowledgement under certain circumstances ... Postpone
* sending an acknowledgement if ... the following conditions hold" :
*
* (1) "There is no revised window information to be sent back."
*
* (A) However, if any local receive window size is available to update to
* the remote host, an acknowledgement should be immediately transmitted.
*
* (1) HOWEVER, since local receive window size updates will continually
* occur for "a host that is receiving a stream of TCP data segments"
* (RFC #1122, Section 4.2.3.2); it is NOT possible to both update the
* local receive window & implement a delayed acknowledgement.
*
* (a) #### Therefore, in order to implement a delayed acknowledgement,
* the only local receive window size updates that SHOULD transmit
* an immediate acknowledgement :
*
* (1) Local receive window size sets/resets
* (2) Local receive window size increases
* (3) Local receive window size decreases to zero-sized
*
* (b) #### The following local receive window size updates SHOULD NOT
* transmit an immediate acknowledgement :
*
* (1) Local receive window size decreases
*
* (b) RFC #1122, Section 4.2.3.2 states that "a delayed ACK gives the application an
* opportunity to update the window and perhaps to send an immediate response".
*
* See also 'NetTCP_TxConnAck() Notes #4b1, #6, & #7'.
*$PAGE*
* (5) Since the configured receive window size may be asynchronously modified by the
* application layer, changes in the calculated &/or advertised receive window size
* MUST be appropriately validated to any possible new value for the configured
* receive window size :
*
* (a) During receive window size increases, if the currently calculated receive
* window size is already greater than the currently configured receive window
* size; then the calculated window size is NOT increased, but is allowed to
* remain greater than the configured window size until the calculated window
* size decreases below the configured window size.
*
* (b) During receive window size decreases, if the currently calculated receive
* window size is already greater than the currently configured receive window
* size; then the calculated window size is further decreased, but is allowed to
* remain greater than the configured window size until the calculated window
* size decreases below the configured window size.
*
* (c) During receive window size decreases, if the currently configured receive
* window size is less than the actual configured receive window size; then
* the actual configured receive window size is also decremented by the window
* size decrease.
*********************************************************************************************************
*/
static void NetTCP_RxConnWinSizeHandler (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_update_code)
{
CPU_BOOLEAN tx_ack;
NET_TCP_ACK_CODE tx_ack_code;
NET_TCP_WIN_SIZE win_size_avail;
NET_TCP_WIN_SIZE win_size_delta;
NET_ERR err;
/* ---------- HANDLE TCP CONN RX WIN ---------- */
tx_ack = DEF_NO;
switch (win_update_code) {
case NET_TCP_CONN_RX_WIN_RESET:
default:
/* If < cfg'd win size (see Note #5a), ... */
if (pconn->RxWinSizeCalcd < pconn->RxWinSizeCfgd) {
/* ... reset calc'd win size to cfg'd win size. */
pconn->RxWinSizeCalcd = pconn->RxWinSizeCfgd;
pconn->RxWinSizeCfgdActual = pconn->RxWinSizeCfgd;
pconn->RxWinSizeCfgdActualUpdateRem = 0;
}
if (pconn->RxWinSizeActual < pconn->RxWinSizeCalcd) { /* Do NOT shrink rx win (see Note #2b). */
pconn->RxWinSizeActual = pconn->RxWinSizeCalcd;
tx_ack = DEF_YES;
tx_ack_code = NET_TCP_CONN_TX_ACK_IMMED; /* See Note #4a1A1a1. */
}
break;
case NET_TCP_CONN_RX_WIN_SET:
if (pconn->RxWinSizeActual < win_update_size) { /* If actual rx win size < win update, ... */
pconn->RxWinSizeActual = win_update_size; /* ... set rx win size. */
pconn->RxWinSizeCalcd = win_update_size;
tx_ack = DEF_YES;
tx_ack_code = NET_TCP_CONN_TX_ACK_IMMED; /* See Note #4a1A1a1. */
break;
} /* Else inc; do NOT shrink win (see Note #2b). */
/* 'break' intentionally omitted; do NOT .. */
/* .. move from the following case : .. */
/* .. 'NET_TCP_CONN_RX_WIN_INC'. */
/*$PAGE*/
case NET_TCP_CONN_RX_WIN_INC:
if (win_update_size == 0) { /* If NO win update, MUST NOT update win. */
break;
}
if (pconn->RxWinSizeCalcd <= pconn->RxWinSizeCfgdActual) { /* If <= cfg'd win size (see Note #5a), ... */
/* ... inc rx win size. */
win_size_avail = pconn->RxWinSizeCfgdActual - pconn->RxWinSizeCalcd;
if (win_size_avail > win_update_size) { /* If avail rx win size > win update, ... */
pconn->RxWinSizeCalcd += win_update_size; /* ... inc rx win size by win update. */
} else { /* Else limit to cfg'd rx win size. */
pconn->RxWinSizeCalcd = pconn->RxWinSizeCfgdActual;
}
if (pconn->RxWinSizeCalcd > pconn->RxWinSizeActual) {
win_size_delta = pconn->RxWinSizeCalcd - pconn->RxWinSizeActual;
if (win_size_delta >= pconn->RxWinSizeUpdateTh) { /* If calc'd - actual rx win size >= th, ... */
pconn->RxWinSizeActual = pconn->RxWinSizeCalcd;/* ... update rx win size (see Note #3b2). */
tx_ack = DEF_YES;
tx_ack_code = NET_TCP_CONN_TX_ACK_IMMED; /* See Note #4a1A1a2. */
}
} else { /* Prevent rx win shrink (see Note #2b). */
pconn->RxWinSizeCalcd = pconn->RxWinSizeActual;
}
}
break;
case NET_TCP_CONN_RX_WIN_DEC:
if (win_update_size == 0) { /* If NO win update, MUST NOT update win. */
break;
}
if (pconn->RxWinSizeCfgdActualUpdateRem > 0) { /* If cfg'd win update > 0 (see Note #5c), .. */
/* .. cfg actual cfg'd win update to : .. */
if (pconn->RxWinSizeCfgdActualUpdateRem > win_update_size) {
win_size_avail = win_update_size; /* .. win update size .. */
} else { /* .. or limit to cfg'd win update rem'ing; .. */
win_size_avail = pconn->RxWinSizeCfgdActualUpdateRem;
}
pconn->RxWinSizeCfgdActualUpdateRem -= win_size_avail; /* .. dec cfg'd win update rem'ing; & .. */
if (pconn->RxWinSizeCfgdActual > win_size_avail) {
pconn->RxWinSizeCfgdActual -= win_size_avail; /* .. dec actual cfg'd win size. */
} else {
pconn->RxWinSizeCfgdActual = 0;
}
}
if (pconn->RxWinSizeCalcd > win_update_size) { /* If calc'd rx win size > win update, ... */
pconn->RxWinSizeCalcd -= win_update_size; /* ... dec rx win size by win update. */
} else {
pconn->RxWinSizeCalcd = 0; /* Else limit to min rx win size. */
}
if (pconn->RxWinSizeActual > 0) {
if (pconn->RxWinSizeActual > win_update_size) { /* If actual rx win size > win update, ... */
pconn->RxWinSizeActual -= win_update_size; /* ... dec rx win size by win update. */
tx_ack_code = NET_TCP_CONN_TX_ACK; /* See Note #4a1A1b1. */
} else {
pconn->RxWinSizeActual = 0; /* Else limit to min rx win size. */
tx_ack_code = NET_TCP_CONN_TX_ACK_IMMED; /* See Note #4a1A1a3. */
}
tx_ack = DEF_YES;
}
break;
}
/* --------------- TX TCP CONN ACK ------------ */
if (tx_ack == DEF_YES) { /* If rx win updated, tx ack (see Note #4a1A). */
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If rx'd pkt avail, req tx ack; but ack ... */
pbuf_hdr->TCP_SegAckTxReqCode = tx_ack_code; /* ... NOT tx'd until after rx'd pkt handling. */
} else {
NetTCP_TxConnAck(pconn, pbuf_hdr, tx_ack_code, NET_TCP_CONN_CLOSE_ALL, &err);
}
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeCfg()
*
* Description : (1) Configure TCP connection's transmit window controls :
*
* (a) Configure TCP connection's transmit window congestion controls
* (b) Configure TCP connection's transmit window minimum threshold
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnCfg().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnCfg().
*
* Note(s) : (2) A TCP connection's transmit window controls should NOT be updated until after the
* following TCP connection control(s) have been configured :
*
* (a) TCP connection's maximum transmit remote window size ('TxWinSizeRemoteMax')
* [see 'NetTCP_TxConnWinSizeCfgCongCtrl() Note #5a'
* & 'NetTCP_TxConnWinSizeCfgMinTh() Note #2a']
*
* (b) TCP connection's remaining transmit remote window size ('TxWinSizeRemoteRem')
* [see 'NetTCP_TxConnWinSizeCfgCongCtrl() Note #5b']
*
* (c) TCP connection's connection maximum segment size ('MaxSegSizeConn')
* [see 'NetTCP_TxConnWinSizeCfgCongCtrl() Note #5c']
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeCfg (NET_TCP_CONN *pconn)
{
NetTCP_TxConnWinSizeCfgCongCtrl(pconn);
NetTCP_TxConnWinSizeCfgMinTh(pconn);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeCfgCongCtrl()
*
* Description : (1) Configure TCP connection's transmit window congestion controls :
*
* (a) Configure TCP connection's transmit window slow start threshold See Note #2
* (b) Configure TCP connection's transmit window congestion controls See Note #3
* (c) Reset TCP connection's transmit window duplicate acknowledgement
* controls
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeCfg(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeCfg(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (2) RFC #2581, Section 3.1 states that "the initial value of ssthresh [slow start
* threshold] MAY be arbitrarily high (for example, some implementations use the
* size of the advertised window)".
*
* (a) This amends RFC #2001, Section 2.1 which previously stated that "initialization
* for a given connection sets ... ssthresh to 65535 bytes".
*
* (b) To always ensure a sufficiently high initial value, the slow start threshold
* initializes to the TCP connection's maximum remote window size.
*
* (3) "The initial value of cwnd [congestion window], MUST be less than or equal to 2*SMSS
* bytes and MUST NOT be more than 2 segments."
*
* (a) This amends RFC #2001, Section 2.1 which previously stated that "initialization
* for a given connection sets cwnd to one segment".
*
* (4) (a) RFC #2001, Section 2.2 states that "the TCP output routine never sends more than
* the minimum of cwnd and the receiver's advertised window".
*
* (b) RFC #2581, Section 3.1 reiterates that "the minimum of cwnd and rwnd [receiver's
* advertised window] governs data transmission".
*
* See also 'NetTCP_TxConnWinSizeUpdateAvail() Note #1'.
*
* (5) A TCP connection's transmit window congestion controls should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's maximum transmit remote window size ('TxWinSizeRemoteMax')
* [see 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1a2A'
* & 'NetTCP_TxConnWinSizeHandlerCongCtrl() Notes #3a2A & #3b']
*
* (b) TCP connection's remaining transmit remote window size ('TxWinSizeRemoteRem')
* [see 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1a2A'
* & 'NetTCP_TxConnWinSizeHandlerCongCtrl() Notes #3a2A']
*
* (c) TCP connection's connection maximum segment size ('MaxSegSizeConn')
* [see 'NetTCP_ConnCfgMaxSegSize() Note #1']
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeCfgCongCtrl (NET_TCP_CONN *pconn)
{
/* Cfg tx slow start th (see Note #2b). */
pconn->TxWinSizeSlowStartThInit = (NET_TCP_WIN_SIZE)pconn->TxWinSizeRemoteMax;
pconn->TxWinSizeSlowStartTh = (NET_TCP_WIN_SIZE)pconn->TxWinSizeSlowStartThInit;
/* Cfg tx cong ctrls (see Note #3a). */
pconn->TxWinSizeCongInit = (NET_TCP_WIN_SIZE)pconn->MaxSegSizeConn * NET_TCP_CONG_WIN_MSS_SCALAR_INIT;
pconn->TxWinSizeCongCalcdActual = (NET_TCP_WIN_SIZE)pconn->TxWinSizeCongInit;
pconn->TxWinSizeCongCalcdCur = (NET_TCP_WIN_SIZE)0;
pconn->TxWinSizeCongRem = (NET_TCP_WIN_SIZE)pconn->TxWinSizeCongCalcdActual;
/* Cfg tx win avail (see Note #4). */
NetTCP_TxConnWinSizeUpdateAvail(pconn);
NetTCP_TxConnWinSizeDupAckCtrlReset(pconn); /* Reset dup ack ctrls. */
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeCfgMinTh()
*
* Description : Configure TCP connection's transmit silly window minimum threshold.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeCfg(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeCfg(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (1) RFC #1122, Section 4.2.3.4 states that "the sender's SWS avoidance algorithm is ...
* [to] send data ... if at least a fraction Fs of the maximum window can be sent ...
* Fs is a fraction whose recommended value is 1/2".
*
* (2) A TCP connection's transmit window minimum threshold should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's maximum transmit remote window size ('TxWinSizeRemoteMax')
* [see 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1a2A'
* & 'NetTCP_TxConnWinSizeHandlerCongCtrl() Notes #3a2A & #3b']
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeCfgMinTh (NET_TCP_CONN *pconn)
{
/* Cfg silly win min th (see Note #1). */
pconn->TxWinSizeMinTh = (NET_TCP_WIN_SIZE)(((CPU_INT32U)pconn->TxWinSizeRemoteMax * NET_TCP_TX_SILLY_WIN_NUMER)
/ NET_TCP_TX_SILLY_WIN_DENOM);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeHandlerCfgd()
*
* Description : (1) Handle TCP connection's configured transmit window :
*
* (a) Update TCP connection configured transmit window
* (b) Update TCP connection total transmit data queued
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnAppData(),
* NetTCP_RxPktConnHandlerReTxQ().
*
* win_update_size Size to update TCP connection's transmit window (in octets).
*
* win_update_code Indicate how to update TCP connection transmit window :
*
* NET_TCP_CONN_TX_WIN_RESET Reset TCP connection's available
* transmit window size.
* NET_TCP_CONN_TX_WIN_SET Set TCP connection's available
* transmit window size.
* NET_TCP_CONN_TX_WIN_INC Increment TCP connection's available
* transmit window size.
* NET_TCP_CONN_TX_WIN_DEC Decrement TCP connection's available
* transmit window size.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection's configured transmit window
* successfully updated.
*
* --- RETURNED BY NetOS_TCP_TxQ_Signal() : ---
* NET_TCP_ERR_TX_Q_SIGNAL_FAULT TCP connection transmit queue signal fault.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnAppData(),
* NetTCP_RxPktConnHandlerReTxQ().
*
* Note(s) : (2) (a) RFC #793, Section 3.7 'Data Communication : Managing the Window' states
* that "the window sent in each segment indicates the range of sequence
* numbers the sender of the window (the data receiver) is currently
* prepared to accept. There is an assumption that this is related to the
* currently available data buffer space available for this connection".
*
* (b) Thus, a TCP connection's configured transmit window is constrained by
* the available network resources; of which, network buffers are the
* primary transmit window network resource.
*
* However, since network buffers are discrete resources with non-discrete
* packet size; it is NOT necessary to enforce exact/strict compliance with
* a TCP connection's configured transmit window.
*
* In other words, network buffers allocated for TCP connection transmit
* SHOULD be fully used even if the TCP connection's configured transmit
* window is zero.
*
* (3) Since the configured transmit window size may be asynchronously modified by
* the application layer, changes in the remaining transmit window size MUST be
* appropriately validated to any possible new value for the configured transmit
* window size :
*
* (a) During transmit window size increases, if the remaining transmit window
* size is already greater than the currently configured transmit window
* size; then the remaining window size is NOT increased, but is allowed to
* remain greater than the configured window size until the remaining window
* size decreases below the configured window size.
*
* (b) During transmit window size decreases, if the remaining transmit window
* size is already greater than the currently configured transmit window
* size; then the remaining window size is further decreased, but is allowed
* to remain greater than the configured window size until the remaining
* window size decreases below the configured window size.
*
* (c) Window size update is NOT validated for transmit window size resets.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnWinSizeHandlerCfgd (NET_TCP_CONN *pconn,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_update_code,
NET_ERR *perr)
{
CPU_BOOLEAN q_prevly_full;
NET_TCP_WIN_SIZE win_size_avail;
NET_TCP_CONN_ID conn_id_tcp;
switch (win_update_code) {
case NET_TCP_CONN_TX_WIN_RESET: /* Reset cfg'd tx win size (see Note #1c). */
default:
pconn->TxWinSizeCfgdRem = pconn->TxWinSizeCfgd;
break;
case NET_TCP_CONN_TX_WIN_SET:
if (pconn->TxWinSizeCfgdRem < win_update_size) { /* If rem cfg'd win size < win update, ... */
pconn->TxWinSizeCfgdRem = win_update_size; /* .. set cfg'd win size. */
break;
} /* Else inc; do NOT shrink win. */
/* 'break' intentionally omitted; do NOT .. */
/* .. move from the following case : .. */
/* .. 'NET_TCP_CONN_TX_WIN_INC'. */
case NET_TCP_CONN_TX_WIN_INC:
if (win_update_size == 0) { /* If NO win update, do NOT update win. */
break;
}
q_prevly_full = (pconn->TxWinSizeCfgdRem < 1) ? DEF_YES : DEF_NO;
if (pconn->TxWinSizeCfgdRem < pconn->TxWinSizeCfgd) { /* If < cfg'd win size (see Note #3a), ... */
/* ... inc tx win size. */
win_size_avail = pconn->TxWinSizeCfgd - pconn->TxWinSizeCfgdRem;
if (win_size_avail > win_update_size) { /* If avail tx win size > win update, ... */
pconn->TxWinSizeCfgdRem += win_update_size; /* ... inc tx win size by win update. */
} else {
pconn->TxWinSizeCfgdRem = pconn->TxWinSizeCfgd; /* Else limit to cfg'd tx win size. */
}
}
if (q_prevly_full == DEF_YES) { /* If tx Q prev'ly full, ... */
conn_id_tcp = pconn->ID;
NetOS_TCP_TxQ_Signal(conn_id_tcp, perr); /* ... signal tx Q. */
if (*perr != NET_TCP_ERR_NONE) { /* #### On err, handle tx Q?; close TCP conn? */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
return;
}
}
break;
case NET_TCP_CONN_TX_WIN_DEC:
if (win_update_size == 0) { /* If NO win update, do NOT update win. */
break;
}
if (pconn->TxWinSizeCfgdRem > win_update_size) { /* If rem tx win size > win update, .. */
pconn->TxWinSizeCfgdRem -= win_update_size; /* .. dec tx win size by win update. */
} else {
pconn->TxWinSizeCfgdRem = 0; /* Else limit to min tx win size. */
}
break;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeHandlerCongCtrl()
*
* Description : (1) Handle TCP connection's transmit window congestion controls :
*
* (a) Perform slow start / congestion avoidance algorithms See Note #2c2A
* (b) Perform fast re-transmit / fast recovery algorithms See Note #2c2B
* (c) Handle remote host's receive window updates See Note #3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandlerSeg(),
* NetTCP_RxPktConnHandlerReTxQ(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnTxQ_TimeoutIdleSet(),
* NetTCP_TxConnTxQ_TimeoutIdle(),
* NetTCP_TxConnReTxQ().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* ack_code Indicates the received segment's acknowledgement condition :
*
* NET_TCP_CONN_RX_ACK_NONE NO received acknowledgement number.
*
* NET_TCP_CONN_RX_ACK_INVALID Received acknowledgement number
* is invalid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_VALID Received acknowledgement number
* is valid for the TCP connection.
*
* NET_TCP_CONN_RX_ACK_DUP Received acknowledgement number
* is a duplicate for the
* TCP connection.
*
* NET_TCP_CONN_RX_ACK_PREV Received acknowledgement number
* is a previous duplicate for the
* TCP connection.
*
* win_update_size Size to update TCP connection's transmit window (in octets).
*
* win_update_code Indicate how to update TCP connection transmit window :
*
* NET_TCP_CONN_TX_WIN_RESET Reset TCP connection's congestion
* control transmit window size.
* NET_TCP_CONN_TX_WIN_SEG_RXD Update TCP connection's congestion
* control transmit window size
* based on received segment.
* NET_TCP_CONN_TX_WIN_TIMEOUT Update TCP connection's congestion
* control transmit window size
* based on transmission timeout.
* NET_TCP_CONN_TX_WIN_INC Increment TCP connection's congestion
* control transmit window sizes.
* NET_TCP_CONN_TX_WIN_DEC Decrement TCP connection's
* transmit window sizes.
* NET_TCP_CONN_TX_WIN_REMOTE_UPDATE Update TCP connection's remote
* receive window size.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection's transmit window congestion controls
* successfully updated.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
*
* --------- RETURNED BY NetTCP_TxConnReTxQ() : ---------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
* NET_TCP_ERR_TX TCP transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerSeg(),
* NetTCP_RxPktConnHandlerReTxQ(),
* NetTCP_RxPktConnHandlerTxWinRemote(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnTxQ_TimeoutIdleSet(),
* NetTCP_TxConnTxQ_TimeoutIdle(),
* NetTCP_TxConnReTxQ().
*$PAGE*
* Note(s) : (2) (a) (1) The following sections define, specify, &/or require "TCP's four intertwined congestion
* control algorithms: slow start, congestion avoidance, fast retransmit, and fast recovery" :
*
* (A) RFC #2001 See Note #2c1
* (B) RFC #2581 See Notes #2c2, #2a2, & #2e
* (C) RFC #1122
* (1) Section 4.2.2.15
* (2) Section 4.2.2.21
* (3) Section 4.2.3.9 See 'net_tcp.c Note #1e'
* (a) 'Source Quench' See Note #2e2
* (b) 'Destination Unreachable -- Codes 2-4'
*
*
* (2) Although RFC #2581, Section 1 states that "this document is an update of [RFC #2001]";
* both references are included as complementary specifications of the congestion control
* algorithms.
*
* However, since RFC #2581 is the update to RFC #2001, its specifications supercede
* those of RFC #2001; & ALL differences are implemented by RFC #2581 specifications.
*
* (b) (1) (A) RFC #2581, Section 3.1 states that "the slow start and congestion avoidance
* algorithms MUST be used by a TCP sender to control the amount of outstanding
* data being injected into the network".
*
* (B) RFC #1122, Section 4.2.2.15 reiterates that "a TCP MUST implement ... 'slow
* start' with 'congestion avoidance'".
*
* (2) (A) RFC #2001, Section 1 states that "the sender's ... congestion window ... is
* flow control imposed by the sender, while the advertised window is flow control
* imposed by the receiver. The former is based on the sender's assessment of
* perceived network congestion; the latter is related to the amount of available
* buffer space at the receiver for this connection".
*
* (B) RFC #2581, Section 3.1 reiterates that "the congestion window ... is a sender-
* side limit on the amount of data the sender can transmit into the network
* before receiving an acknowledgment (ACK), while the receiver's advertised
* window ... is a receiver-side limit on the amount of outstanding data."
*
* (3) (A) (1) RFC #2001, Section 1 states that "the sender can transmit up to the minimum
* of the congestion window and the advertised window."
*
* (2) RFC #2001, Section 2.2 reiterates that "the TCP output routine never sends
* more than the minimum of cwnd and the receiver's advertised window".
*
* (3) RFC #2581, Section 3.1 also reiterates that "the minimum of cwnd and rwnd
* [receiver's advertised window] governs data transmission".
*
* (B) RFC #2581, Section 3 also states that "a TCP MUST NOT be more aggressive than
* the [congestion control] algorithms allow (that is, MUST NOT send data when
* the value of cwnd computed by the [congestion control] algorithms would not
* allow the data to be sent)".
*
* (C) TCP transmit resulting from TCP congestion controls update handled by appropriate
* TCP connection state receive handler function(s).
*
* See 'NetTCP_RxPktConnHandlerSyncRxd() Note #1c3',
* 'NetTCP_RxPktConnHandlerSyncTxd() Note #1c3',
* 'NetTCP_RxPktConnHandlerConn() Note #1c',
* 'NetTCP_RxPktConnHandlerFinWait1() Note #1c',
* 'NetTCP_RxPktConnHandlerClosing() Note #1c',
* 'NetTCP_RxPktConnHandlerCloseWait() Note #1c',
* & 'NetTCP_RxPktConnHandlerLastAck() Note #1c'.
*
* (4) (A) RFC #2001, Sections 3 & 4 state that "since ... a duplicate ACK is caused by
* a lost segment or just a reordering of segments, ... [fast retransmit] waits
* for a small number of duplicate ACKs to be received ... [as] a strong indication
* that a segment has been lost ... [and] then performs a retransmission of what
* appears to be the missing segment, without waiting for a retransmission timer
* to expire.
*
* After fast retransmit sends ... the missing segment, congestion avoidance,
* but not slow start is performed. This is the fast recovery algorithm".
*
* (B) RFC #2581, Section 3.2 reiterates that "the TCP sender SHOULD use the 'fast
* retransmit' algorithm to detect and repair loss, based on ... the arrival of
* 3 duplicate ACKs (4 identical ACKs without the arrival of any other intervening
* packets) as an indication that a segment has been lost. After receiving 3
* duplicate ACKs, TCP performs a retransmission of what appears to be the missing
* segment, without waiting for the retransmission timer to expire.
*
* After the fast retransmit algorithm sends ... the missing segment, the 'fast
* recovery' algorithm ... can continue to transmit new segments ... (using a
* reduced cwnd) ... until a non-duplicate ACK arrives".
*$PAGE*
* (c) (1) (A) RFC #2001, Section 2 states that the "congestion avoidance and slow start ...
* combined algorithm operates as follows" :
*
* (1) "Initialization for a given connection sets" :
*
* (a) "cwnd to one segment" ...
* (b) "and ssthresh to 65535 bytes."
*
* (3) (a) (1) "When congestion occurs (indicated by" :
*
* (A) "a timeout" ...
* (B) "or the reception of duplicate ACKs)," ...
*
* (2) "one-half of the current window size" :
*
* (A) "the minimum of" :
* (1) "cwnd" ...
* (2) "and the receiver's advertised window" ...
* (B) "but at least two segments" ...
*
* (3) "is saved in ssthresh [slow start threshold]."
*
* (b) (1) "Additionally, if the congestion is indicated by a timeout," ...
* (2) "cwnd is set to one segment (i.e., slow start)."
*
* (4) "When new data is acknowledged by the other end, increase cwnd, but the way
* it increases depends on whether TCP is performing slow start or congestion
* avoidance" :
*
* (a) (1) (A) (1) (a) "If cwnd is less than or equal to ssthresh," ...
* (b) "TCP is in slow start."
*
* (2) "Slow start continues until TCP is halfway to where it was
* when congestion occurred (since it recorded half of the
* window size that caused the problem)."
*
* (B) (1) "Slow start has cwnd begin at one segment," ...
*
* (2) (a) "and be incremented by one segment" ...
* (b) "every time an ACK is received."
*
* (3) "The increase in cwnd ... [for] slow start increments cwnd
* by the number of ACKs received in a round-trip time ...
* [which] opens the window exponentially: send one segment,
* then two, then four, and so on."
*
* (2) RFC #2001, Section 1 states that :
*
* (A) "Early implementations performed slow start only if the other
* end was on a different network."
*
* (B) "Current implementations always perform slow start."
*
* (b) (1) (A) "If cwnd is [not] less than or equal to ssthresh," ...
* (B) "TCP is performing congestion avoidance."
*
* (2) (A) (1) "cwnd [is] incremented by segsize*segsize/cwnd" ...
* (a) "where segsize is the segment size" ...
* (b) "and cwnd is maintained in bytes";
* (2) "each time an ACK is received."
*
* (B) "This is a linear growth of cwnd ... The increase in cwnd should
* be at most one segment each round-trip time (regardless how many
* ACKs are received in that RTT)."
*
* (B) RFC #2001, Section 4 states that "the fast retransmit and fast recovery
* algorithms are usually implemented together as follows" :
*
* (1) "When the third duplicate ACK in a row is received" :
*
* (a) "Set ssthresh to" :
* (1) "one-half the current congestion window, cwnd" ...
* (2) "but no less than two segments."
*
* (b) "Retransmit the missing segment."
*
* (c) "Set cwnd to ssthresh plus 3 times the segment size."
*
* (2) "Each time another duplicate ACK arrives" :
*
* (a) "Increment cwnd by the segment size."
* (b) "Transmit a packet, if allowed by the new value of cwnd."
*
* (3) "When the next ACK arrives that acknowledges new data" :
*
* (a) "Set cwnd to ssthresh" (see Note #2c1B1a).
*$PAGE*
* (2) (A) RFC #2581, Section 3.1 defines the "slow start and congestion avoidance algorithms"
* as follows :
*
* (1) (a) "The initial value of cwnd, MUST be" :
*
* (1) "less than or equal to 2*SMSS bytes" ...
* (2) "and MUST NOT be more than 2 segments."
*
* (b) "The initial value of ssthresh MAY be arbitrarily high" :
* (1) "some implementations use the size of the advertised window."
*
* (2) (a) "The slow start algorithm is used when cwnd < ssthresh," ...
* (b) "while the congestion avoidance algorithm is used when cwnd > ssthresh."
* (c) "When cwnd and ssthresh are equal the sender may use either slow start or
* congestion avoidance."
*
* (3) (a) "During slow start" :
*
* (1) "a TCP increments cwnd by at most SMSS bytes" ...
* (2) "for each ACK received that acknowledges new data."
*
* (b) "Slow start ends when" :
*
* (1) "cwnd exceeds ... or ... reaches ... ssthresh" ...
* (2) "or when congestion is observed."
*
* (4) (a) "During congestion avoidance" :
*
* (1) "cwnd is incremented by 1 full-sized segment per round-trip time (RTT)."
*
* (2) (A) "One formula commonly used to update cwnd during congestion avoidance
* is given" by :
*
* (2) cwnd += (SMSS * SMSS) / cwnd
*
* (B) "Another acceptable way to increase cwnd during congestion avoidance
* is to count the number of bytes that have been acknowledged by ACKs
* for new data" :
*
* (1) "When the number of bytes acknowledged reaches cwnd," ...
* (2) "then cwnd can be incremented by up to SMSS bytes."
*
* (3) "This adjustment is executed on every incoming non-duplicate ACK."
*
* (b) "Congestion avoidance continues until congestion is detected."
*
* (5) "When a TCP sender detects segment loss using the retransmission timer" :
*
* (a) "the value of ssthresh MUST be set to no more than" :
*
* (3) ssthresh = max (FlightSize / 2, 2 * SMSS)
*
* (A) "FlightSize is the amount of outstanding data ... that has been
* sent but not yet acknowledged."
*
* (b) "cwnd MUST be set to no more than ... 1 full-sized segment."
*
* (c) "Therefore, after retransmitting the dropped segment the TCP sender uses
* the slow start algorithm to increase the window."
*$PAGE*
* (B) RFC #2581, Section 3.2 states that "the fast retransmit and fast recovery algorithms
* are usually implemented together as follows" :
*
* (1) "When the third duplicate ACK is received" (see Note #2d1) :
*
* (a) "set ssthresh to no more than the value given [by the] equation"
* (see Note #2c2A5a3), ...
*
* (b) "Retransmit the lost segment"
* (see Note #2d2), ...
*
* (c) "set cwnd to ssthresh plus 3*SMSS."
* (1) "This artificially 'inflates' the congestion window by the number of
* segments (three) that have left the network and which the receiver
* has buffered."
*
* (2) "For each additional duplicate ACK received" :
*
* (a) "increment cwnd by SMSS."
* (1) "This artificially inflates the congestion window in order to reflect
* the additional segment that has left the network."
*
* (b) (1) "Transmit a segment, if allowed by" :
*
* (A) "the new value of cwnd" ...
* (B) "and the receiver's advertised window."
*
* (2) TCP transmit resulting from TCP congestion controls update handled by
* appropriate TCP connection state receive handler function(s).
*
* See also Note #2b3C.
*
* (3) (a) "When the next ACK arrives that acknowledges new data," ...
* (b) "set cwnd to ssthresh" (see Note #2c2B1a).
*
* (d) (1) (A) RFC #1122, Section 4.2.2.21 states that "'fast retransmit' ... counts the number of
* ... 'redundant' ACK's ... received with" :
*
* (1) "the same value of SEG.ACK and" ...
* (2) "the same right window edge".
*
* (B) Although it is not directly stated, it is inferred that duplicate acknowledgements
* SHOULD be :
*
* (1) Acknowledgement-only segments
* (a) i.e. with NO transmit data See Note #2d1C1
* (1) i.e. with NO TCP segment length
* (2) With NO sequence number update
* (3) With NO receive window size update See Note #2d1C2
*
* (C) Also although RFC #2581, Section 3.2 states that "the TCP sender SHOULD use the
* 'fast retransmit' algorithm ... based on ... the arrival of ... 4 identical ACKs
* without the arrival of any other intervening packets"; it seems reasonable that
* the TCP fast retransmit algorithm MUST NOT consider the arrival of non-duplicate
* acknowledgement segments as "intervening packets".
*
* In other words, TCP fast retransmit MUST ignore the following TCP packets as
* duplicate acknowledgement packets :
*
* (1) TCP data segments
* (2) Remote host receive window updates
*
* (2) RFC #1122, Section 4.2.2.21 reiterates that "with this ... 'fast retransmit' ...
* algorithm, the sender uses the redundant ACK's to deduce that a segment has been
* lost before the retransmission timer has expired. If more than a threshold number
* of such ACK's is received, then the segment containing the octets starting at
* SEG.ACK is assumed to have been lost and is retransmitted, without awaiting a
* timeout".
*
* (e) (1) RFC #2581, Section 4.1 states that "after TCP has been idle for a relatively long period
* of time ... use slow start to restart transmission" :
*
* (A) (1) "If the TCP has not sent data in an interval exceeding the retransmission timeout"
* (2) "cwnd is reduced to ... no more than ... the value of the restart window"
* (see Note #2c2A1).
*
* See also 'NetTCP_TxConnTxQ_TimeoutIdle() Note #2a'.
*
* (B) Although NO RFC specifies that a TCP connection's slow start threshold should be
* reset following a TCP transmit idle timeout; it seems reasonable to reset the slow
* start threshold whenever the TCP transmit congestion window is reset.
*
* See also 'NetTCP_TxConnWinSizeCfgCongCtrl() Notes #2 & #3'.
*
* (2) RFC #1122, Section 4.2.3.9 'Source Quench' states that "TCP MUST react to a Source Quench
* by slowing transmission on the connection. The RECOMMENDED procedure is ... to trigger a
* 'slow start', as if a retransmission timeout had occurred".
*$PAGE*
* (3) (a) (1) The following sections ... :
*
* (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* ESTABLISHED STATE'
* (B) RFC #1122, Section 4.2.2.20.(c)
* (C) RFC #1122, Section 4.2.2.20.(f)
*
* (2) ... generalize that "the following variables should be set ... [when] the send
* window should be updated" :
*
* (A) SND.WND <- SEG.WND
*
* (1) A TCP connection's remote host receive window advertisements are relative
* to the received window advertisement acknowledgement sequence number, &
* are asynchronous to the TCP connection's recent transmitted sequences.
*
* Therefore, the actual transmit remote window size MUST be compensated by
* the difference in the remote host receive window advertisement & the TCP
* connection's number of recently transmitted sequences :
*
* (a) TxWinSizeRemoteActual = SEG.WIN - (SND.NXT - SEG.ACK)
*
* where
*
* TxWinSizeRemoteActual TCP connection's actual transmit
* remote window size
*
* (B) SND.WL1 <- SEG.SEQ
* (C) SND.WL2 <- SEG.ACK
*
* (b) RFC #1122, Section 4.2.3.4 'IMPLEMENTATION' states that "because the sender does not
* know (directly) the receiver's total buffer space RCV.BUFF ... An approach [that] has
* been found to work well is for the sender to calculate Max(SND.WND), the maximum send
* window it has seen so far on the connection, and to use this value as an estimate of
* RCV.BUFF".
*
* (c) RFC #1122, Section 4.2.2.17 states that although "a TCP MAY keep its offered receive
* window closed indefinitely ... the sending TCP MUST allow the connection to stay open
* ... as long as the receiving TCP continues to send acknowledgments in response to ...
* probe segments".
*
* See also 'NetTCP_TxConnWinSizeZeroWinHandler() Note #1'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnWinSizeHandlerCongCtrl (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_ACK_CODE ack_code,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_update_code,
NET_ERR *perr)
{
CPU_BOOLEAN ack_dup;
NET_TCP_WIN_SIZE tx_win_size_remote_actual;
NET_TCP_WIN_SIZE tx_win_size_remote_actual_min;
switch (win_update_code) {
case NET_TCP_CONN_TX_WIN_RESET:
default:
NetTCP_TxConnWinSizeCfgCongCtrl(pconn); /* Reset tx cong ctrls (see Note #2e). */
break;
case NET_TCP_CONN_TX_WIN_SEG_RXD:
switch (ack_code) {
case NET_TCP_CONN_RX_ACK_VALID:
/* -------------- FAST RECOVERY --------------- */
/* If valid ack rx'd after fast re-tx th, .. */
if (pconn->TxWinRxdAckDupCtr >= NET_TCP_FAST_RE_TX_ACK_DUP_TH) {
/* .. perform fast recovery (see Note #2c2B3) : */
/* .. set cong win to slow start th .. */
/* .. (see Note #2c2B3b). */
NetTCP_TxConnWinSizeCongSet(pconn, NET_TCP_CONN_TX_WIN_CONG_SET_SLOW_START);
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3). */
} else { /* -------- SLOW START / CONG AVOIDANCE ------- */
/* If cong win < slow start th .. */
/* .. (see Notes #2c2A2a), .. */
if (pconn->TxWinSizeCongCalcdActual < pconn->TxWinSizeSlowStartTh) {
/* .. perform slow start (see Note #2c2A3) : */
/* .. inc cong win by MSS (see Note #2c2A3a1). */
NetTCP_TxConnWinSizeCongInc(pconn, pbuf_hdr, 0, NET_TCP_CONN_TX_WIN_CONG_INC_SLOW_START);
} else { /* If cong win >= slow start th .. */
/* .. (see Note #2c2A2b & #2c2A2c), .. */
/* .. perform cong avoid (see Note #2c2A4) : */
/* .. inc cong win (see Note #2c2A4a2B). */
NetTCP_TxConnWinSizeCongInc(pconn, pbuf_hdr, 0, NET_TCP_CONN_TX_WIN_CONG_INC_CONG_AVOID);
}
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3A). */
}
#if 0 /* Tx avail seg(s) [see Note #2b3C]. */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
#endif
/* Reset dup ack ctrls. */
NetTCP_TxConnWinSizeDupAckCtrlUpdate(pconn, pbuf_hdr, DEF_YES);
break;
/*$PAGE*/
case NET_TCP_CONN_RX_ACK_DUP: /* -------- FAST RE-TX / FAST RECOVERY -------- */
/* Chk dup ack (see Notes #2b4 & #2d1). */
ack_dup = ((pbuf_hdr->TCP_SeqNbr == pconn->TxWinRxdLastSeqNbr ) &&
(pbuf_hdr->TCP_AckNbr == pconn->TxWinRxdLastAckNbr ) &&
(pbuf_hdr->TCP_WinSize == pconn->TxWinRxdLastWinSize) &&
(pbuf_hdr->TCP_SegLen == 0 )) ? DEF_YES : DEF_NO;
if (ack_dup == DEF_YES) { /* If dup ack, .. */
pconn->TxWinRxdAckDupCtr++; /* .. inc dup ack ctr. */
/* If equal to fast re-tx th, .. */
if (pconn->TxWinRxdAckDupCtr == NET_TCP_FAST_RE_TX_ACK_DUP_TH) {
/* .. perform fast re-tx (see Note #2c2B1) : .. */
/* .. calc slow start th (see Note #2c2B1a); .. */
NetTCP_TxConnWinSizeCalcSlowStartTh(pconn);
/* .. re-tx unack'd seg (see Note #2c2B1b); .. */
NetTCP_TxConnReTxQ(pconn, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_ERR_TX: /* Ignore transitory re-tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_TX:
case NET_TCP_ERR_RE_TX_SEG_TH:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
/* .. set cong win to fast recovery th .. */
/* .. (see Note #2c2B1c). */
NetTCP_TxConnWinSizeCongSet(pconn, NET_TCP_CONN_TX_WIN_CONG_SET_FAST_RECOVERY);
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3). */
/* Else if > fast re-tx th, .. */
} else if (pconn->TxWinRxdAckDupCtr > NET_TCP_FAST_RE_TX_ACK_DUP_TH) {
/* .. perform fast recovery (see Note #2c2B2) : */
/* .. inc cong win by MSS (see Note #2c2B2a); */
NetTCP_TxConnWinSizeCongInc(pconn, pbuf_hdr, 0, NET_TCP_CONN_TX_WIN_CONG_INC_SLOW_START);
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* .. update avail tx win (see Note #2b3) .. */
#if 0 /* .. & tx avail seg(s) [see Note #2c2B2b]. */
NetTCP_TxConnTxQ(pconn, pbuf_hdr, ack_code, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
#endif
}
} else { /* Else update dup ack ctrls (see Note #2d1C). */
NetTCP_TxConnWinSizeDupAckCtrlUpdate(pconn, pbuf_hdr, DEF_NO);
}
break;
/*$PAGE*/
case NET_TCP_CONN_RX_ACK_PREV: /* Ignore prev dup acks. */
*perr = NET_TCP_ERR_NONE;
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_RX_ACK_NONE:
case NET_TCP_CONN_RX_ACK_INVALID:
default:
*perr = NET_TCP_ERR_CONN_FAIL;
return; /* Prevent 'break NOT reachable' warning. */
}
break;
case NET_TCP_CONN_TX_WIN_TIMEOUT: /* --------------- SLOW START ----------------- */
/* On timeout (see Note #2c2A5), .. */
/* .. perform slow start (see Note #2c2A5c) : */
NetTCP_TxConnWinSizeCalcSlowStartTh(pconn); /* .. calc slow start th (see Note #2c2A5a); .. */
/* .. set cong win to timeout th .. */
/* .. (see Note #2c2A5b). */
NetTCP_TxConnWinSizeCongSet(pconn, NET_TCP_CONN_TX_WIN_CONG_SET_TIMEOUT);
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3). */
break;
case NET_TCP_CONN_TX_WIN_INC:
if (win_update_size == 0) { /* If NO win update, do NOT update win. */
break;
}
/* Inc rem cong win size. */
NetTCP_TxConnWinSizeCongInc(pconn, pbuf_hdr, win_update_size, NET_TCP_CONN_TX_WIN_CONG_INC_REM);
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3). */
break;
case NET_TCP_CONN_TX_WIN_DEC:
if (win_update_size == 0) { /* If NO win update, do NOT update win. */
break;
}
if (pconn->TxWinSizeCongRem > win_update_size) { /* If rem cong win size > win update, .. */
pconn->TxWinSizeCongRem -= win_update_size; /* .. dec cong win size by win update. */
} else {
pconn->TxWinSizeCongRem = 0; /* Else limit to min cong win size. */
}
if (pconn->TxWinSizeRemoteRem > win_update_size) { /* If rem remote win size > win update, .. */
pconn->TxWinSizeRemoteRem -= win_update_size; /* .. dec remote win size by win update. */
} else {
pconn->TxWinSizeRemoteRem = 0; /* Else limit to min remote win size. */
}
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3). */
break;
case NET_TCP_CONN_TX_WIN_REMOTE_UPDATE:
/* Calc actual tx remote win (see Note #3a2A1a).*/
tx_win_size_remote_actual = (NET_TCP_WIN_SIZE)(pbuf_hdr->TCP_WinSize - (pconn->TxSeqNbrNext - pbuf_hdr->TCP_AckNbr));
tx_win_size_remote_actual_min = (NET_TCP_WIN_SIZE) DEF_MIN(pbuf_hdr->TCP_WinSize, tx_win_size_remote_actual);
/* Update tx remote win (see Note #3a2). */
pconn->TxWinSizeRemote = (NET_TCP_WIN_SIZE) pbuf_hdr->TCP_WinSize;
pconn->TxWinSizeRemoteActual = (NET_TCP_WIN_SIZE) tx_win_size_remote_actual_min;
pconn->TxWinSizeRemoteRem = (NET_TCP_WIN_SIZE) pconn->TxWinSizeRemoteActual;
pconn->TxWinUpdateSeqNbr = (NET_TCP_SEQ_NBR ) pbuf_hdr->TCP_SeqNbr;
pconn->TxWinUpdateAckNbr = (NET_TCP_SEQ_NBR ) pbuf_hdr->TCP_AckNbr;
pconn->TxWinUpdateWinSize = (NET_TCP_WIN_SIZE) pbuf_hdr->TCP_WinSize;
if (pconn->TxWinSizeRemoteMax < pconn->TxWinSizeRemote) { /* If max < updated remote win size, ... */
pconn->TxWinSizeRemoteMax = pconn->TxWinSizeRemote; /* ... set as new max (see Note #3b). */
NetTCP_TxConnWinSizeCfgMinTh(pconn); /* Cfg new tx silly win min th. */
}
/* Handle zero win size (see Note #3c). */
NetTCP_TxConnWinSizeZeroWinHandler(pconn, NET_TCP_CONN_TX_WIN_REMOTE_UPDATE, NET_TCP_CONN_CLOSE_ALL);
NetTCP_TxConnWinSizeUpdateAvail(pconn); /* Update avail tx win (see Note #2b3). */
break;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeCalcSlowStartTh()
*
* Description : Calculate TCP connection's transmit slow start threshold.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (1) RFC #2581, Section 3.1 states that ... :
*
* (a) "the value of ssthresh MUST be set to no more than" :
*
* (3) ssthresh = max (FlightSize / 2, 2 * SMSS)
*
* (A) "FlightSize is the amount of outstanding data ... that has been sent but
* not yet acknowledged."
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2c2A5a'.
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeCalcSlowStartTh (NET_TCP_CONN *pconn)
{
NET_TCP_SEQ_NBR tx_data_unackd;
NET_TCP_SEQ_NBR tx_data_unackd_th;
NET_TCP_SEG_SIZE max_seg_size_th;
/* Calc slow start th (see Note #1a3). */
tx_data_unackd = (NET_TCP_SEQ_NBR ) (pconn->TxSeqNbrNext - pconn->TxSeqNbrUnAckd);
tx_data_unackd_th = (NET_TCP_SEQ_NBR )((tx_data_unackd * NET_TCP_SST_UNACKD_DATA_NUMER)
/ NET_TCP_SST_UNACKD_DATA_DENOM);
max_seg_size_th = (NET_TCP_SEG_SIZE)pconn->MaxSegSizeConn * NET_TCP_SST_MSS_SCALAR;
pconn->TxWinSizeSlowStartTh = (NET_TCP_WIN_SIZE)DEF_MAX(tx_data_unackd_th,
max_seg_size_th);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeCongSet()
*
* Description : Set TCP connection's transmit congestion window.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* win_inc_code Indicate how to set TCP connection transmit congestion window :
*
* NET_TCP_CONN_TX_WIN_CONG_SET_SLOW_START Set TCP connection's congestion
* control transmit window size
* based on slow start.
*
* NET_TCP_CONN_TX_WIN_CONG_SET_FAST_RECOVERY Set TCP connection's congestion
* control transmit window size
* based on fast recovery
* (see Note #1a).
*
* NET_TCP_CONN_TX_WIN_CONG_SET_TIMEOUT Set TCP connection's congestion
* control transmit window size
* based on transmission timeout
* (see Note #1b).
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (1) (a) RFC #2581, Section 3.2 states that "when the third duplicate ACK is received ...
* [for] fast recovery ... set cwnd to ssthresh plus 3*SMSS".
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2c2B1c'.
*
* (b) RFC #2581, Section 3.1 states that "when a TCP sender detects segment loss using the
* retransmission timer ... cwnd MUST be set to no more than ... 1 full-sized segment".
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2c2A5b'.
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeCongSet (NET_TCP_CONN *pconn,
NET_TCP_WIN_CODE win_inc_code)
{
NET_TCP_WIN_SIZE win_size_set;
switch (win_inc_code) {
case NET_TCP_CONN_TX_WIN_CONG_SET_SLOW_START:
win_size_set = (NET_TCP_WIN_SIZE)pconn->TxWinSizeSlowStartTh;
break;
case NET_TCP_CONN_TX_WIN_CONG_SET_FAST_RECOVERY: /* See Note #1a. */
win_size_set = (NET_TCP_WIN_SIZE)pconn->TxWinSizeSlowStartTh;
win_size_set += (NET_TCP_WIN_SIZE)pconn->MaxSegSizeConn * NET_TCP_FAST_RECOVERY_MSS_SCALAR;
break;
case NET_TCP_CONN_TX_WIN_CONG_SET_TIMEOUT: /* See Note #1b. */
default:
win_size_set = (NET_TCP_WIN_SIZE)pconn->MaxSegSizeConn * NET_TCP_CONG_WIN_MSS_SCALAR_TIMEOUT;
break;
}
pconn->TxWinSizeCongCalcdActual = win_size_set;
pconn->TxWinSizeCongCalcdCur = 0;
pconn->TxWinSizeCongRem = pconn->TxWinSizeCongCalcdActual;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeCongInc()
*
* Description : Increment TCP connection's transmit congestion window.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* win_update_size Size to increment TCP connection's transmit congestion window (in octets).
*
* win_inc_code Indicate how to increment TCP connection transmit congestion window :
*
* NET_TCP_CONN_TX_WIN_CONG_INC_SLOW_START Increment TCP connection's congestion
* control transmit window size
* based on slow start
* (see Note #1a).
*
* NET_TCP_CONN_TX_WIN_CONG_INC_CONG_AVOID Increment TCP connection's congestion
* control transmit window size
* based on congestion avoidance
* (see Note #1b).
*
* NET_TCP_CONN_TX_WIN_CONG_INC_REM Increment TCP connection's congestion
* control transmit window size
* remaining.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (1) RFC #2581, Section 3.1 states that ... :
*
* (a) "During slow start, a TCP increments cwnd by at most SMSS bytes for each ACK received
* that acknowledges new data."
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2c2A3a'.
*
* (b) "During congestion avoidance, cwnd is incremented by 1 full-sized segment per round-
* trip time (RTT) ... [An] acceptable way to increase cwnd during congestion avoidance
* is to" :
*
* (1) "Count the number of bytes that have been acknowledged by ACKs for new data."
*
* (A) The following equation calculates the number of octets that acknowledge
* new data for a TCP connection :
*
* Number of Octets Acknowledged = (SEG.ACK - SND.UNA)
*
* (B) However, since TCP connection transmit congestion controls are
* updated following any TCP connection re-transmit queue handling
* (see 'NetTCP_RxPktConnHandlerSeg() Notes #1c & #1d'); the saved
* previous value of the TCP connection's last unacknowledged
* transmit sequence number ('TxSeqNbrUnackdPrev') MUST be used
* (see 'NetTCP_RxPktConnHandlerReTxQ() Note #4').
*
* (2) "When the number of bytes acknowledged reaches cwnd," ...
* (3) "then cwnd can be incremented by up to SMSS bytes."
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2c2A4'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnWinSizeCongInc (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_WIN_SIZE win_update_size,
NET_TCP_WIN_CODE win_inc_code)
{
CPU_BOOLEAN win_size_rem_update;
NET_TCP_WIN_SIZE win_size_inc;
NET_TCP_WIN_SIZE win_size_inc_mss;
NET_TCP_WIN_SIZE win_size_inc_rem;
NET_TCP_WIN_SIZE win_size_avail;
win_size_rem_update = DEF_NO;
win_size_inc_mss = (NET_TCP_WIN_SIZE)pconn->MaxSegSizeConn * NET_TCP_CONG_WIN_MSS_SCALAR_INC;
switch (win_inc_code) {
case NET_TCP_CONN_TX_WIN_CONG_INC_SLOW_START: /* See Note #1a. */
default:
win_size_avail = NET_TCP_WIN_SIZE_MAX - pconn->TxWinSizeCongCalcdActual;
if (win_size_inc_mss < win_size_avail) { /* If inc < max avail, .. */
pconn->TxWinSizeCongCalcdActual += win_size_inc_mss; /* .. inc cong win by MSS (see Note #1a). */
} else {
pconn->TxWinSizeCongCalcdActual = NET_TCP_WIN_SIZE_MAX; /* Else set cong win to max. */
}
pconn->TxWinSizeCongCalcdCur = 0;
win_size_rem_update = DEF_YES;
win_size_inc_rem = win_size_inc_mss;
break;
case NET_TCP_CONN_TX_WIN_CONG_INC_CONG_AVOID: /* See Note #1b. */
/* Calc nbr ack'd octets (see Note #1b1). */
win_size_inc = (NET_TCP_WIN_SIZE)((NET_TCP_SEQ_NBR)pbuf_hdr->TCP_AckNbr - pconn->TxSeqNbrUnAckdPrev);
win_size_avail = NET_TCP_WIN_SIZE_MAX - pconn->TxWinSizeCongCalcdActual;
if (win_size_inc < win_size_avail) { /* If inc < max avail, .. */
pconn->TxWinSizeCongCalcdCur += win_size_inc; /* .. inc nbr ack'd octets (see Note #1b1). */
/* If >= cong win (see Note #1b2), */
/* .. inc cong win by MSS (see Note #1b3). */
if (pconn->TxWinSizeCongCalcdCur >= pconn->TxWinSizeCongCalcdActual) {
pconn->TxWinSizeCongCalcdCur -= pconn->TxWinSizeCongCalcdActual;
win_size_avail = NET_TCP_WIN_SIZE_MAX - pconn->TxWinSizeCongCalcdActual;
if (win_size_inc_mss < win_size_avail) {
pconn->TxWinSizeCongCalcdActual += win_size_inc_mss;
} else {
pconn->TxWinSizeCongCalcdActual = NET_TCP_WIN_SIZE_MAX;
}
/* Cfg rem cong win inc by MSS. */
win_size_rem_update = DEF_YES;
win_size_inc_rem = win_size_inc_mss;
}
} else { /* Else set cong win to max. */
pconn->TxWinSizeCongCalcdActual = NET_TCP_WIN_SIZE_MAX;
win_size_avail = NET_TCP_WIN_SIZE_MAX - pconn->TxWinSizeCongCalcdCur;
if (win_size_inc < win_size_avail) { /* If inc < max avail, .. */
pconn->TxWinSizeCongCalcdCur += win_size_inc; /* .. inc nbr ack'd octets (see Note #1b1). */
} else { /* Else set nbr ack'd octets to inc ovf ... */
pconn->TxWinSizeCongCalcdCur = win_size_inc - win_size_avail;
/* ... & cfg rem cong win inc by MSS. */
win_size_rem_update = DEF_YES;
win_size_inc_rem = win_size_inc_mss;
}
}
break;
case NET_TCP_CONN_TX_WIN_CONG_INC_REM: /* Cfg rem cong win inc by win update size. */
win_size_rem_update = DEF_YES;
win_size_inc_rem = win_update_size;
break;
}
if (win_size_rem_update == DEF_YES) { /* If rem tx cong win update req'd ... */
if (pconn->TxWinSizeCongRem < pconn->TxWinSizeCongCalcdActual) { /* ... & < actual tx cong win size, ... */
/* ... inc rem tx cong win size. */
win_size_avail = pconn->TxWinSizeCongCalcdActual - pconn->TxWinSizeCongRem;
if (win_size_inc_rem < win_size_avail) { /* If avail win size > rem inc, ... */
pconn->TxWinSizeCongRem += win_size_inc_rem; /* ... inc rem tx cong win size by rem inc. */
} else { /* Else limit to actual tx cong win size. */
pconn->TxWinSizeCongRem = pconn->TxWinSizeCongCalcdActual;
}
}
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeUpdateAvail()
*
* Description : Update TCP connection's available transmit window.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeCfgCongCtrl(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (1) (a) RFC #2001, Section 1 states that "the sender can transmit up to the minimum
* of the congestion window and the advertised window."
*
* (b) RFC #2001, Section 2.2 reiterates that "the TCP output routine never sends
* more than the minimum of cwnd and the receiver's advertised window".
*
* (c) RFC #2581, Section 3.1 also reiterates that "the minimum of cwnd and rwnd
* [receiver's advertised window] governs data transmission".
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2b3'.
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeUpdateAvail (NET_TCP_CONN *pconn)
{
/* Calc avail tx win (see Note #1). */
pconn->TxWinSizeAvail = DEF_MIN(pconn->TxWinSizeCongRem,
pconn->TxWinSizeRemoteRem);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeDupAckCtrlReset()
*
* Description : Reset TCP connection's transmit window duplicate acknowledgement controls.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeCfgCongCtrl().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeCfgCongCtrl().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeDupAckCtrlReset (NET_TCP_CONN *pconn)
{
pconn->TxWinRxdLastSeqNbr = pconn->RxSeqNbrNext;
pconn->TxWinRxdLastAckNbr = pconn->TxSeqNbrNext;
pconn->TxWinRxdLastWinSize = pconn->TxWinSizeRemote;
pconn->TxWinRxdAckDupCtr = 0;
}
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeDupAckCtrlUpdate()
*
* Description : Update TCP connection's transmit window duplicate acknowledgement controls.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* reset_ctr Indicate whether to reset the duplicate acknowledgement counter :
*
* DEF_YES Reset duplicate acknowledgement counter.
* DEF_NO Do NOT reset duplicate acknowledgement counter.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_TxConnWinSizeDupAckCtrlUpdate (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
CPU_BOOLEAN reset_ctr)
{
pconn->TxWinRxdLastSeqNbr = (NET_TCP_SEQ_NBR )pbuf_hdr->TCP_SeqNbr;
pconn->TxWinRxdLastAckNbr = (NET_TCP_SEQ_NBR )pbuf_hdr->TCP_AckNbr;
pconn->TxWinRxdLastWinSize = (NET_TCP_WIN_SIZE)pbuf_hdr->TCP_WinSize;
if (reset_ctr == DEF_YES) {
pconn->TxWinRxdAckDupCtr = 0;
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeZeroWinHandler()
*
* Description : Handle TCP connection's transmit queue zero window.
*
* Argument(s) : pconn Pointer to TCP connection.
* ----- Argument validated in NetTCP_TxConnWinSizeHandlerCongCtrl(),
* NetTCP_TxConnWinSizeZeroWinTimeout().
*
* win_update_code Indicate how to update TCP connection transmit window :
*
* NET_TCP_CONN_TX_WIN_REMOTE_UPDATE Handle TCP connection's remote
* receive window size update.
* NET_TCP_CONN_TX_WIN_TIMEOUT Handle TCP connection's remote
* receive zero window size timeout.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeZeroWinTimeout(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* Note(s) : (1) RFC #1122, Section 4.2.2.17 states that although "a TCP MAY keep its offered receive
* window closed indefinitely ... the sending TCP MUST allow the connection to stay open
* ... as long as the receiving TCP continues to send acknowledgments in response to ...
* probe segments".
*
* (a) "Probing of zero (offered) windows MUST be supported."
*
* (1) "If zero window probing is not supported, a connection may hang forever when an
* ACK segment that re-opens the window is lost."
*
* See also Note #1c2.
*
* (b) (1) "The transmitting host SHOULD send the first zero-window probe" ...
*
* (A) Although NO RFC specifies whether a TCP zero window probe should or should NOT
* include data; Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 22.1,
* Page 325 states that "the window probes contain 1 byte of data".
*
* (2) (A) "when a zero window has existed for the retransmission timeout period," ...
*
* (B) "and SHOULD increase exponentially the interval between successive probes."
*
* (1) "Exponential backoff is recommended ... similar to ... the retransmission
* algorithm, and it may be possible to combine the two procedures in the
* implementation."
*
* See also 'NetTCP_TxConnRTO_CalcBackOff() Notes #1 & #2'.
*
* (c) (1) "It is extremely important to remember that ACK (acknowledgment) segments that
* contain no data are not reliably transmitted by TCP."
*
* (2) "This procedure minimizes delay if the zero-window condition is due to a lost
* ACK segment containing a window-opening update."
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnWinSizeZeroWinHandler (NET_TCP_CONN *pconn,
NET_TCP_WIN_CODE win_update_code,
NET_TCP_CLOSE_CODE close_code)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_BOOLEAN tmr_update;
NET_TCP_TIMEOUT_MS timeout_ms;
NET_TMR_TICK timeout_tick;
NET_ERR err;
/* ----------- VALIDATE TCP CONN STATE ------------ */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* --------- HANDLE TCP CONN TX ZERO WIN ---------- */
tmr_update = DEF_NO;
switch (win_update_code) {
case NET_TCP_CONN_TX_WIN_REMOTE_UPDATE:
default:
if (pconn->TxWinSizeRemote > 0) { /* If remote win size > 0, ... */
if (pconn->TxQ_ZeroWinTmr != (NET_TMR *)0) { /* ... free zero win tmr. */
NetTmr_Free(pconn->TxQ_ZeroWinTmr);
pconn->TxQ_ZeroWinTmr = (NET_TMR *)0;
}
} else { /* Else if remote win size zero ... */
if (pconn->TxQ_ZeroWinTmr != (NET_TMR *)0) { /* ... & NO zero win tmr; ... */
/* ... set first tx zero win probe timeout ... */
timeout_ms = pconn->TxRTT_RTO_ms; /* ... = RTO (see Note #1b2A). */
timeout_tick = pconn->TxRTT_RTO_tick;
tmr_update = DEF_YES;
}
}
break;
case NET_TCP_CONN_TX_WIN_TIMEOUT: /* On timeout : ... */
/* ... tx TCP zero win probe (see Note #1b1); ... */
NetTCP_TxConnProbe((NET_TCP_CONN *) pconn,
(CPU_BOOLEAN ) DEF_YES, /* Tx probe with data (see Note #1b1A). */
(NET_TCP_CLOSE_CODE) close_code,
(NET_ERR *)&err); /* Ignore transitory tx err(s). */
/* ... update tx probe timeout (see Note #1b2B). */
timeout_ms = (NET_TCP_TIMEOUT_MS )NetTCP_TxConnRTO_CalcBackOff(pconn, pconn->TxWinZeroWinTimeout_ms);
timeout_tick = ((NET_TMR_TICK )timeout_ms * NET_TMR_TIME_TICK_PER_SEC) / DEF_TIME_NBR_mS_PER_SEC;
tmr_update = DEF_YES;
break;
}
if (tmr_update == DEF_YES) { /* If tx probe tmr update req'd, ... */
/* ... get tx zero win probe tmr. */
pconn->TxQ_ZeroWinTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_TxConnWinSizeZeroWinTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
if (err == NET_TMR_ERR_NONE) { /* If NO err(s), cfg tx zero win probe timeout. */
pconn->TxWinZeroWinTimeout_ms = timeout_ms;
} /* Else ignore transitory rsrc err(s) ... */
/* ... [see Note #1a1]. */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnWinSizeZeroWinTimeout()
*
* Description : (1) (a) Handle TCP connection's transmit queue zero window persist timeout ... :
*
* (1) Clear TCP connection's transmit zero window persist timer See Note #4aA1
* (2) Handle TCP connection transmit zero window See Note #2
*
* (b) ... for the following states :
*
* (1) ESTABLISHED
* (2) FIN-WAIT-1
* (3) CLOSING
* (4) CLOSE-WAIT
* (5) LAST-ACK
*
*
* Argument(s) : pconn_timeout Pointer to TCP connection (see Note #3b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_TxConnWinSizeZeroWinHandler().
*
* Note(s) : (2) RFC #1122, Section 4.2.2.17 states that the "probing of zero (offered) windows
* ... SHOULD send the first zero-window probe when a zero window has existed for
* the retransmission timeout period and SHOULD increase exponentially the interval
* between successive probes".
*
* See also 'NetTCP_TxConnWinSizeZeroWinHandler() Note #1'.
*
* (3) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (4) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) ... :
*
* (A) TCP connection transmit zero window persist timer ('TxQ_ZeroWinTmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared prior to next handler function(s) as an extra precaution to
* avoiding re-freeing the timer (see Note #4a2B).
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN
*
* (5) Certain network connections MUST periodically suspend network transmit(s) to handle
* network receive packet(s). To protect TCP connections from transmit corruption while
* suspended, ALL TCP data transmits & TCP transmit queue handling MUST be blocked for
* suspended connections until the connection is no longer suspended.
*
* However, handling the TCP connection's transmit zero window timeout is permitted since
* NO TCP data is transmitted & the TCP connection's transmit queue is NOT handled (see
* Note #1a).
*
* See also 'NetTCP_TxConnTxQ() Note #10b2A2',
* 'NetTCP_TxConnTxQ_TimeoutIdle() Note #5',
* 'NetTCP_TxConnTxQ_TimeoutSillyWin() Note #5',
* & 'NetTCP_TxConnReTxQ_Timeout() Note #5'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnWinSizeZeroWinTimeout (void *pconn_timeout)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CLOSE_CODE close_code;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #3b2A. */
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN); /* See Note #4b1. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* -------------- VALIDATE TCP CONN --------------- */
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CONN: /* See Note #1. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* See Note #5. */
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* ----- HANDLE TCP CONN TX ZERO WIN TIMEOUT ------ */
pconn->TxQ_ZeroWinTmr = (NET_TMR *)0; /* Clr tx Q zero win tmr (see Note #4a2A1). */
/* Handle tx zero win (see Note #2). */
NetTCP_TxConnWinSizeZeroWinHandler(pconn, NET_TCP_CONN_TX_WIN_TIMEOUT, close_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnSync()
*
* Description : (1) Prepare & transmit TCP connection synchronization :
*
* (a) Validate TCP connection state
* (b) Prepare TCP connection synchronization :
* (1) Get timer
* (2) Get buffer
* (3) Prepare TCP segment :
* (A) TCP segment addresses
* (B) TCP segment sequence numbers
* (C) TCP segment transmit flags :
*- (1) SYN
* (2) ACK
* (D) TCP segment window size
* (E) TCP segment options
* (F) IP datagram parameters
* (G) TCP segment packet buffer controls
* (c) Update TCP connection :
* (1) Queue TCP connection synchronization packet
* (2) Update TCP connection sequence numbers
* (d) Transmit TCP connection synchronization
*
*
* (2) (a) RFC #793, Section 3.3 'Sequence Numbers : Initial Sequence Number Selection' states
* that "for a [TCP] connection to be established or initialized, ... two TCP's must
* synchronize ... each other's initial sequence numbers" by transmitting initial
* connection request segments (i.e., segments with the SYN control bit set).
*
* RFC #793, Section 3.4 states that "this procedure normally is initiated by one TCP
* and responded to by another TCP ... [but] works if two TCP simultaneously initiate
* the procedure".
*
* (b) RFC #793, Section 3.9 'Event Processing : OPEN Call : CLOSED STATE' states that after
* "a SYN segment ... is sent ... [to] set SND.UNA to ISS [initial send sequence number],
* SND.NXT to ISS+1".
*
* The following sections confirm these sequence number configurations summary :
*
* (1) RFC #793, Section 3.9 'Event Processing : OPEN Call : LISTEN STATE'
* (2) RFC #793, Section 3.9 'Event Processing : SEND Call : LISTEN STATE'
* (3) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for SYN'
*
* (3) A TCP connection's transmit sequences are initialized when the initial TCP synchronization
* segment is queued for transmission :
*
* (a) 'TxSeqNbrSync' points to the initial, synchronization (SYN) transmit sequence number.
*
* (b) (1) 'TxSeqNbrNextQ' points to the next transmit sequence number to enqueue data octets.
* (2) 'TxSeqNbrNext' points to the next transmit sequence number to transmit.
*
*
* ----- ------------------------ Initial Synchronization
* ^ | Initial SEQ # (SYN) | <--- Transmit Sequence Number
* | ------------------------ (see Note #3a)
* | | Data Octet # 1 | ---
* | | Data Octet # 2 | ^
* | | Data Octet # 3 | |
* | . | | Next / Queued
* TCP Connection | . | | Transmit Sequence Number(s)
* Transmit Sequences | . | | (see Note #3b)
* (see Note #3) | Data Octet # (N - 2) | |
* | Data Octet # (N - 1) | v
* | | Data Octet # N | ---
* | ------------------------
* | | Close SEQ # (FIN) |
* | ------------------------
* v | Last SEQ # |
* ----- ------------------------
*
*
* See also 'NetTCP_TxConnClose() Note #2'.
*
*
*$PAGE*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnReq(),
* NetTCP_RxPktConnHandlerListen().
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection synchronization successfully
* transmitted.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* - RETURNED BY NetTCP_TxConnReTxQ_TimeoutSet() : -
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
*
* - RETURNED BY NetTCP_TxConnPrepareSegAddrs() : --
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* ------ RETURNED BY NetTCP_TxPktHandler() : ------
* NET_TCP_ERR_TX TCP transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnReq(),
* NetTCP_RxPktConnHandlerListen(),
* NetTCP_RxPktConnHandlerSyncTxd().
*
* Note(s) : (4) RFC #1122, Section 4.2.2.6 states that a "TCP SHOULD send an MSS (Maximum Segment Size)
* option in every SYN segment".
*
* (5) Network resources MUST be appropriately allocated/deallocated :
*
* (a) Increment network buffer's reference counter to include the queued TCP connection
* synchronization as a new reference to the network buffer.
*
* (b) On ANY errors, network resources MUST be appropriately freed :
*
* (1) For any network resources NOT yet linked to the TCP connection, each
* network resource MUST be freed by appropriate function(s).
* (2) For all network resources that have been linked to the TCP connection, ALL
* network resources are freed by NetTCP_ConnClose().
*
* (6) If transmitting a TCP synchronization packet from the SYN-SENT state :
*
* (a) Connection timeout is reset to initial synchronization timeout value
* (b) Previous synchronization sequence number MUST be re-used
* (c) Previous synchronization packet in TCP connection's re-transmit queue is freed
*
* See also 'NetTCP_RxPktConnHandlerSyncTxd() Note #2c3B2'.
*
* (7) #### IP options currently NOT implemented.
*********************************************************************************************************
*/
static void NetTCP_TxConnSync (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_ERR *perr)
{
#if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)
CPU_SR cpu_sr;
#endif
NET_BUF_SIZE data_len;
NET_BUF_SIZE data_ix;
NET_BUF *pseg_sync;
NET_BUF_HDR *pseg_sync_hdr;
NET_IP_TOS TOS;
NET_IP_TTL TTL;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR ack_nbr;
NET_TCP_WIN_SIZE win_size;
NET_TCP_OPT_CFG_MAX_SEG_SIZE *popt_cfg_max_seg_size;
NET_TCP_OPT_CFG_MAX_SEG_SIZE opt_cfg_max_seg_size;
CPU_INT16U flags_tcp;
CPU_INT16U flags_ip;
NET_ERR err;
/*$PAGE*/
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ----------- VALIDATE TCP CONN STATE ------------ */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_TXD:
break;
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, NET_TCP_CONN_CLOSE_CONN_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* ----------- PREPARE TCP CONN SYNC SEG ---------- */
/* ------------------- GET TMR -------------------- */
NetTCP_TxConnReTxQ_TimeoutSet(pconn, DEF_NO, NET_TCP_CONN_CLOSE_ALL, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ------------------- GET BUF -------------------- */
data_len = NET_TCP_DATA_LEN_TX_SYNC;
data_ix = NET_BUF_DATA_TX_IX;
pseg_sync = NetBuf_Get((NET_BUF_SIZE) data_len,
(NET_BUF_SIZE) data_ix,
(CPU_INT16U ) NET_BUF_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) { /* See Note #5b1. */
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
/*$PAGE*/
/* --------------- PREPARE TCP HDR ---------------- */
/* Prepare seg addrs. */
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If TCP pkt rx'd, cfg TCP tx ... */
/* ... src addr from rx'd TCP pkt dest addr ... */
src_port = (NET_TCP_PORT_NBR)pbuf_hdr->TCP_UDP_PortDest;
src_addr = (NET_IP_ADDR )pbuf_hdr->IP_AddrDest;
/* .. & dest addr from rx'd TCP pkt src addr. */
dest_port = (NET_TCP_PORT_NBR)pbuf_hdr->TCP_UDP_PortSrc;
dest_addr = (NET_IP_ADDR )pbuf_hdr->IP_AddrSrc;
} else { /* Else cfg TCP tx pkt addrs from TCP conn addrs. */
NetTCP_TxConnPrepareSegAddrs((NET_TCP_CONN *) pconn,
(CPU_INT08U *)&src_port,
(CPU_INT08U *)&src_addr,
(CPU_INT16U ) sizeof(src_port),
(CPU_INT16U ) sizeof(src_addr),
(CPU_INT08U *)&dest_port,
(CPU_INT08U *)&dest_addr,
(CPU_INT16U ) sizeof(dest_port),
(CPU_INT16U ) sizeof(dest_addr),
(NET_ERR *) perr);
if (*perr != NET_TCP_ERR_NONE) { /* See Note #5b1. */
NetBuf_Free(pseg_sync);
return;
}
}
/* Prepare TCP sync seq nbrs. */
if (pconn->ConnState != NET_TCP_CONN_STATE_SYNC_TXD) { /* For non-sync-tx'd states (see Note #6b), ... */
NET_TCP_TX_GET_SEQ_NBR(seq_nbr); /* ... get sync seq nbr. */
} else {
seq_nbr = pconn->TxSeqNbrSync;
}
ack_nbr = (pconn->ConnState != NET_TCP_CONN_STATE_CLOSED) ? pconn->RxSeqNbrNext
: NET_TCP_ACK_NBR_NONE;
/* Prepare TCP tx flags (see Note #1b3C). */
flags_tcp = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_SYNC;
if (pconn->ConnState != NET_TCP_CONN_STATE_CLOSED) { /* For non-CLOSED state, ... */
DEF_BIT_SET(flags_tcp, NET_TCP_FLAG_TX_ACK); /* ... tx ACK. */
}
/* Prepare TCP rx win size. */
win_size = pconn->RxWinSizeActual;
/* Prepare TCP max seg size opt (see Note #4). */
popt_cfg_max_seg_size = &opt_cfg_max_seg_size;
popt_cfg_max_seg_size->Type = NET_TCP_OPT_CFG_TYPE_MAX_SEG_SIZE;
popt_cfg_max_seg_size->MaxSegSize = pconn->MaxSegSizeLocal;
popt_cfg_max_seg_size->NextOptPtr = (void *)0;
/* Prepare IP params. */
TOS = pconn->TxIP_TOS;
TTL = pconn->TxIP_TTL;
flags_ip = pconn->TxIP_Flags;
/*$PAGE*/
/* Init buf ctrls. */
pseg_sync_hdr = &pseg_sync->Hdr;
pseg_sync_hdr->DataIx = (CPU_INT16U )data_ix;
pseg_sync_hdr->DataLen = (NET_BUF_SIZE)data_len;
pseg_sync_hdr->TotLen = (NET_BUF_SIZE)pseg_sync_hdr->DataLen;
pseg_sync_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
pseg_sync_hdr->TCP_UDP_PortSrc = (NET_PORT_NBR)src_port;
pseg_sync_hdr->IP_AddrSrc = (CPU_INT32U )src_addr;
pseg_sync_hdr->TCP_UDP_PortDest = (NET_PORT_NBR)dest_port;
pseg_sync_hdr->IP_AddrDest = (CPU_INT32U )dest_addr;
pseg_sync_hdr->TCP_SegLenInit = (CPU_INT16U )NET_TCP_SEG_LEN_SYNC;
pseg_sync_hdr->TCP_SegLen = (CPU_INT16U )pseg_sync_hdr->TCP_SegLenInit;
pseg_sync_hdr->TCP_SegLenLast = (CPU_INT16U )pseg_sync_hdr->TCP_SegLenInit;
pseg_sync_hdr->TCP_SegLenData = (CPU_INT16U )0;
pseg_sync_hdr->TCP_SegSync = (CPU_BOOLEAN )DEF_YES;
pseg_sync_hdr->TCP_SegClose = (CPU_BOOLEAN )DEF_NO;
pseg_sync_hdr->TCP_SegAck = (CPU_BOOLEAN )DEF_BIT_IS_SET(flags_tcp, NET_TCP_FLAG_TX_ACK);
pseg_sync_hdr->TCP_SegReset = (CPU_BOOLEAN )DEF_NO;
pseg_sync_hdr->TCP_SeqNbrInit = (CPU_INT32U )seq_nbr;
pseg_sync_hdr->TCP_SeqNbrLast = (CPU_INT32U )pseg_sync_hdr->TCP_SeqNbrInit;
pseg_sync_hdr->TCP_SeqNbr = (CPU_INT32U )pseg_sync_hdr->TCP_SeqNbrInit;
pseg_sync_hdr->TCP_AckNbr = (CPU_INT32U )ack_nbr;
pseg_sync_hdr->TCP_AckNbrLast = (CPU_INT32U )pseg_sync_hdr->TCP_AckNbr;
pseg_sync_hdr->TCP_WinSizeLast = (CPU_INT16U )win_size;
pseg_sync_hdr->TCP_Flags = (CPU_INT16U )flags_tcp;
pseg_sync_hdr->TCP_SegReTxCtr = (CPU_INT16U )0;
pseg_sync_hdr->RefCtr++; /* TCP maintains ref until seg ack'd (see Note #5a).*/
/* --------------- UPDATE TCP CONN ---------------- */
/* Q conn sync seg to TCP re-tx Q. */
NetTCP_ConnFreeBufQ(&pconn->ReTxQ_Head, &pconn->ReTxQ_Tail); /* Free re-tx Q (see Note #6c). */
pconn->ReTxQ_Head = pseg_sync;
pconn->ReTxQ_Tail = pseg_sync;
/* Update TCP conn seq nbrs (see Notes #2 & #3). */
pconn->TxSeqNbrSync = (NET_TCP_SEQ_NBR) seq_nbr;
pconn->TxSeqNbrNext = (NET_TCP_SEQ_NBR)(seq_nbr + pseg_sync_hdr->TCP_SegLen);
pconn->TxSeqNbrNextQ = (NET_TCP_SEQ_NBR) pconn->TxSeqNbrNext;
pconn->TxSeqNbrUnAckdPrev = (NET_TCP_SEQ_NBR) pconn->TxSeqNbrUnAckd;
pconn->TxSeqNbrUnAckd = (NET_TCP_SEQ_NBR) pconn->TxSeqNbrSync;
pconn->TxSeqNbrUnReTxd = (NET_TCP_SEQ_NBR) pconn->TxSeqNbrUnAckd;
/* ------------- TX TCP CONN SYNC SEG ------------- */
NetTCP_TxPktHandler((NET_BUF *)pseg_sync,
(NET_IP_ADDR )src_addr,
(NET_TCP_PORT_NBR)src_port,
(NET_IP_ADDR )dest_addr,
(NET_TCP_PORT_NBR)dest_port,
(NET_TCP_SEQ_NBR )seq_nbr,
(NET_TCP_SEQ_NBR )ack_nbr,
(NET_TCP_WIN_SIZE)win_size,
(NET_IP_TOS )TOS,
(NET_IP_TTL )TTL,
(CPU_INT16U )flags_tcp,
(CPU_INT16U )flags_ip,
(void *)popt_cfg_max_seg_size,
(void *)0, /* See Note #7. */
(NET_ERR *)perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_ERR_INIT_INCOMPLETE:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
NET_CTR_STAT_INC(NetTCP_StatTxSegConnSyncCtr);
break;
case NET_TCP_ERR_TX:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, NET_TCP_CONN_CLOSE_CONN_ALL);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnClose()
*
* Description : (1) Prepare & transmit TCP connection close :
*
* (a) Validate TCP connection state
* (b) Prepare TCP connection close segment :
* (1) Get buffer
* (2) Prepare TCP segment :
* (A) TCP segment addresses
* (B) TCP segment sequence numbers
* (C) TCP segment transmit flags :
* (1) ACK
* (2) FIN
* (D) TCP segment window size
* (E) IP datagram parameters
* (F) TCP segment packet buffer controls
* (c) Update TCP connection :
* (1) Queue TCP connection close packet
* (2) Update TCP connection sequence number(s)
* (d) Transmit TCP connection close segment
*
*
* (2) A TCP connection's transmit sequences are closed when the closing TCP segment is queued
* for transmission :
*
* (a) 'TxSeqNbrClose' points to the closing (FIN) transmit sequence number.
*
* (b) 'TxSeqNbrLast' points to the last sequence number used to close the TCP connection
* transmit sequences when acknowledged.
*
*
* ----- ------------------------
* ^ | Initial SEQ # (SYN) |
* | ------------------------
* | | Data Octet # 1 |
* | | Data Octet # 2 |
* | | Data Octet # 3 |
* | . |
* TCP Connection | . |
* Transmit Sequences | . |
* (see Note #2) | Data Octet # (N - 2) |
* | Data Octet # (N - 1) |
* | | Data Octet # N | Closing Transmit
* | ------------------------ Sequence Number
* | | Close SEQ # (FIN) | <--- (see Note #2a)
* | ------------------------
* v | Last SEQ # | <--- Last Transmit
* ----- ------------------------ Sequence Number
* (see Note #2b)
*
*
* See also 'NetTCP_TxConnSync() Note #3'.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnReqClose().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection close successfully
* transmitted.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* ------- RETURNED BY NetTCP_TxConnTxQ() : -------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_CONN_ACK_INVALID TCP connection acknowledgement NOT valid for
* current TCP connection state.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
* NET_TCP_ERR_TX TCP transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnReqClose().
*$PAGE*
* Note(s) : (3) Network resources MUST be appropriately allocated/deallocated :
*
* (a) Network buffer's reference counter MUST include the queued TCP connection close as a
* new reference to the network buffer. However, this additional reference is handled
* by the TCP connection transmit queue (see 'NetTCP_TxConnTxQ() Note #9').
*
* (b) On ANY errors, network resources MUST be appropriately freed :
*
* (1) For any network resources NOT yet linked to the TCP connection, each network
* resource MUST be freed by appropriate function(s).
* (2) For all network resources that have been linked to the TCP connection, ALL network
* resources are freed by NetTCP_ConnClose().
*
* (4) Network buffer's reference counter must be incremented to include the TCP connection close
* segment to be enqueued to the TCP connection's re-transmit queue as a new reference to the
* network buffer.
*
* However, NetTCP_TxConnTxQ() handles the reference counter increment when it enqueues the
* TCP connection close segment queued to the TCP connection's re-transmit queue.
*
* See 'NetTCP_TxConnTxQ() Note #9'.
*********************************************************************************************************
*/
static void NetTCP_TxConnClose (NET_TCP_CONN *pconn,
NET_ERR *perr)
{
#if ((((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) || \
(NET_CTR_CFG_STAT_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_SEG_SIZE seg_len;
NET_BUF_SIZE data_len;
NET_BUF_SIZE data_ix;
NET_BUF *pseg_close;
NET_BUF_HDR *pseg_close_hdr;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
CPU_INT16U flags_tcp;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ----------- VALIDATE TCP CONN STATE ------------ */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/*$PAGE*/
/* ---------- PREPARE TCP CONN CLOSE SEG ---------- */
seg_len = NET_TCP_SEG_LEN_CLOSE;
data_len = NET_TCP_DATA_LEN_TX_CLOSE;
if (pconn->TxQ_Tail != (NET_BUF *)0) { /* If tx Q NOT empty ... */
pseg_close = pconn->TxQ_Tail; /* ... update tx Q tail seg as close seg. */
pseg_close_hdr = &pseg_close->Hdr;
pseg_close_hdr->DataLen += (NET_BUF_SIZE)data_len;
pseg_close_hdr->TotLen += (NET_BUF_SIZE)data_len;
pseg_close_hdr->TCP_SegLenInit += (CPU_INT16U )seg_len;
pseg_close_hdr->TCP_SegLen += (CPU_INT16U )seg_len;
pseg_close_hdr->TCP_SegLenData += (CPU_INT16U )data_len;
DEF_BIT_SET(pseg_close_hdr->TCP_Flags, NET_TCP_FLAG_TX_CLOSE);
} else { /* Else get/cfg close seg buf. */
/* Get buf. */
data_ix = NET_BUF_DATA_TX_IX;
pseg_close = NetBuf_Get((NET_BUF_SIZE) data_len,
(NET_BUF_SIZE) data_ix,
(CPU_INT16U ) NET_BUF_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) {
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
/* --------------- PREPARE TCP HDR ---------------- */
/* Prepare seg addrs. */
NetTCP_TxConnPrepareSegAddrs((NET_TCP_CONN *) pconn,
(CPU_INT08U *)&src_port,
(CPU_INT08U *)&src_addr,
(CPU_INT16U ) sizeof(src_port),
(CPU_INT16U ) sizeof(src_addr),
(CPU_INT08U *)&dest_port,
(CPU_INT08U *)&dest_addr,
(CPU_INT16U ) sizeof(dest_port),
(CPU_INT16U ) sizeof(dest_addr),
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) { /* See Note #3b1. */
*perr = NET_TCP_ERR_CONN_FAULT;
NetBuf_Free(pseg_close);
return;
}
/* Prepare TCP seq nbr(s). */
seq_nbr = pconn->TxSeqNbrNextQ;
/* Prepare TCP tx flags (see Note #1b2C). */
flags_tcp = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_ACK |
NET_TCP_FLAG_TX_CLOSE;
/* Init buf ctrls. */
pseg_close_hdr = &pseg_close->Hdr;
pseg_close_hdr->DataIx = (CPU_INT16U )data_ix;
pseg_close_hdr->DataLen = (NET_BUF_SIZE)data_len;
pseg_close_hdr->TotLen = (NET_BUF_SIZE)pseg_close_hdr->DataLen;
pseg_close_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
pseg_close_hdr->TCP_UDP_PortSrc = (NET_PORT_NBR)src_port;
pseg_close_hdr->IP_AddrSrc = (CPU_INT32U )src_addr;
pseg_close_hdr->TCP_UDP_PortDest = (NET_PORT_NBR)dest_port;
pseg_close_hdr->IP_AddrDest = (CPU_INT32U )dest_addr;
pseg_close_hdr->TCP_SegLenInit = (CPU_INT16U )seg_len;
pseg_close_hdr->TCP_SegLen = (CPU_INT16U )pseg_close_hdr->TCP_SegLenInit;
pseg_close_hdr->TCP_SegLenData = (CPU_INT16U )data_len;
pseg_close_hdr->TCP_SegSync = (CPU_BOOLEAN )DEF_NO;
pseg_close_hdr->TCP_SegClose = (CPU_BOOLEAN )DEF_YES;
pseg_close_hdr->TCP_SegAck = (CPU_BOOLEAN )DEF_YES;
pseg_close_hdr->TCP_SegReset = (CPU_BOOLEAN )DEF_NO;
pseg_close_hdr->TCP_SeqNbrInit = (CPU_INT32U )seq_nbr;
pseg_close_hdr->TCP_SeqNbr = (CPU_INT32U )pseg_close_hdr->TCP_SeqNbrInit;
pseg_close_hdr->TCP_Flags = (CPU_INT16U )flags_tcp;
}
/*$PAGE*/
/* --------------- UPDATE TCP CONN ---------------- */
/* Q conn close seg to TCP tx Q : ... */
if (pconn->TxQ_Tail == (NET_BUF *)0) { /* ... if tx Q empty, add close seg to empty tx Q. */
pconn->TxQ_Head = (NET_BUF *)pseg_close;
pconn->TxQ_Tail = (NET_BUF *)pseg_close;
}
/* Update TCP conn seq nbrs (see Note #2). */
pconn->TxSeqNbrNextQ += (NET_TCP_SEQ_NBR) seg_len; /* Update next tx Q seq nbr by close seg len. */
pconn->TxSeqNbrLast = (NET_TCP_SEQ_NBR) pconn->TxSeqNbrNextQ;
pconn->TxSeqNbrClose = (NET_TCP_SEQ_NBR)(pconn->TxSeqNbrLast - seg_len);
/* ------------ TX TCP CONN CLOSE SEG ------------- */
NetTCP_TxConnTxQ((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_ACK_CODE )NET_TCP_CONN_TX_ACK_NONE,
(CPU_BOOLEAN )DEF_NO,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL,
(NET_ERR *)perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_TCP_ERR_CONN_ACK_NONE:
case NET_TCP_ERR_CONN_ACK_INVALID:
case NET_TCP_ERR_CONN_ACK_DLYD:
case NET_TCP_ERR_CONN_ACK_PREVLY_TXD:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_CONN_NOT_USED:
case NET_TCP_ERR_CONN_CLOSE:
case NET_TCP_ERR_CONN_FAULT:
case NET_TCP_ERR_CONN_FAIL:
case NET_TCP_ERR_INVALID_CONN_STATE:
case NET_TCP_ERR_INVALID_CONN_OP:
case NET_TCP_ERR_INVALID_LEN_SEG:
case NET_TCP_ERR_NONE_AVAIL:
case NET_TCP_ERR_TX:
case NET_CONN_ERR_INVALID_FAMILY:
case NET_CONN_ERR_INVALID_ADDR:
case NET_CONN_ERR_INVALID_ADDR_LEN:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
NET_CTR_STAT_INC(NetTCP_StatTxSegConnCloseCtr);
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnAck()
*
* Description : (1) Prepare & transmit a TCP connection acknowledgement :
*
* (a) Validate TCP connection for TCP acknowledgement See Notes #2, #4, #5, & #6
* (b) Prepare TCP acknowledgement segment :
* (1) Get buffer
* (2) Prepare TCP segment :
* (A) TCP segment addresses
* (B) TCP segment sequence numbers See Notes #4a1D1a1, #4a2A1
* & #4a1D3b1B,
* (C) TCP segment transmit flags :
* (1) ACK
* (D) TCP segment window size
* (E) IP datagram parameters
* (F) TCP segment packet buffer controls
* (c) Transmit TCP connection acknowledgement
*
*
* (2) NetTCP_TxConnAck() transmits TCP connection acknowledgements in response to certain
* received TCP packets or TCP connection events (see Note #4). TCP acknowledgements
* transmitted with other TCP controls &/or data SHOULD NOT be transmitted with
* NetTCP_TxConnAck().
*
* See also 'NetTCP_TxConnTxQ() Note #2'.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in various.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
* -------- Argument validated in NetTCP_Rx().
*
* tx_ack_code Indicate whether & how to transmit a TCP acknowledgement segment :
*
* NET_TCP_CONN_TX_ACK_NONE Do NOT transmit a TCP acknowledgement segment.
* NET_TCP_CONN_TX_ACK Transmit a TCP acknowledgement segment.
* NET_TCP_CONN_TX_ACK_IMMED Transmit a TCP acknowledgement segment
* immediately (see Note #4a5).
* NET_TCP_CONN_TX_ACK_FAULT Transmit a TCP acknowledgement segment
* immediately in response to an invalid
* received TCP packet (see Note #4a1).
* NET_TCP_CONN_TX_ACK_TIMEOUT Transmit a TCP acknowledgement segment
* immediately in response to a delayed
* acknowledgement timeout (see Note #6).
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection acknowledgement successfully
* transmitted.
* NET_TCP_ERR_CONN_ACK_NONE TCP connection acknowledgement NOT requested.
* NET_TCP_ERR_CONN_ACK_DLYD TCP connection acknowledgement transmit delayed
* (see Note #6).
* NET_TCP_ERR_CONN_ACK_PREVLY_TXD TCP connection acknowledgement previously
* transmitted for segment (see Note #7).
* NET_TCP_ERR_CONN_ACK_INVALID TCP connection acknowledgement NOT valid for
* current TCP connection state.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* -- RETURNED BY NetTCP_RxPktConnIsValidSeq() : --
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* Return(s) : none.
*
* Caller(s) : various.
*$PAGE*
* Note(s) : (3) See the following RFC's for TCP acknowledgement generation summary :
*
* (a) RFC # 793, Section 3.9 'Event Processing : SEGMENT ARRIVES'
* (b) RFC # 813, Section 5
* (c) RFC #1122, Section 4.2.3.2
* (d) RFC #2581, Sections 3.2 & 4.2
* (e) RFC Draft-IETF-TCPm-TCPSecure #00, Sections 2 & 3
*
* (4) (a) TCP connection acknowledgements are transmitted when certain segments are received :
*
* (A) Some TCP transmit acknowledgement validation logic implemented in previous
* functions; include duplicate validation logic in NetTCP_TxConnAck() only
* if debug/validation code is enabled (i.e. NET_ERR_CFG_ARG_CHK_DBG_EN is
* DEF_ENABLED in 'net_cfg.h').
*
* (1) (A) RFC #793, Section 3.4 'Establishing a Connection : Reset Generation : 1' states that
* "if [a] connection does not exist (CLOSED) then a reset is sent in response to any
* incoming segment except another reset".
*
* Thus, ONLY resets are transmitted from the CLOSED state; never acknowledgements.
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State]' allows
* for the transmission of TCP connection reset & connection synchronization segments
* ONLY; never acknowledgement-only segments (see also Note #2).
*
* (C) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check SYN Bit' states that "if ... our SYN has been ACKed ... change the
* connection state to ESTABLISHED, form an ACK segment ... and send it".
*
* Thus, acknowledgements MUST be immediately transmitted in reply to all valid
* synchronization segments received.
*
* (D) (1) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence
* Number' states that for the "SYN-RECEIVED STATE, ESTABLISHED STATE, FIN-WAIT-1
* STATE, FIN-WAIT-2 STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK STATE, TIME-
* WAIT STATE ... if an incoming segment is not acceptable," ...
*
* (a) "an acknowledgment should be sent in reply" :
*
* (1) <SEQ=SND.NXT> <ACK=RCV.NXT> <CTL=ACK>
*
* (b) (1) "(unless the RST bit is set)".
*
* (2) However, RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 requires
* transmitting a TCP acknowledgement upon receipt of certain TCP
* segments regardless of whether "the RST bit" is set (see Notes
* #4a1D2b1c & #4a1D2b3).
*
* See also Notes #4a1D2b & #4a1D3b.
*$PAGE*
* (2) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check RST Bit'
* states that "if the RST bit is set ... enter the CLOSED state".
*
* Note this check is placed following the sequence check to prevent a segment
* from an old connection ... from causing an abort of the current connection".
*
* (b) (1) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 2.2 amends the "handling
* of a segment with the RST bit when in a synchronized state" to "provide some
* protection against ... blind reset attack[s] using the RST bit" :
*
* (a) "If the RST bit is set and the sequence number is outside the
* expected window, silently drop the segment."
*
* (b) "If the RST bit is exactly the next expected sequence number [sic],
* reset the connection"; it is assumed that this should read "if the
* RST bit is set and the sequence number is exactly the next expected
* sequence number, reset the connection."
*
* (c) "If the RST bit is set and the sequence number does not exactly
* match the next expected sequence value, yet is within the
* acceptable window (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) send
* an acknowledgment."
*
* (2) ???? Although RFC Draft-IETF-TCPm-TCPSecure #00 explicitly states that this
* amendment applies only to the "handling of a ... RST when in a synchronized
* state", it is assumed that this should also apply to the SYN-RECEIVED state.
*
* (3) ???? In addition, RFC Draft-IETF-TCPm-TCPSecure #00 does NOT provide a
* precedence priority for handling TCP segments received with BOTH the RST
* & SYN bits set.
*
* ???? Therefore, since it does NOT seem reasonable to reset a TCP connection
* due to a TCP segment that also attempted to synchronize the TCP connection,
* it is assumed that the amended handling of the SYN bit should take precedence
* over the amended handling of the RST bit.
*
* See Note #4a1D3b.
*
* (3) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN
* Bit' states that for "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT
* STATE-1, FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK
* STATE, TIME-WAIT STATE ... [to next] check the SYN bit ... [and] if
* the SYN is in the window it is an error, send a reset ... [and] enter
* the CLOSED state ...
*
* [But] if the SYN is not in the window this step would not have been
* reached and an ack would have been sent".
*
* (b) (1) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the
* "handling of a segment with the SYN bit set in the synchronized state
* ... [by] handling ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact match to
* the next expected sequence (RCV.NXT == SEG.SEQ) then send an ACK
* segment ... but ... subtract one from value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable, i.e.:
* (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) then send an ACK segment."
*
* (2) ???? Although RFC Draft-IETF-TCPm-TCPSecure #00 explicitly states that
* this amendment applies only to the "handling of a ... SYN ... in a
* synchronized state", it is assumed that this should also apply to the
* SYN-RECEIVED state.
*
* (4) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states that if in the "ESTABLISHED STATE" or any state with similar "processing
* as for the ESTABLISHED STATE", that "if the ACK acks something not yet sent
* (SEG.ACK > SND.NXT) then send an ACK".
*$PAGE*
* (2) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Process Segment Text',
* states that in the "ESTABLISHED STATE, FIN-WAIT-1 STATE, FIN-WAIT-2 STATE ... when
* ... TCP takes responsibility for ... data ... it must also acknowledge ... the data" :
*
* (A) "Send an acknowledgment of the form" :
*
* (1) <SEQ=SND.NXT> <ACK=RCV.NXT> <CTL=ACK>
*
* (B) "This acknowledgment should be piggybacked on a segment being transmitted if
* possible without incurring undue delay."
*
* See also Note #6.
*
* (3) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check FIN Bit' states
* that "if the FIN bit is set, ... send an acknowledgment for the FIN".
*
* (4) RFC #813, Section 5 states that "the receiver of data will refrain from sending an
* acknowledgement under certain circumstances ... The most obvious event on which to
* depend is the arrival of another segment. So, if a segment arrives, postpone sending
* an acknowledgement if ... the following conditions hold" :
*
* (A) "The push bit is not set in the segment, since it is a reasonable assumption
* that there is more data coming in a subsequent segment."
*
* (1) However, if the PUSH bit is set in any received segment, an acknowledgement
* should be immediately transmitted.
*
* See also Notes #4b1, #5b2, & #6.
*
* (5) (A) RFC #2581, Section 3.2 states that "a TCP receiver SHOULD send an immediate ACK" :
*
* (1) "When an out-of-order segment arrives. The purpose of this ACK is to
* inform the sender that a segment was received out-of-order and which
* sequence number is expected."
*
* (2) "In addition, ... when the incoming segment fills in all or part of a
* gap in the sequence space. This will generate more timely information
* for a sender recovering from a ... retransmission timeout ... [or] a
* fast retransmit."
*
* (B) RFC #1122, Section 4.2.2.21 reiterates that "a TCP MAY send an ACK segment
* acknowledging RCV.NXT when a valid segment arrives that is in the window
* but not at the left window edge ... One reason for ACKing out-of-order
* segments [is] to support ... 'fast retransmit'".
*
* (b) TCP connection acknowledgements are transmitted for certain TCP connection events :
*
* (1) RFC #813, Section 5 states that "the receiver of data will refrain from sending an
* acknowledgement under certain circumstances ... Postpone sending an acknowledgement
* if ... the following conditions hold" :
*
* (B) "There is no revised window information to be sent back."
*
* (1) However, if any local receive window size is available to update to the
* remote host, an acknowledgement should be immediately transmitted.
*
* See also Note #4a4 & 'NetTCP_RxConnWinSizeHandler() Note #4'.
*$PAGE*
* (5) (a) Although NO RFC specifies whether an acknowledgement should or should NOT
* be transmitted in response to a received acknowledgement-only segment, it
* seems reasonable & is assumed that NO TCP connection acknowledgement should
* be transmitted in response to any acknowledgement-only segment(s) received.
*
* (1) A received TCP segment is considered an acknowledgement-only segment if
* the segment was received with zero segment length, i.e. NO received TCP
* sequences :
*
* (A) NO synchronization or close controls)
* (B) NO TCP data
*
* (b) (1) However, since acknowledgements are transmitted in response to various
* invalid segments received, some acknowledgements MUST be transmitted
* even for certain invalid acknowledgement-only segments.
*
* See also Note #4a1.
*
* (2) Also, acknowledgements SHOULD be transmitted for received segments with
* the PUSH bit set, even for segments with NO received TCP data.
*
* See also Note #4a4.
*
* (3) (A) Also, RFC #1122, Section 4.2.2.17 states that the "probing of zero
* (offered) windows MUST be supported. A TCP MAY keep its offered
* receive window closed indefinitely. As long as the receiving TCP
* continues to send acknowledgements in response to the probe segments".
*
* (B) In order to always acknowledge a remote host's probing of the local
* TCP connection's receive window size :
*
* (1) Since probe segments :
*
* (a) may or may NOT contain data, ...
* (b) sequence values may or may NOT be within the TCP connection's
* current receive window; ...
*
* See also Note #4a1D1a1 & 'NetTCP_RxPktConnIsValidSeq() Note #1d3'.
*
* (2) ... acknowledgements SHOULD be transmitted in reply to ALL valid
* & SOME invalid received segments from the remote host whenever
* the TCP connection's local receive window is zero-sized.
*
* (6) (a) The following sections state that "a TCP SHOULD implement a delayed ACK" :
*
* (A) RFC # 813, Section 5
* (B) RFC #1122, Section 4.2.3.2
* (C) RFC #2581, Section 4.2
*
* (1) (A) (1) RFC #1122, Section 4.2.3.2 states that "in a stream of full-sized segments
* there SHOULD be an ACK for at least every second segment".
*
* (2) RFC #2581, Section 4.2 reiterates that "an ACK SHOULD be generated for at
* least every second full-sized segment".
*
* (B) However, RFC #2581, Section 4.2 states that "an implementation is deemed to
* comply with this requirement ... by acknowledging at least every second segment,
* regardless of size".
*
* (2) (A) (1) RFC #813, Section 5 states that "the receiver of data will refrain from
* sending an acknowledgement under certain circumstances, in which case it
* must set a timer which will cause the acknowledgement to be sent later".
*
* (2) RFC #1122, Section 4.2.3.2 states that "an ACK should not be excessively
* delayed; in particular, the delay MUST be less than 0.5 seconds".
*
* (3) RFC #2581, Section 4.2 reiterates that "an ACK ... MUST be generated
* within 500 ms of the arrival of the first unacknowledged packet".
*
* (B) If the acknowledgement delay timeout is configured with a non-zero value,
* at least one timer tick MUST be set to ensure that the non-zero timeout
* is implemented.
*
* (b) However, if NO network timer is available to delay the acknowledgement, the TCP
* connection acknowledgement SHOULD be immediately transmitted.
*$PAGE*
* (7) (a) (1) RFC #1122, Section 4.2.2.14 states that "a careless implementation can send
* two or more acknowledgment segments per data segment received".
*
* (2) RFC #1122, Section 4.2.2.20 states that "in general, the processing of
* received segments MUST be implemented to aggregate ACK segments whenever
* possible. For example, if the TCP is processing a series of queued
* segments, it MUST process them all before sending any ACK segments".
*
* (3) Thus, no more than one acknowledgement SHOULD be transmitted in response
* to any received segment.
*
* (b) "When the application program subsequently consumes the data and increases
* the available receive buffer space again, the receiver may send a second
* acknowledgement segment to update the window at the sender."
*
* However, the application layer receives data from a TCP connection's application
* receive queue asynchronously & irrespective of distinct or specific TCP packets
* (see 'NetTCP_RxAppData() Note #5a'). Thus, any acknowledgement transmissions
* triggered during asynchronous application receives CANNOT be associated with, &
* thereby limited by, any specific received segments.
*
* (8) (a) (1) RFC #793, Sections 3.7 & 2.6 state that "TCP uses retransmission ... to ensure
* delivery of every segment".
*
* (2) However, RFC #1122, Section 4.2.2.17 'DISCUSSION' states that "it is extremely
* important to remember that ACK (acknowledgment) segments that contain no data
* are not reliably transmitted by TCP".
*
* Therefore, it is assumed that TCP acknowledgement-ONLY segments should NOT be
* queued for retransmission but SHOULD be silently discarded.
*
* (b) (1) The network buffer's reference counter is NOT incremented since the TCP layer
* does NOT maintain a reference to any transmitted TCP acknowledgement segments.
*
* (2) Therefore, the network buffer MUST be freed by lower layer(s).
*
* See also 'NetTCP_TxConnReset() Note #6',
* & 'NetTCP_TxConnProbe() Note #3'.
*
* (9) On ANY errors, network resources MUST be appropriately freed :
*
* (a) For any network resources NOT linked to the TCP connection, each network resource
* MUST be freed by appropriate function(s).
*
* (10) #### IP options currently NOT implemented.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnAck (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_ACK_CODE tx_ack_code,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr)
{
#if (((NET_CTR_CFG_STAT_EN == DEF_ENABLED) || \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_SEQ_CODE seq_code;
NET_TCP_RESET_CODE reset_code;
#endif
CPU_BOOLEAN tx_ack;
CPU_BOOLEAN tmr_free;
CPU_BOOLEAN push_avail;
NET_TMR_TICK timeout_tick;
NET_BUF_SIZE data_len;
NET_BUF_SIZE data_ix;
NET_BUF *pseg_ack;
NET_BUF_HDR *pseg_ack_hdr;
NET_IP_TOS TOS;
NET_IP_TTL TTL;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR ack_nbr;
NET_TCP_SEQ_NBR ack_nbr_delta;
NET_TCP_WIN_SIZE win_size;
CPU_INT16U flags_tcp;
CPU_INT16U flags_ip;
NET_ERR err;
/* ----------- VALIDATE TCP CONN TX ACK ----------- */
tx_ack = DEF_NO;
tmr_free = DEF_YES;
ack_nbr_delta = 0;
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #4a1A. */
case NET_TCP_CONN_STATE_LISTEN: /* See Note #4a1B. */
break;
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #4a1C. */
if (pbuf_hdr != (NET_BUF_HDR *)0) {
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #4aA. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (seq_code == NET_TCP_CONN_RX_SEQ_SYNC) { /* If valid sync rx'd, ... */
tx_ack = DEF_YES; /* ... tx TCP conn ack. */
}
#else
tx_ack = DEF_YES;
#endif
if (pbuf_hdr->TCP_SegAckTxd != DEF_NO) { /* If prev'ly tx'd TCP conn ack for rx'd seg, .. */
*perr = NET_TCP_ERR_CONN_ACK_PREVLY_TXD; /* .. do NOT re-tx TCP conn ack (see Note #7a3). */
return;
}
} else {
tx_ack = DEF_YES;
}
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
if (pbuf_hdr != (NET_BUF_HDR *)0) {
if (pbuf_hdr->TCP_SegAckTxd != DEF_NO) { /* If prev'ly tx'd TCP conn ack for rx'd seg, .. */
*perr = NET_TCP_ERR_CONN_ACK_PREVLY_TXD; /* .. do NOT re-tx TCP conn ack (see Note #7a3). */
return;
}
}
switch (tx_ack_code) {
case NET_TCP_CONN_TX_ACK_NONE:
*perr = NET_TCP_ERR_CONN_ACK_NONE;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_TX_ACK:
case NET_TCP_CONN_TX_ACK_IMMED:
if (pbuf_hdr != (NET_BUF_HDR *)0) {
push_avail = DEF_BIT_IS_SET(pbuf_hdr->TCP_HdrLen_Flags, NET_TCP_HDR_FLAG_PUSH);
if (push_avail == DEF_YES) { /* If rx'd seg push'd & en'd, .. */
if (pconn->TxAckImmedRxdPushEn != DEF_DISABLED) {
tx_ack = DEF_YES; /* .. tx TCP conn ack (see Note #4a4A1). */
break;
}
}
if (pbuf_hdr->TCP_SegLen == 0) { /* If ack-ONLY seg (see Note #5a1); .. */
if (pconn->RxWinSizeActual > 0) { /* .. & local rx win > 0, .. */
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return; /* .. do NOT tx ack (see Note #5a); .. */
} else { /* .. & local rx win = 0 (see Note #5b3B2), .. */
tx_ack = DEF_YES; /* .. tx TCP conn ack. */
break;
}
}
}
if (tx_ack_code == NET_TCP_CONN_TX_ACK_IMMED) { /* If immed ack req'd, ... */
tx_ack = DEF_YES; /* ... tx TCP conn ack. */
break;
}
if (pconn->TxAckDlyTimeout_ms == 0) { /* If ack dly timeout zero, ... */
tx_ack = DEF_YES; /* ... tx TCP conn ack. */
break;
}
pconn->TxAckDlyCnt++; /* If ack dly cnt >= th, ... */
if (pconn->TxAckDlyCnt >= NET_TCP_ACK_DLY_CNT_TH) {
tx_ack = DEF_YES; /* ... tx TCP conn ack (see Note #6a1B). */
break;
}
if (pconn->TxAckDlyTmr != (NET_TMR *)0) { /* If ack dly tmr prev'ly started, ... */
*perr = NET_TCP_ERR_CONN_ACK_DLYD; /* ... continue ack dly (see Note #6a2A1). */
return;
}
timeout_tick = ((NET_TMR_TICK)pconn->TxAckDlyTimeout_ms * NET_TMR_TIME_TICK_PER_SEC) / DEF_TIME_NBR_mS_PER_SEC;
if (timeout_tick < 1) { /* If < 1 tick, ... */
timeout_tick = 1; /* ... set at least 1 tick (see Note #6a2B). */
}
pconn->TxAckDlyTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_TxConnAckDlyTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
if ( err == NET_TMR_ERR_NONE) { /* If ack dly tmr avail, ... */
*perr = NET_TCP_ERR_CONN_ACK_DLYD; /* ... start ack dly (see Note #6a2A1). */
return;
} else { /* Else tx TCP conn ack (see Note #6b). */
tx_ack = DEF_YES;
}
break;
/*$PAGE*/
case NET_TCP_CONN_TX_ACK_FAULT: /* See Note #4a1D. */
if (pbuf_hdr != (NET_BUF_HDR *)0) {
if (pbuf_hdr->TCP_SegSync == DEF_YES) { /* If sync rx'd (see Note #4a1D3b1), ... */
tx_ack = DEF_YES; /* ... tx TCP conn ack; ignore possible reset. */
/* If rx'd sync equal to next rx seq nbr, ... */
if (pbuf_hdr->TCP_SeqNbr == pconn->RxSeqNbrNext) {
ack_nbr_delta = 1; /* ... sub 1 from ack (see Note #4a1D3b1B). */
}
} else {
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #4aA. */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
reset_code = NetTCP_RxPktConnIsValidReset(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
switch (seq_code) {
case NET_TCP_CONN_RX_SEQ_VALID: /* If valid seq rx'd .. */
/* .. but invalid reset rx'd, .. */
if (reset_code == NET_TCP_CONN_RX_RESET_INVALID) {
tx_ack = DEF_YES; /* .. tx TCP conn ack (see Note #4a1D2b1c). */
}
break;
case NET_TCP_CONN_RX_SEQ_SYNC: /* If invalid sync rx'd, .. */
case NET_TCP_CONN_RX_SEQ_SYNC_INVALID:
tx_ack = DEF_YES; /* .. tx TCP conn ack (see Note #4a1D3b1). */
break;
case NET_TCP_CONN_RX_SEQ_NONE:
case NET_TCP_CONN_RX_SEQ_INVALID: /* If invalid seq rx'd (see Note #4a1D1) .. */
default:
/* .. & reset NOT rx'd (see Note #4a1D1b1), .. */
if (reset_code == NET_TCP_CONN_RX_RESET_NONE) {
tx_ack = DEF_YES; /* .. tx TCP conn ack (see Note #4a1D1a). */
}
break;
}
#else
tx_ack = DEF_YES;
#endif
}
} else {
tx_ack = DEF_YES;
}
break;
case NET_TCP_CONN_TX_ACK_TIMEOUT:
tx_ack = DEF_YES;
tmr_free = DEF_NO;
break;
default:
break;
}
break;
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
if (tx_ack != DEF_YES) { /* If NOT valid, abort tx TCP conn ack. */
*perr = NET_TCP_ERR_CONN_ACK_INVALID;
return;
}
NetTCP_TxConnAckDlyReset(pconn, tmr_free); /* Reset ack dly ctrls. */
if (pbuf_hdr != (NET_BUF_HDR *)0) {
pbuf_hdr->TCP_SegAckTxd = DEF_YES; /* Set ack tx'd for rx'd seg (see Note #7a). */
}
/*$PAGE*/
/* ----------- PREPARE TCP CONN ACK SEG ----------- */
/* If valid, prepare & tx TCP conn ack. */
/* Get buf. */
data_len = NET_TCP_DATA_LEN_TX_ACK;
data_ix = NET_BUF_DATA_TX_IX;
pseg_ack = NetBuf_Get((NET_BUF_SIZE) data_len,
(NET_BUF_SIZE) data_ix,
(CPU_INT16U ) NET_BUF_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) {
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
/* --------------- PREPARE TCP HDR ---------------- */
/* Prepare seg addrs. */
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If TCP pkt rx'd, cfg TCP tx ... */
/* ... src addr from rx'd TCP pkt dest addr ... */
src_port = (NET_TCP_PORT_NBR)pbuf_hdr->TCP_UDP_PortDest;
src_addr = (NET_IP_ADDR )pbuf_hdr->IP_AddrDest;
/* .. & dest addr from rx'd TCP pkt src addr. */
dest_port = (NET_TCP_PORT_NBR)pbuf_hdr->TCP_UDP_PortSrc;
dest_addr = (NET_IP_ADDR )pbuf_hdr->IP_AddrSrc;
} else { /* Else cfg TCP tx pkt addrs from TCP conn addrs. */
NetTCP_TxConnPrepareSegAddrs((NET_TCP_CONN *) pconn,
(CPU_INT08U *)&src_port,
(CPU_INT08U *)&src_addr,
(CPU_INT16U ) sizeof(src_port),
(CPU_INT16U ) sizeof(src_addr),
(CPU_INT08U *)&dest_port,
(CPU_INT08U *)&dest_addr,
(CPU_INT16U ) sizeof(dest_port),
(CPU_INT16U ) sizeof(dest_addr),
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) { /* See Note #9a. */
*perr = NET_TCP_ERR_CONN_FAULT;
NetBuf_Free(pseg_ack);
return;
}
}
/* Prepare TCP seq nbrs (see Note #1b2B). */
seq_nbr = pconn->TxSeqNbrNext;
ack_nbr = pconn->RxSeqNbrNext - ack_nbr_delta;
/* Prepare TCP tx flags (see Note #1b2C). */
flags_tcp = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_ACK;
/* Prepare TCP win size. */
win_size = pconn->RxWinSizeActual;
/* Prepare IP params. */
TOS = pconn->TxIP_TOS;
TTL = pconn->TxIP_TTL;
flags_ip = pconn->TxIP_Flags;
/* Init buf ctrls. */
pseg_ack_hdr = &pseg_ack->Hdr;
pseg_ack_hdr->DataIx = (CPU_INT16U )data_ix;
pseg_ack_hdr->DataLen = (NET_BUF_SIZE)data_len;
pseg_ack_hdr->TotLen = (NET_BUF_SIZE)pseg_ack_hdr->DataLen;
pseg_ack_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
pseg_ack_hdr->TCP_SegSync = (CPU_BOOLEAN )DEF_NO;
pseg_ack_hdr->TCP_SegClose = (CPU_BOOLEAN )DEF_NO;
pseg_ack_hdr->TCP_SegAck = (CPU_BOOLEAN )DEF_YES;
pseg_ack_hdr->TCP_SegReset = (CPU_BOOLEAN )DEF_NO;
pseg_ack_hdr->TCP_Flags = flags_tcp;
/*$PAGE*/
/* ------------- TX TCP CONN ACK SEG -------------- */
NetTCP_TxPktHandler((NET_BUF *) pseg_ack,
(NET_IP_ADDR ) src_addr,
(NET_TCP_PORT_NBR) src_port,
(NET_IP_ADDR ) dest_addr,
(NET_TCP_PORT_NBR) dest_port,
(NET_TCP_SEQ_NBR ) seq_nbr,
(NET_TCP_SEQ_NBR ) ack_nbr,
(NET_TCP_WIN_SIZE) win_size,
(NET_IP_TOS ) TOS,
(NET_IP_TTL ) TTL,
(CPU_INT16U ) flags_tcp,
(CPU_INT16U ) flags_ip,
(void *) 0,
(void *) 0, /* See Note #10. */
(NET_ERR *)&err); /* Ignore transitory tx err(s). */
#if 0 /* Tx buf freed by lower layer(s) [see Note #8b2]. */
NetTCP_TxPktFree(pseg_ack);
#endif
NET_CTR_STAT_INC(NetTCP_StatTxSegConnAckCtr);
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnAckDlyReset()
*
* Description : Reset a TCP connection's delayed acknowledgement controls.
*
* Argument(s) : pconn Pointer to TCP connection to reset delayed acknowledgement controls.
* ----- Argument validated in NetTCP_TxConnAck(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnReTxQ_Timeout().
*
* tmr_free Indicate whether to free network timer :
*
* DEF_YES Free network timer for delayed acknowledgement.
* DEF_NO Do NOT free network timer for delayed acknowledgement
* [Freed by NetTmr_TaskHandler()
* via NetTCP_TxConnAckDlyTimeout()].
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnAck(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnReTxQ().
*
* Note(s) : (1) A TCP connection's delayed acknowledgement controls SHOULD be reset whenever :
*
* (a) TCP data segment(s) are transmitted
* (b) TCP data segment(s) are re-transmitted
*
* ... since any transmitted or re-transmitted data segment(s) always transmit an
* accompanying acknowledgement.
*********************************************************************************************************
*/
static void NetTCP_TxConnAckDlyReset (NET_TCP_CONN *pconn,
CPU_BOOLEAN tmr_free)
{
pconn->TxAckDlyCnt = 0; /* Reset ack dly cnts ... */
if (pconn->TxAckDlyTmr != (NET_TMR *)0) { /* ... & free/clr ack dly tmr. */
if (tmr_free == DEF_YES) {
NetTmr_Free(pconn->TxAckDlyTmr);
}
pconn->TxAckDlyTmr = (NET_TMR *)0;
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnAckDlyTimeout()
*
* Description : (1) Handle TCP connection's delayed acknowledgement transmit for the following connected
* states :
*
* (a) SYN-RECEIVED
* (b) ESTABLISHED
* (c) FIN-WAIT-1
* (d) FIN-WAIT-2
* (e) CLOSING
* (f) TIME-WAIT
* (g) CLOSE-WAIT
* (h) LAST-ACK
*
*
* Argument(s) : pconn_timeout Pointer to TCP connection to transmit delayed acknowledgement (see Note #2b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_TxConnAck().
*
* Note(s) : (2) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (3) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) :
*
* (A) TCP connection transmit acknowledgement delay timer ('TxAckDlyTmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared prior to next handler function(s) as an extra precaution to
* avoiding re-freeing the timer (see Note #3a2B).
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnAckDlyTimeout (void *pconn_timeout)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CLOSE_CODE close_code;
NET_ERR err;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #2b2A. */
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY); /* See Note #3b1. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* -------------- VALIDATE PTR ---------------- */
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
/* -------------- VALIDATE TYPE --------------- */
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #1. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' warning. */
}
#endif
/* ------ HANDLE TCP CONN TX ACK TIMEOUT ------ */
pconn->TxAckDlyTmr = (NET_TMR *)0; /* Clr tx ack dly tmr (see Note #3a2A1). */
NetTCP_TxConnAck((NET_TCP_CONN *) pconn,
(NET_BUF_HDR *) 0,
(NET_TCP_ACK_CODE ) NET_TCP_CONN_TX_ACK_TIMEOUT,
(NET_TCP_CLOSE_CODE) close_code,
(NET_ERR *)&err); /* Ignore transitory tx err(s). */
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnReset()
*
* Description : (1) Prepare & transmit a TCP connection reset :
*
* (a) Validate received TCP packet for TCP reset See Note #4
* (b) Validate TCP connection state for TCP reset See Note #3
* (c) Prepare TCP reset segment :
* (1) Get buffer
* (2) Prepare TCP segment :
* (A) TCP segment addresses
* (B) TCP segment sequence numbers See Note #5
* (C) TCP segment transmit flags :
* (1) RESET
* (2) ACK See Note #5a2A
* (D) TCP segment window size
* (E) TCP segment packet buffer controls
* (d) Transmit TCP connection reset
*
*
* Argument(s) : pconn Pointer to a TCP connection.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet, if available.
*
* tx_reset_code Indicate whether & how to transmit a TCP reset segment :
*
* NET_TCP_CONN_TX_RESET Transmit a TCP reset segment, if permitted
* (see Notes #3 & #4).
* NET_TCP_CONN_TX_RESET_FAULT Transmit a TCP reset segment immediately for
* a closing TCP connection fault.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection reset successfully transmitted.
* NET_TCP_ERR_CONN_RESET_INVALID TCP connection reset NOT valid for current TCP
* connection state.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* - RETURNED BY NetTCP_RxPktConnIsValidSeq() : -
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
*
* Return(s) : none.
*
* Caller(s) : various.
*$PAGE*
* Note(s) : (2) See the following RFC's for TCP reset generation summary :
*
* (a) RFC #793, Section 3.4 'Establishing a Connection : Reset Generation'
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES'
* (c) RFC Draft-IETF-TCPm-TCPSecure #00, Section 3
*
* (3) TCP connection resets are transmitted :
*
* (a) When certain invalid segments are received :
*
* (A) Some TCP transmit reset validation logic implemented in previous functions;
* include duplicate validation logic in NetTCP_TxConnReset() only if debug/
* validation code is enabled (i.e. NET_ERR_CFG_ARG_CHK_DBG_EN is DEF_ENABLED
* in 'net_cfg.h').
*
* (1) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : CLOSED [State]'
* states that if the current TCP connection "state is CLOSED", then ...
*
* (1) "An incoming segment containing a RST is discarded".
* (2) "An incoming segment NOT containing a RST causes a RST to be sent".
*
* (B) RFC #793, Section 3.4 'Establishing a Connection : Reset Generation : 1'
* reiterates that "if [a] connection does not exist (CLOSED) then a reset is
* sent in response to any incoming segment except another reset".
*
* (2) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for ACK' states that "any acknowledgment is bad if it arrives on a
* connection still in the LISTEN state. An acceptable reset segment should
* be formed for any arriving ACK-bearing segment".
*
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for SYN' also states that "if the security/compartment on the incoming
* segment does not exactly match the security/compartment in the TCB ... [or]
* if the SEG.PRC is ... not allowed [then] send a reset".
*
* However, these checks for invalid connection permissions are NOT necessary
* since TCP security & precedence NOT supported (see 'net_tcp.c Note #1a').
*
* (3) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check ACK Bit' states that "if the state is SYN-SENT" & "the ACK bit is set" &
* the incoming segment's "SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset".
*$PAGE*
* (4) (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check Sequence
* Number' states that for the "SYN-RECEIVED STATE, ESTABLISHED STATE, FIN-
* WAIT-1 STATE, FIN-WAIT-2 STATE, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK
* STATE, TIME-WAIT STATE", to "first check [the] sequence number ... [and if
* it] is not acceptable, an acknowledgment should be sent in reply ... unless
* the RST bit is set".
*
* (B) (1) (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check SYN
* Bit' states that for "SYN-RECEIVED [STATE], ESTABLISHED STATE, FIN-WAIT
* STATE-1, FIN-WAIT STATE-2, CLOSE-WAIT STATE, CLOSING STATE, LAST-ACK
* STATE, TIME-WAIT STATE ... [to next] check the SYN bit ... [and] if
* the SYN is in the window it is an error, send a reset, any outstanding
* RECEIVEs and SEND[s] should receive 'reset' responses, all segment
* queues should be flushed, the user should also receive an unsolicited
* general 'connection reset' signal[, and] enter the CLOSED state".
*
* (b) But "if the SYN is not in the window this step would not have been
* reached and an ack would have been sent" (see Note #3a4A).
*
* (2) (a) HOWEVER, RFC Draft-IETF-TCPm-TCPSecure #00, Section 3.2 amends the
* "handling of a segment with the SYN bit set in the synchronized state
* ... [by] handling ... the SYN bit" as follows :
*
* (a) "If the SYN bit is set and the sequence number is outside the
* expected window, send an ACK back to the peer."
*
* (b) "If the SYN bit is set and the sequence number is an exact
* match to the next expected sequence (RCV.NXT == SEG.SEQ)
* then send an ACK segment ... but ... subtract one from
* value being acknowledged."
*
* (c) "If the SYN bit is set and the sequence number is acceptable,
* i.e.: (RCV.NXT <= SEG.SEQ <= RCV.NXT+RCV.WND) then send an
* ACK segment."
*
* (b) ???? Although RFC Draft-IETF-TCPm-TCPSecure #00 explicitly states that
* this amendment applies only to the "handling of a ... SYN ... in a
* synchronized state", it is assumed that this should also apply to the
* SYN-RECEIVED state.
*
* (C) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field'
* states to next "check the ACK Field" :
*
* (1) If in the "SYN-RECEIVED STATE ... [and] if the segment acknowledgment
* is not acceptable, form a reset segment".
*
* (2) If in the "ESTABLISHED STATE" or any state with similar "processing as
* for the ESTABLISHED STATE", that "if the ACK acks something not yet sent
* (SEG.ACK > SND.NXT) then send an ACK" but "if the ACK is a duplicate
* (SEG.ACK =< SND.UNA), it can be ignored".
*
* (D) RFC #793, Section 3.4 'Establishing a Connection : Reset Generation : 3'
* reiterates that for any TCP "connection ... in a synchronized state
* (ESTABLISHED, FIN-WAIT-1, FIN-WAIT-2, CLOSE-WAIT, CLOSING, LAST-ACK,
* TIME-WAIT), any unacceptable segment (out of window sequence number
* or unacceptible [sic] acknowledgment number) must elicit only an empty
* acknowledgment segment containing the current send-sequence number and
* an acknowledgment indicating the next sequence number expected to be
* received".
*
* (b) (1) When TCP connection fault-closes from the following synchronization/connected/
* closing states :
*
* (A) SYN-RECEIVED
* (B) SYN-SENT
* (C) ESTABLISHED
* (D) FIN-WAIT-1
* (E) FIN-WAIT-2
* (F) CLOSING
* (G) TIME_WAIT
* (H) CLOSE-WAIT
* (I) LAST-ACK
*
* (2) Although NO RFC directly states to transmit a TCP reset segment when a TCP
* connection fault-closes, it is inferred & seems reasonable that a TCP reset
* segment SHOULD be transmitted whenever a TCP connection closes abnormally.
*$PAGE*
* (4) The following sections reiterate the generalization that "a reset is sent in response
* to any [unacceptable segment] ... EXCEPT* another reset"; also "send a reset (UNLESS*
* the RST bit is set, if so drop the segment)" : [*emphasis added]
*
* (a) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State] :
* Check for RST'
* (b) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State] :
* Check ACK Bit'
* (c) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* SYN-RECEIVED STATE' (see Note #4A)
*
* (A) This confirms that the received segment does NOT contain a TCP reset control
* since it follows RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES :
* Check RST Bit'.
*
* (5) (a) (1) The following sections ... :
*
* (A) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : CLOSED [State]'
* (B) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : LISTEN [State]'
* (1) Amended by RFC #1122, Section 4.2.2.20.(b)
* (C) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : SYN-SENT [State]'
* (D) RFC #793, Section 3.9 'Event Processing : SEGMENT ARRIVES : Check ACK Field :
* SYN-RECEIVED STATE'
*
* (2) ... generalize that "the acknowledgment and sequence field values [for the reset
* segment to transmit] are selected to make the reset sequence acceptable to the
* TCP that sent the offending segment" (see Note #3a) :
*
* (A) "If the ACK bit is off, sequence number zero is used,
*
* <SEQ=0> <ACK=SEG.SEQ + SEG.LEN> <CTL=RST, ACK>"
*
* (B) "If the ACK bit is on,
*
* <SEQ=SEG.ACK> <CTL=RST>"
*
* (b) However, NO RFC specifies the sequence & acknowledgement numbers to use when
* trasmitting a reset segment for a TCP connection that closes due to any fault
* condition(s) [see Note #3b].
*
* (1) #### Therefore, TCP transmit reset segments for fault-closing TCP connections
* should be prepared as follows :
*
* (A) With the following TCP sequence numbers :
*
* (1) TCP_SeqNbr = TxSeqNbrUnAckd
*
* (2) TCP_AckNbr = RxSeqNbrNext
*
* where
*
* TCP_SeqNbr TCP transmit reset segment sequence number
* TCP_AckNbr TCP transmit reset segment acknowledgement number
* TxSeqNbrUnAckd TCP connection's currently unacknowledged transmit
* sequence number
* RxSeqNbrNext TCP connection's currently expected next receive
* sequence number
*
* (B) With the following TCP segment header flags set :
*
* (1) RESET
*
* (2) This TCP transmit reset segment format complies with TCP connection received
* reset segment handling as specified in RFC #793, Section 3.9 'Event Processing :
* SEGMENT ARRIVES'.
*
* See also 'NetTCP_RxPktConnIsValidReset() Notes #2a2, 2a3, 2a4A1, & 2a4B1'.
*$PAGE*
* (6) (a) RFC #793, Sections 3.7 & 2.6 state that "TCP uses retransmission ... to ensure
* delivery of every segment".
*
* However, NO RFC specifies whether TCP connection reset segments should be queued
* for retransmission. Therefore, it is assumed that ALL TCP connection reset
* segments SHOULD NOT be queued for retransmission but SHOULD be silently discarded.
*
* (b) (1) The network buffer's reference counter is NOT incremented since the TCP layer
* does NOT maintain a reference to any transmitted TCP connection reset segments.
*
* (2) Therefore, the network buffer MUST be freed by lower layer(s).
*
* See also 'NetTCP_TxConnAck() Note #8',
* & 'NetTCP_TxConnProbe() Note #3'.
*
* (7) On ANY errors :
*
* (a) Network resources MUST be appropriately freed :
*
* (1) For any network resources NOT linked to the TCP connection, each network resource
* MUST be freed by appropriate function(s).
*
* (b) TCP connection MUST NOT be re-closed.
*
* See also 'NetTCP_ConnClose() Note #5'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnReset (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_RESET_CODE tx_reset_code,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr)
{
#if (((NET_CTR_CFG_ERR_EN == DEF_ENABLED) || \
(NET_CTR_CFG_STAT_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_ACK_CODE ack_code;
NET_TCP_SEQ_CODE seq_code;
#endif
CPU_BOOLEAN tx_reset;
NET_BUF_SIZE data_len;
NET_BUF_SIZE data_ix;
NET_BUF *pseg_reset;
NET_BUF_HDR *pseg_reset_hdr;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR ack_nbr;
NET_TCP_WIN_SIZE win_size;
CPU_INT16U flags_tcp;
NET_ERR err;
/* ------------ VALIDATE RX'D TCP PKT ------------- */
if (pbuf_hdr != (NET_BUF_HDR *)0) {
if (pbuf_hdr->TCP_SegReset != DEF_NO) { /* If TCP reset pkt rx'd, ... */
*perr = NET_TCP_ERR_CONN_RESET_INVALID; /* ... do NOT tx TCP conn reset (see Note #4). */
return;
}
}
/* ----------- VALIDATE TCP CONN STATE ------------ */
tx_reset = DEF_NO;
if (pconn != (NET_TCP_CONN *)0) {
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #3a1. */
tx_reset = DEF_YES;
break;
case NET_TCP_CONN_STATE_LISTEN: /* See Note #3a2. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #3aA. */
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If seg rx'd ... */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
if (ack_code != NET_TCP_CONN_RX_ACK_NONE) { /* ... with ANY (invalid) ack, ... */
tx_reset = DEF_YES; /* ... tx TCP conn reset (see Note #3a2A). */
}
}
#else
tx_reset = DEF_YES;
#endif
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #3a3. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #3aA. */
switch (tx_reset_code) {
case NET_TCP_CONN_TX_RESET:
default:
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If seg rx'd ... */
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ... with invalid ack, ... */
if (ack_code == NET_TCP_CONN_RX_ACK_INVALID) {
tx_reset = DEF_YES; /* ... tx TCP conn reset (see Note #3a3). */
}
} else { /* Else no seg rx'd, ... */
tx_reset = DEF_YES; /* ... tx TCP conn reset (see Note #3b1B). */
}
break;
case NET_TCP_CONN_TX_RESET_FAULT:
tx_reset = DEF_YES;
break;
}
#else
(void)&tx_reset_code; /* Prevent compiler warning. */
tx_reset = DEF_YES;
#endif
break;
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #3a4. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #3aA. */
switch (tx_reset_code) {
case NET_TCP_CONN_TX_RESET:
default:
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If seg rx'd ... */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ... with invalid seq/sync, ... */
if (seq_code != NET_TCP_CONN_RX_SEQ_VALID) {
/* ... tx TCP conn ack (see Notes #3a4A & #3a4B2); */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return;
}
ack_code = NetTCP_RxPktConnIsValidAck(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ... without valid ack, ... */
if (ack_code != NET_TCP_CONN_RX_ACK_VALID) {
tx_reset = DEF_YES; /* ... tx TCP conn reset (see Note #3a4C1). */
}
} else { /* Else no seg rx'd, ... */
tx_reset = DEF_YES; /* ... tx TCP conn reset (see Note #3b1A). */
}
break;
case NET_TCP_CONN_TX_RESET_FAULT:
tx_reset = DEF_YES;
break;
}
#else
(void)&tx_reset_code; /* Prevent compiler warning. */
tx_reset = DEF_YES;
#endif
break;
/*$PAGE*/
case NET_TCP_CONN_STATE_CONN: /* See Note #3a4. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #3aA. */
switch (tx_reset_code) {
case NET_TCP_CONN_TX_RESET:
default:
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If seg rx'd ... */
seq_code = NetTCP_RxPktConnIsValidSeq(pconn, pbuf_hdr, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* ... with invalid seq/sync, ... */
if (seq_code != NET_TCP_CONN_RX_SEQ_VALID) {
/* ... tx TCP conn ack (see Notes #3a4A & #3a4B2). */
NetTCP_TxConnAck(pconn, pbuf_hdr, NET_TCP_CONN_TX_ACK_FAULT, NET_TCP_CONN_CLOSE_ALL, &err);
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return;
}
} else { /* Else no seg rx'd, ... */
tx_reset = DEF_YES; /* ... tx TCP conn reset (see Notes #3b1C - #3b1I).*/
}
break;
case NET_TCP_CONN_TX_RESET_FAULT:
tx_reset = DEF_YES;
break;
}
#else
(void)&tx_reset_code; /* Prevent compiler warning. */
tx_reset = DEF_YES;
#endif
break;
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
tx_reset = DEF_YES;
break;
case NET_TCP_CONN_STATE_NONE:
default:
if (close_code != NET_TCP_CONN_CLOSE_NONE) { /* If tx reset NOT req'd by TCP conn close fnct(s), */
/* ... close TCP conn (see Note #7b). */
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_CONN_TX_RESET);
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
}
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
} else { /* If NO demux'd TCP conn avail, handle as CLOSED. */
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If rx'd pkt avail, ... */
tx_reset = DEF_YES; /* ... tx reset. */
}
}
if (tx_reset != DEF_YES) { /* If NOT valid, abort tx TCP conn reset. */
*perr = NET_TCP_ERR_CONN_RESET_INVALID;
return;
}
/*$PAGE*/
/* ---------- PREPARE TCP CONN RESET SEG ---------- */
/* If valid, prepare & tx TCP conn reset. */
/* Get buf. */
data_len = NET_TCP_DATA_LEN_TX_RESET;
data_ix = NET_BUF_DATA_TX_IX;
pseg_reset = NetBuf_Get((NET_BUF_SIZE) data_len,
(NET_BUF_SIZE) data_ix,
(CPU_INT16U ) NET_BUF_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) {
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
/* --------------- PREPARE TCP HDR ---------------- */
/* Prepare seg addrs. */
if (pbuf_hdr != (NET_BUF_HDR *)0) { /* If TCP pkt rx'd, cfg TCP tx ... */
/* ... src addr from rx'd TCP pkt dest addr ... */
src_port = (NET_TCP_PORT_NBR)pbuf_hdr->TCP_UDP_PortDest;
src_addr = (NET_IP_ADDR )pbuf_hdr->IP_AddrDest;
/* .. & dest addr from rx'd TCP pkt src addr. */
dest_port = (NET_TCP_PORT_NBR)pbuf_hdr->TCP_UDP_PortSrc;
dest_addr = (NET_IP_ADDR )pbuf_hdr->IP_AddrSrc;
} else { /* Else cfg TCP tx pkt addrs from TCP conn addrs. */
NetTCP_TxConnPrepareSegAddrs((NET_TCP_CONN *) pconn,
(CPU_INT08U *)&src_port,
(CPU_INT08U *)&src_addr,
(CPU_INT16U ) sizeof(src_port),
(CPU_INT16U ) sizeof(src_addr),
(CPU_INT08U *)&dest_port,
(CPU_INT08U *)&dest_addr,
(CPU_INT16U ) sizeof(dest_port),
(CPU_INT16U ) sizeof(dest_addr),
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) { /* See Note #7a. */
*perr = NET_TCP_ERR_CONN_FAULT;
NetBuf_Free(pseg_reset);
return;
}
}
/* Prepare TCP tx flags (see Note #1c2C). */
flags_tcp = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_RESET;
/* Prepare TCP seq nbrs (see Note #5). */
if (pbuf_hdr != (NET_BUF_HDR *)0) {
if (pbuf_hdr->TCP_SegAck != DEF_NO) { /* If TCP ack rx'd, ... (see Note #5a2B) */
seq_nbr = pbuf_hdr->TCP_AckNbr; /* .. tx seq = ack ... */
ack_nbr = NET_TCP_ACK_NBR_NONE; /* .. & ack = none. */
} else { /* Otherwise, ... (see Note #5a2A) */
seq_nbr = NET_TCP_SEQ_NBR_NONE; /* .. tx seq = 0 (none) ... */
ack_nbr = pbuf_hdr->TCP_SeqNbr /* .. & ack = seg seq ... */
+ pbuf_hdr->TCP_SegLen; /* .. + seg len. */
DEF_BIT_SET(flags_tcp, NET_TCP_FLAG_TX_ACK);
}
} else { /* Else no seg rx'd, ... (see Note #5b1A) */
seq_nbr = pconn->TxSeqNbrUnAckd; /* .. tx seq = tx unack'd ... */
ack_nbr = pconn->RxSeqNbrNext; /* .. & ack = rx next. */
}
/* Prepare TCP win size. */
win_size = NET_TCP_WIN_SIZE_NONE;
/* Init buf ctrls. */
pseg_reset_hdr = &pseg_reset->Hdr;
pseg_reset_hdr->DataIx = (CPU_INT16U )data_ix;
pseg_reset_hdr->DataLen = (NET_BUF_SIZE)data_len;
pseg_reset_hdr->TotLen = (NET_BUF_SIZE)pseg_reset_hdr->DataLen;
pseg_reset_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
pseg_reset_hdr->TCP_SegSync = (CPU_BOOLEAN )DEF_NO;
pseg_reset_hdr->TCP_SegClose = (CPU_BOOLEAN )DEF_NO;
pseg_reset_hdr->TCP_SegAck = (CPU_BOOLEAN )DEF_BIT_IS_SET(flags_tcp, NET_TCP_FLAG_TX_ACK);
pseg_reset_hdr->TCP_SegReset = (CPU_BOOLEAN )DEF_YES;
pseg_reset_hdr->TCP_Flags = flags_tcp;
/*$PAGE*/
/* ------------ TX TCP CONN RESET SEG ------------- */
NetTCP_TxPktHandler((NET_BUF *) pseg_reset,
(NET_IP_ADDR ) src_addr,
(NET_TCP_PORT_NBR) src_port,
(NET_IP_ADDR ) dest_addr,
(NET_TCP_PORT_NBR) dest_port,
(NET_TCP_SEQ_NBR ) seq_nbr,
(NET_TCP_SEQ_NBR ) ack_nbr,
(NET_TCP_WIN_SIZE) win_size,
(NET_IP_TOS ) NET_IP_TOS_DFLT,
(NET_IP_TTL ) NET_IP_TTL_DFLT,
(CPU_INT16U ) flags_tcp,
(CPU_INT16U ) NET_IP_FLAG_NONE,
(void *) 0,
(void *) 0,
(NET_ERR *)&err); /* Ignore transitory tx err(s). */
#if 0 /* Tx buf freed by lower layer(s) [see Note #6b2]. */
NetTCP_TxPktFree(pseg_reset);
#endif
NET_CTR_STAT_INC(NetTCP_StatTxSegConnResetCtr);
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnProbe()
*
* Description : (1) Prepare & transmit a TCP connection probe :
*
* (a) Validate TCP connection state for TCP probe
* (b) Prepare TCP probe segment : See Note #2
* (1) Get buffer
* (2) Prepare TCP segment :
* (A) TCP segment addresses
* (B) TCP segment sequence numbers See Note #2b1
* (C) TCP segment transmit flags :
* (1) ACK
* (D) TCP segment window size
* (E) IP datagram parameters
* (F) TCP segment packet buffer controls
* (c) Transmit TCP connection probe
*
*
* Argument(s) : pconn Pointer to a TCP connection.
*
* tx_probe_data_octet Indicate whether to transmit a single data probe octet (see Note #2b2) :
*
* DEF_YES Transmit data probe octet.
* DEF_NO Do NOT transmit data probe octet.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection probe successfully transmitted.
* NET_TCP_ERR_CONN_PROBE_INVALID TCP connection probe NOT valid for current
* TCP connection state.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_CONN_FAIL TCP connection operation(s) failed.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnWinSizeZeroWinHandler(),
* NetTCP_TxConnKeepAlive().
*$PAGE*
* Note(s) : (2) TCP connection probes are transmitted for certain TCP conditions :
*
* (A) Some TCP transmit probe validation logic implemented in previous functions;
* include duplicate validation logic in NetTCP_TxConnProbe() only if debug/
* validation code is enabled (i.e. NET_ERR_CFG_ARG_CHK_DBG_EN is DEF_ENABLED
* in 'net_cfg.h').
*
* (a) RFC #1122, Section 4.2.3.6 specifies a "mechanism [that] periodically probes the
* other end of a connection" for the following TCP connection conditions :
*
* (1) Probing Zero Windows RFC #1122, Section 4.2.2.17
* (see 'NetTCP_TxConnWinSizeZeroWinHandler() Note #1b')
*
* (2) TCP Keep-Alives RFC #1122, Section 4.2.3.6
* (see 'NetTCP_TxConnKeepAlive() Note #2c')
*
* (b) "Send a probe segment ... to elicit a response from the peer TCP" :
*
* (1) "Such a segment generally contains SEG.SEQ = SND.NXT-1" ...
*
* (A) "Note that on a quiet [or deadlocked] connection SND.NXT = RCV.NXT, so that
* this SEG.SEQ will be outside the window. Therefore, the probe causes the
* receiver to return an acknowledgment segment."
*
* (B) "It is extremely important to remember that ACK segments that contain no data
* are not reliably transmitted by TCP."
*
* (2) "and may or may not contain one garbage octet of data."
*
* (A) "An implementation SHOULD send a [probe] segment with no data."
*
* (B) (1) "Unfortunately, some misbehaved TCP implementations fail to respond to
* a segment with SEG.SEQ = SND.NXT-1 unless the segment contains data."
*
* (2) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 23.3,
* Page 335 reiterates that "some older implementations based on 4.2BSD
* do not respond to these ... probes unless the segment contains data".
*
* (C) Therefore, RFC #1122, Section 4.2.3.6 states that a TCP "implementation ...
* MAY be configurable to send a [probe] segment containing one garbage octet,
* for compatibility with erroneous TCP implementations".
*
* (3) (a) (1) RFC #793, Sections 3.7 & 2.6 state that "TCP uses retransmission ... to ensure
* delivery of every segment".
*
* (2) However, RFC #1122, Section 4.2.2.17 'DISCUSSION' states that "it is extremely
* important to remember that ACK (acknowledgment) segments that contain no data
* are not reliably transmitted by TCP".
*
* Therefore, it is assumed that TCP acknowledgement/probe segments should NOT be
* queued for retransmission but SHOULD be silently discarded.
*
* (b) (1) The network buffer's reference counter is NOT incremented since the TCP layer
* does NOT maintain a reference to any transmitted TCP probe segments.
*
* (2) Therefore, the network buffer MUST be freed by lower layer(s).
*
* See also 'NetTCP_TxConnAck() Note #8',
* & 'NetTCP_TxConnReset() Note #6'.
*
* (4) On ANY errors, network resources MUST be appropriately freed :
*
* (a) For any network resources NOT linked to the TCP connection, each network resource
* MUST be freed by appropriate function(s).
*
* (5) #### IP options currently NOT implemented.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnProbe (NET_TCP_CONN *pconn,
CPU_BOOLEAN tx_probe_data_octet,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr)
{
#if ((((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) || \
(NET_CTR_CFG_STAT_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
CPU_BOOLEAN tx_probe;
#endif
NET_BUF_SIZE data_len;
NET_BUF_SIZE data_ix;
NET_BUF *pseg_probe;
NET_BUF_HDR *pseg_probe_hdr;
NET_IP_TOS TOS;
NET_IP_TTL TTL;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR ack_nbr;
NET_TCP_WIN_SIZE win_size;
CPU_INT16U flags_tcp;
CPU_INT16U flags_ip;
CPU_INT08U probe_data[NET_TCP_DATA_LEN_TX_PROBE_DATA];
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* See Note #2A. */
/* ----------- VALIDATE TCP CONN STATE ------------ */
tx_probe = DEF_NO;
if (pconn != (NET_TCP_CONN *)0) {
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
tx_probe = DEF_YES;
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
if (tx_probe != DEF_YES) { /* If NOT valid, abort tx TCP conn probe. */
*perr = NET_TCP_ERR_CONN_PROBE_INVALID;
return;
}
#else /* Prevent compiler warning. */
(void)&close_code;
#endif
/*$PAGE*/
/* ---------- PREPARE TCP CONN PROBE SEG ---------- */
/* If valid, prepare & tx TCP conn probe. */
/* Get buf. */
data_len = (tx_probe_data_octet == DEF_YES) /* Cfg data len for probe data (see Note #2b2C). */
? NET_TCP_DATA_LEN_TX_PROBE_DATA
: NET_TCP_DATA_LEN_TX_PROBE_NO_DATA;
data_ix = NET_BUF_DATA_TX_IX;
pseg_probe = NetBuf_Get((NET_BUF_SIZE) data_len,
(NET_BUF_SIZE) data_ix,
(CPU_INT16U ) NET_BUF_FLAG_NONE,
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) {
*perr = NET_TCP_ERR_NONE_AVAIL;
return;
}
if (tx_probe_data_octet == DEF_YES) { /* If tx probe data req'd, ... */
probe_data[0] = NET_TCP_TX_PROBE_DATA; /* ... prepare data (see Note #2b2) ... */
NetBuf_DataWr((NET_BUF *) pseg_probe, /* ... & wr data into TCP tx buf. */
(NET_BUF_SIZE) data_ix,
(NET_BUF_SIZE) data_len,
(CPU_INT08U *)&probe_data[0],
(NET_ERR *)&err);
if ( err != NET_BUF_ERR_NONE) { /* See Note #4a. */
NetBuf_Free(pseg_probe);
*perr = NET_TCP_ERR_CONN_FAIL;
return;
}
}
/* --------------- PREPARE TCP HDR ---------------- */
/* Prepare seg addrs. */
NetTCP_TxConnPrepareSegAddrs((NET_TCP_CONN *) pconn,
(CPU_INT08U *)&src_port,
(CPU_INT08U *)&src_addr,
(CPU_INT16U ) sizeof(src_port),
(CPU_INT16U ) sizeof(src_addr),
(CPU_INT08U *)&dest_port,
(CPU_INT08U *)&dest_addr,
(CPU_INT16U ) sizeof(dest_port),
(CPU_INT16U ) sizeof(dest_addr),
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) { /* See Note #4a. */
*perr = NET_TCP_ERR_CONN_FAULT;
NetBuf_Free(pseg_probe);
return;
}
/* Prepare TCP seq nbrs (see Note #1b2B). */
seq_nbr = pconn->TxSeqNbrNext - 1; /* Sub 1 from probe seq (see Note #2b1). */
ack_nbr = pconn->RxSeqNbrNext;
/* Prepare TCP tx flags (see Note #1b2C). */
flags_tcp = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_ACK;
/* Prepare TCP win size. */
win_size = pconn->RxWinSizeActual;
/* Prepare IP params. */
TOS = pconn->TxIP_TOS;
TTL = pconn->TxIP_TTL;
flags_ip = pconn->TxIP_Flags;
/* Init buf ctrls. */
pseg_probe_hdr = &pseg_probe->Hdr;
pseg_probe_hdr->DataIx = (CPU_INT16U )data_ix;
pseg_probe_hdr->DataLen = (NET_BUF_SIZE)data_len;
pseg_probe_hdr->TotLen = (NET_BUF_SIZE)pseg_probe_hdr->DataLen;
pseg_probe_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
pseg_probe_hdr->TCP_SegSync = (CPU_BOOLEAN )DEF_NO;
pseg_probe_hdr->TCP_SegClose = (CPU_BOOLEAN )DEF_NO;
pseg_probe_hdr->TCP_SegAck = (CPU_BOOLEAN )DEF_YES;
pseg_probe_hdr->TCP_SegReset = (CPU_BOOLEAN )DEF_NO;
pseg_probe_hdr->TCP_Flags = flags_tcp;
/*$PAGE*/
/* ------------ TX TCP CONN PROBE SEG ------------- */
NetTCP_TxPktHandler((NET_BUF *) pseg_probe,
(NET_IP_ADDR ) src_addr,
(NET_TCP_PORT_NBR) src_port,
(NET_IP_ADDR ) dest_addr,
(NET_TCP_PORT_NBR) dest_port,
(NET_TCP_SEQ_NBR ) seq_nbr,
(NET_TCP_SEQ_NBR ) ack_nbr,
(NET_TCP_WIN_SIZE) win_size,
(NET_IP_TOS ) TOS,
(NET_IP_TTL ) TTL,
(CPU_INT16U ) flags_tcp,
(CPU_INT16U ) flags_ip,
(void *) 0,
(void *) 0, /* See Note #5. */
(NET_ERR *)&err); /* Ignore transitory tx err(s). */
#if 0 /* Tx buf freed by lower layer(s) [see Note #3b2]. */
NetTCP_TxPktFree(pseg_probe);
#endif
NET_CTR_STAT_INC(NetTCP_StatTxSegConnProbeCtr);
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnKeepAlive()
*
* Description : (1) #### Prepare & transmit a TCP connection keep-alive :
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in ####
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection keep-alive successfully
* transmitted.
*
* Return(s) : none.
*
* Caller(s) : ####
*
* Note(s) : (2) RFC #1122, Section 4.2.3.6 states that "implementors MAY include 'keep-alives' in
* their TCP implementations, although this practice is not universally accepted ...
* A 'keep-alive' mechanism periodically probes the other end of a connection when
* the connection is otherwise idle, even when there is no data to be sent".
*
* (a) "If keep-alives are included," ...
*
* (1) "the application MUST be able to turn them on or off for each TCP connection,"
* (2) "and they MUST default to off."
*
* (b) "Keep-alive packets MUST only be sent when no data or acknowledgement packets have
* been received for the connection within an interval" :
*
* (1) "This interval MUST be configurable" ...
* (2) "and MUST default to no less than two hours."
*
* (c) "To confirm that an idle connection is still active ... send a probe segment ...
* to elicit a response from the peer TCP" :
*
* (1) "Such a segment generally contains SEG.SEQ = SND.NXT-1" ...
*
* (A) "Note that on a quiet connection SND.NXT = RCV.NXT, so that this SEG.SEQ will
* be outside the window. Therefore, the probe causes the receiver to return an
* acknowledgment segment, confirming that the connection is still live. If the
* peer has dropped the connection ... it will respond with a RST instead of an
* acknowledgment segment."
*
* (2) "and may or may not contain one garbage octet of data."
*
* (A) "An implementation SHOULD send a keep-alive segment with no data".
*
* (1) (a) "Unfortunately, some misbehaved TCP implementations fail to respond to
* a segment with SEG.SEQ = SND.NXT-1 unless the segment contains data."
*
* (b) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 23.3,
* Page 335 reiterates that "some older implementations based on 4.2BSD do
* not respond to these keepalive probes unless the segment contains data".
*
* (2) (a) Therefore, RFC #1122, Section 4.2.3.6 states that a TCP "implementation ...
* MAY be configurable to send a keep-alive segment containing one garbage
* octet, for compatibility with erroneous TCP implementations".
*
* (b) (1) "Alternatively, an implementation could determine whether a peer
* responded correctly to keep-alive packets with no garbage data octet."
*
* (2) (A) Or as Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section
* 23.3, Page 335 states, some "systems send the 4.3BSD-style segment
* (no data) for the first half of the probe period, and if no response
* is received, switch to the 4.2BSD-style segment for the last half".
*
* (B) Therefore, it seems reasonable to implement the combined BSD 4.3/4.2
* solution since it does NOT require any non-standard configuration
* for the garbage data octet & SHOULD be backwards-compatible with all
* other systems.
*
* (3) "It is extremely important to remember that ACK segments that contain no data
* are not reliably transmitted by TCP. Consequently, if a keep-alive mechanism
* is implemented it MUST NOT interpret failure to respond to any specific probe
* as a dead connection."
*********************************************************************************************************
*/
#if 0 /* #### NOT yet implemented. */
static void NetTCP_TxConnKeepAlive (NET_TCP_CONN *pconn,
NET_ERR *perr)
{
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnTxQ()
*
* Description : (1) Transmit TCP data segment(s) from TCP connection transmit queue :
*
* (a) Configure TCP connection transmit :
*
* (1) Configure TCP connection transmit acknowledgement request : See Note #1d1
*
* (A) Do NOT transmit TCP data/acknowledgement if ...
* (1) NO TCP transmit data available or allowed to transmit
* AND
* (2) NO transmit acknowledgement requested
*
* (B) Transmit TCP acknowledgement if ...
* (1) NO TCP transmit data available or allowed to transmit
* BUT
* (2) Transmit acknowledgement requested
*
* (2) Configure TCP connection transmit free timer request See Note #1d4
*
* (b) Transmit TCP connection transmit queue data :
*
* (1) Control TCP connection transmit versus transmit congestion controls :
*
* (a) See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2'
* & 'NetTCP_TxConnWinSizeUpdateAvail() Note #1'
*
* (A) Available Transmit Window See Note #1b1a
* (B) Transmit Queue Segment See Notes #5 & #8
* (C) Nagle Algorithm See Notes #6, #7b2B, & #8
* (D) Silly Window Syndrome See Notes #7 & #8
*
* (2) Update TCP connection transmit queue :
* (A) Remove TCP transmit segment(s) from
* TCP connection transmit queue See Note #3
* (B) Append TCP transmit segment(s) to
* TCP connection re-transmit queue See Note #4
* (C) Update TCP connection re-transmit queue timer
*
* (3) Update TCP connection :
* (A) Update TCP connection sequence number(s)
* (B) Update TCP connection transmit congestion window
*
* (4) Prepare TCP data/acknowledgement segment(s) :
* (A) TCP segment addresses
* (B) TCP segment sequence numbers
* (C) TCP segment transmit flags :
* (1) ACK
* (D) TCP segment window size
* (E) IP datagram parameters
* (F) TCP segment packet buffer controls
*
* (5) Transmit TCP data/acknowledgement segment(s)
*
* (c) Suspend TCP transmit : See Note #10
*
* (1) Handle any network receive packet(s) See Note #10b2A
*
* (d) Complete TCP connection transmit :
*
* (1) Transmit TCP connection acknowledgement See Note #1a1
* (2) Clear TCP connection transmit idle timer
* (see 'NetTCP_TxConnTxQ_TimeoutIdleClr() Note #2b2')
* (3) Reset TCP connection delayed acknowledgement controls
* (4) Free TCP connection transmit queue persist timer See Note #1a2
*
*
* (2) NetTCP_TxConnTxQ() transmits TCP connection data & acknowledgements. TCP acknowledgements
* transmitted independently of TCP controls &/or data MAY be transmitted with NetTCP_TxConnAck().
*
* See also 'NetTCP_TxConnAck() Note #2'.
*
*$PAGE*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in various.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
*
* tx_ack_code Indicate whether & how to transmit a TCP acknowledgement segment :
*
* NET_TCP_CONN_TX_ACK_NONE Do NOT transmit a TCP acknowledgement
* segment if TCP transmit data
* NOT available.
* NET_TCP_CONN_TX_ACK Transmit a TCP acknowledgement segment
* even if TCP transmit data NOT available.
* NET_TCP_CONN_TX_ACK_IMMED Transmit a TCP acknowledgement segment
* immediately even if TCP transmit data
* NOT available.
*
* tx_q_timeout Indicate whether the TCP connection transmit queue timed out :
*
* DEF_NO TCP connection transmit queue did
* NOT time out.
* DEF_YES TCP connection transmit queue
* timed out.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection transmit queue successfully
* handled.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_CLOSE TCP connection closed.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* ------- RETURNED BY NetTCP_TxConnAck() : -------
* NET_TCP_ERR_CONN_ACK_NONE TCP connection acknowledgement NOT requested.
* NET_TCP_ERR_CONN_ACK_DLYD TCP connection acknowledgement transmit delayed.
* NET_TCP_ERR_CONN_ACK_PREVLY_TXD TCP connection acknowledgement previously
* transmitted for segment.
* NET_TCP_ERR_CONN_ACK_INVALID TCP connection acknowledgement NOT valid for
* current TCP connection state.
* NET_TCP_ERR_NONE_AVAIL Resources NOT available.
* NET_TCP_ERR_INVALID_LEN_SEG Invalid TCP sequence-segment length.
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* ----- RETURNED BY NetTCP_TxPktHandler() : ------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_TCP_ERR_TX TCP transmit error (see Note #12a).
* NET_ERR_TX Transmit error.
*
* Return(s) : none.
*
* Caller(s) : various.
*$PAGE*
* Note(s) : (3) See 'NetTCP_TxConnAppData() Note #4' for TCP connection Transmit Queue diagram.
*
* (4) TCP segments that have been transmitted but NOT yet acknowledged are sequenced into
* the TCP connection's re-transmit queue to await acknowledgement or retransmission.
*
* (a) Transmitted TCP segments are inserted into a doubly-linked Re-Transmit Queue,
* ordered consecutively by sequence number(s) [see also Note #4b].
*
* (1) 'ReTxQ_Head' points to the head of the Re-Transmit Queue;
* 'ReTxQ_Tail' points to the tail of the Re-Transmit Queue.
*
* (2) Segment buffers' 'PrevPrimListPtr' & 'NextPrimListPtr' doubly-link each
* segment to form the Re-Transmit Queue.
*
* (b) Transmit segments are transmitted & await acknowledgement in sequence-order.
* Therefore, newly-transmitted segments are sequenced after previously transmitted
* segments starting at the tail of the Re-Transmit Queue.
*
* (c) Segments at the head of the Re-Transmit Queue are awaiting acknowledgement &
* removal from the Re-Transmit Queue; & are ready to be re-transmitted until
* acknowledged & removed from the queue.
*
*
* | |
* |<----- TCP Connection Re-Transmit Queue ------>|
* | (see Note #4) |
*
* Segments Awaiting
* Acknowledgement or Segments Sequenced
* Re-Transmit into Re-Transmit Queue
* start at head starting at tail
* (see Note #4c) (see Note #4b)
*
* | NextPrimListPtr |
* | (see Note #4a2) |
* v | v
* |
* Head of ------- ------- v ------- ------- (see Note #4a1)
* Re-Transmit ---->| |------>| |------>| |------>| |
* Queue | | | | | | | | Tail of
* | |<------| |<------| |<------| |<---- Re-Transmit
* (see Note #4a1) | | | | ^ | | | | Queue
* | | | | | | | | |
* ------- ------- | ------- -------
* |
* PrevPrimListPtr
* (see Note #4a2)
*
*$PAGE*
* (5) In order to simply TCP transmit buffer management, TCP transmit does NOT transmit
* partial network-buffer segments (i.e. portions of TCP segments in the same network
* buffer). This avoids the complexity of queuing & handling partially transmitted
* segments on both the TCP transmit & re-transmit queues.
*
* (a) However, in order to avoid transmit window deadlock with a remote host's receive
* window, the TCP connection's connection maximum segment size MUST be configured
* to ensure that full, maximum-segment-sized segments will transmit even for receive
* windows less than the default maximum segment size.
*
* See also 'NetTCP_ConnCfgMaxSegSize() Note #2'.
*
* (6) (a) (1) RFC #896, Section 'The small-packet problem' states that "there is a special
* problem associated with small packets ... the congestion ... can result in
* lost datagrams and retransmissions, as well as excessive propagation time ...
* In practice, throughput may drop so low that TCP connections are aborted".
*
* (2) RFC #896, Section 'The solution to the small-packet problem' states that "the
* solution to the small-packet problem ... is" :
*
* (A) "to inhibit the sending of new TCP segments when new outgoing data arrives
* from the user" ...
*
* (B) "if any previously transmitted data on the connection remains unacknowledged."
*
* (C) "This inhibition is to be unconditional;" :
* (1) "no timers," ...
* (2) "tests for size of data received, ...
* (3) "or other conditions are required."
*
* (b) (1) RFC #1122, Section 4.2.3.4 states that "the Nagle algorithm is ... as follows" :
*
* (A) "If there is unacknowledged data (i.e., SND.NXT > SND.UNA)," ...
* (B) "then the sending TCP buffers all user data" ...
* (1) "(regardless of the PSH bit)," ...
* (2) "until" :
* (a) "the outstanding data has been acknowledged" ...
* (b) "or until the TCP can send a full-sized segment."
*
* (2) (A) "A TCP SHOULD implement the Nalge Algorithm ... to coalesce short segments."
*
* (B) (1) "However, there MUST be a way for an application to disable the Nagle
* algorithm on an individual connection."
*
* (2) Thus, it is assumed from these two requirements that the Nagle algorithm
* should be enabled by default.
*
* See also Note #7b2Ba2A.
*$PAGE*
* (7) (a) RFC #813, Section 2 states that "a bad implementation of the window algorithm can
* lead to extremely poor performance ... This particular phenomenon ... has been
* given the name of Silly Window Syndrome, or SWS".
*
* Section 3 elaborates that "SWS is a degeneration in the throughput which develops
* ... whenever the acknowledgement of a small segment ... cause[s] another segment
* of the same small size to be sent, until ... the network ... becomes clogged with
* many small segments, and an equal number of acknowledgements".
*
* (b) (1) RFC #813, Section 4 states that "there is an algorithm that the sender can use
* ... [which] compares the useable window to the offered window, and refrains from
* anything if the ratio of useable to offered is less than a certain fraction ...
* Until the useable window reaches a certain amount, the sender should simply refuse
* to send anything".
*
* (2) (A) RFC #1122, Section 4.2.3.4 reiterates that "a TCP MUST include a SWS avoidance
* algorithm in the sender". However, "the SWS avoidance algorithm ... specified"
* in RFC #1122 "is to be used instead of the sender-side algorithm contained in
* [RFC #813]".
*
* (B) (a) RFC #1122, Section 4.2.3.4 states that "the sender's SWS avoidance algorithm
* is ... [to] send data" :
*
* (1) "If a maximum-sized segment can be sent, i.e, [sic] if" :
*
* (A) "min(D,U) >= Eff.snd.MSS"
* (1) (a) This threshold subtly assumes that the amount of data queued
* on the TCP connection's transmit queue is queued in maximum-
* sized segments.
* (b) Although this assumption is typically satisfied since all
* new TCP transmit data is usually aggregated & appended onto
* the TCP connection's transmit queue in maximum-sized segments
* (see 'NetTCP_TxConnAppData() Note #7b1'); to ensure that the
* maximum-sized-segment threshold is satisfied the transmit
* segment's length is also checked.
*
* (2) "Or if the data is pushed and all queued data can be sent now, i.e., if" :
*
* (A) "[SND.NXT = SND.UNA and] ...
* (1) "(the bracketed condition is imposed by the Nagle algorithm)"
* (2) (a) This condition is required ONLY if the Nagle algorithm
* is enabled (see Note #6b2B).
* (b) However, if the Nagle algorithm is disabled, the silly
* window syndrome threshold conditions MUST be checked
* (see Note #7b2Ba3).
*
* (B) "PUSHED and" ...
* (1) See also 'NetTCP_TxConnAppData() Note #7b3B1b'.
*
* (C) "D <= U"
* (1) (a) This threshold subtly assumes that the amount of data queued
* on the TCP connection's transmit queue is queued in maximum-
* sized segments.
* (b) To ensure that the next actual transmit segment is compared
* to the available transmit window, the following threshold is
* actually checked :
*
* (1) min(D, SEG.LEN) <= U
*
* See also Note #7b2Ba1A1.
*
* (3) "Or if at least a fraction Fs of the maximum window can be sent, i.e., if" :
*
* (A) "[SND.NXT = SND.UNA and]" ...
* (1) This condition is required ONLY if the Nagle algorithm is enabled
* (see Note #6b2B).
*
* (B) "min(D,U) >= Fs * Max(SND.WND)"
*$PAGE*
* (4) "or if" :
*
* (A) "data is PUSHed and" ...
* (1) Although it is not directly stated, it is inferred that if
* the segment(s)' data is NOT pushed, the segment transmit
* SHOULD be postponed until the previous transmit silly window
* syndrome avoidance conditions have NOT been satisfied (see
* Notes #7b2Ba1, #7b2Ba2, & #7b2Ba3).
*
* (2) See also 'NetTCP_TxConnAppData() Note #7b3B1b'.
*
* (B) "the override timeout occurs."
* (1) Although it is not directly stated, it is inferred that the
* transmit silly window override timer should be set when :
*
* (a) The previous transmit silly window syndrome avoidance
* conditions have NOT been satisfied (see Notes #7b2Ba1,
* #7b2Ba2, & #7b2Ba3) ...
* (b) BUT ...
* (1) the TCP segment data is pushed ...
* (2) & no current timeout exists.
*
* (2) However, if NO network timer is available to delay the TCP
* data segment(s), the TCP data segment(s) SHOULD be immediately
* transmitted.
*
* See also Note #7b2Bb.
*
*
* where
* (A) D Amount of data queued in the sending TCP but not
* yet sent
*
* (B) U 'Useable window' ... i.e., the offered window less
* the amount of data sent but not acknowledged :
*
* (1) U = SND.UNA + SND.WND - SND.NXT
*
* (2) The 'useable window' is also constrained by the
* available window & other TCP congestion controls
* (see 'NetTCP_TxConnWinSizeUpdateAvail() Note #1').
*
* (C) Eff.snd.MSS Effective send MSS for the connection
* (D) SND.NXT Next sequence number to transmit
* (E) SND.UNA Oldest unacknowledged sequence number
* (F) Max(SND.WND) Maximum send window ... seen ... on the connection
* (G) Fs Fraction whose recommended value is 1/2
*
*
* (b) (1) Although RFC #813, Section 4 stated "that it is not necessary to set
* a timer to protect against protocol lockup when postponing the send
* operation"; RFC #1122, Section 4.2.3.4 amends that "to avoid a ...
* deadlock, it is necessary to have a timeout to force transmission of
* data, overriding the SWS avoidance algorithm".
*
* (2) "The override timeout should be in the range 0.1 - 1.0 seconds."
*
* (3) "In practice, this timeout should seldom occur."
*$PAGE*
* (8) (a) Although it is not directly stated, it is inferred that the limitations of
* the Nagle & transmit silly window syndrome avoidance algorithms apply only
* to discrete, individually-queued data segments & NOT to any stream of data
* segments.
*
* Therefore, a data segment -- especially the last queued data segment in the
* TCP connection's transmit queue -- should NOT be constrained by the Nagle &
* transmit silly window syndrome avoidance algorithms if this last queued data
* segment is immediately transmitted after the transmission of the preceding
* queued data segments.
*
* See also 'NetTCP_TxConnAppData() Notes #7b1 & #7b3B2'.
*
* (b) Also, although NO RFC specifies the Nagle algorithm's or the transmit silly
* window syndrome avoidance algorithm's compliance, effect, or limitation on
* TCP connection closes; it does NOT seem reasonable for the Nagle algorithm
* or the transmit silly window syndrome avoidance algorithm to inhibit or
* delay the transmission of a TCP connection close segment.
*
* (9) Increment network buffer's reference counter to include the TCP segment now enqueued
* to the TCP connection's re-transmit queue as a new reference to the network buffer.
*
* (10) To balance network receive versus transmit packet loads for certain network connection
* types (e.g. stream-type connections), network receive & transmit packets SHOULD be
* handled in an APPROXIMATELY balanced ratio.
*
* (a) Network task priorities & lock mechanisms partially maintain a balanced ratio
* between network receive versus transmit packet handling.
*
* However, the handling of network receive & transmit packets :
*
* (1) SHOULD be interleaved so that for every few packet(s) received & handled,
* several packet(s) should be transmitted; & vice versa.
*
* (2) SHOULD NOT exclusively handle receive nor transmit packets, even for a
* short period of time.
*
* (b) To implement network receive versus transmit load balancing :
*
* (2) Certain network connections MUST periodically suspend network transmit(s)
* to handle network receive packet(s) :
*
* (A) Suspend network transmit(s) if network receive packets are available.
*
* (1) To approximate a balanced ratio of network receive versus transmit
* packets handled; the number of consecutive times that a network
* transmit suspends itself to check for & handle any network receive
* packet(s) SHOULD APPROXIMATELY correspond to the number of queued
* network receive packet(s) availabile.
*
* See also 'net.c Net_RxPktIsAvail() Note #2'.
*
* (2) To protect TCP connections from transmit corruption while suspended,
* ALL TCP data transmits & TCP transmit queue handling MUST be blocked
* for suspended connections until the connection is no longer suspended.
*
* (B) Signal or timeout network transmit suspend(s) to restart transmit(s).
*
* See also 'net.h NETWORK RECEIVE PACKET MACRO'S Note #1'.
*
* (11) On ANY errors, network resources MUST be appropriately freed :
*
* (a) For all network resources that have been linked to the TCP connection, ALL
* network resources are freed by NetTCP_ConnClose().
*
* (12) (a) Since segments enqueued to a TCP connection's transmit queue have already been
* reported as transmitted to the application & since no mechanism exists for a TCP
* connection to re-request previously transmitted data, any TCP connection whose
* transmit queue(s) becomes corrupted MUST be closed to force the application layer
* to abort &/or recover from the corrupted data.
*
* (b) For any internal errors where the TCP connection's transmit queue is NOT corrupted,
* the TCP connection is NOT closed.
*
* See also 'NetTCP_TxConnAppData() Note #10'
* & 'NetTCP_TxConnReTxQ() Note #11'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnTxQ (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_ACK_CODE tx_ack_code,
CPU_BOOLEAN tx_q_timeout,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr)
{
#if (((NET_CTR_CFG_STAT_EN == DEF_ENABLED) || \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_BUF *pseg;
NET_BUF *pseg_next;
NET_BUF *pbuf_q_tail;
NET_BUF_HDR *pseg_hdr;
NET_BUF_HDR *pseg_next_hdr;
NET_BUF_HDR *pbuf_q_tail_hdr;
NET_TMR_TICK timeout_tick;
NET_IP_TOS TOS;
NET_IP_TTL TTL;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR ack_nbr;
NET_TCP_WIN_SIZE win_size;
NET_TCP_WIN_SIZE tx_data_qd;
NET_TCP_WIN_SIZE tx_data_min;
NET_TCP_WIN_SIZE tx_th_q_min;
NET_TCP_TX_Q_STATE state;
CPU_INT16U flags_tcp;
CPU_INT16U flags_ip;
CPU_BOOLEAN tx_ack;
CPU_BOOLEAN tx_seg;
CPU_BOOLEAN tx_seg_push;
CPU_BOOLEAN tx_seg_close;
CPU_BOOLEAN tx_segs_txd;
CPU_BOOLEAN tx_segs;
CPU_BOOLEAN tx_done;
CPU_BOOLEAN tx_th_seg;
CPU_BOOLEAN tx_th_mss;
CPU_BOOLEAN tx_th_nagle;
CPU_BOOLEAN tx_th_silly_win;
CPU_BOOLEAN tx_tmr_free;
CPU_BOOLEAN net_rx_avail;
NET_CTR net_rx_nbr;
NET_ERR err;
NET_ERR err_rtn;
/* ------------------ CFG TCP TX ------------------ */
switch (tx_ack_code) { /* Cfg tx ack req. */
case NET_TCP_CONN_TX_ACK_NONE:
default:
tx_ack = DEF_NO;
break;
case NET_TCP_CONN_TX_ACK:
case NET_TCP_CONN_TX_ACK_IMMED:
tx_ack = DEF_YES;
break;
}
/* Cfg tx tmr free req. */
tx_tmr_free = (pconn->TxQ_Head == (NET_BUF *)0) ? DEF_YES : DEF_NO;
/*$PAGE*/
switch (pconn->ConnState) { /* Cfg tx Q seg(s). */
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
tx_segs = DEF_YES;
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
tx_segs = DEF_YES;
break;
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* See Note #10b2A2. */
tx_segs = DEF_NO;
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
default:
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_CLOSED:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, DEF_YES, close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
err_rtn = NET_TCP_ERR_NONE;
/*$PAGE*/
/* ---------- TX DATA FROM TCP CONN TX Q ---------- */
pseg_next = pconn->TxQ_Head;
tx_done = (tx_segs == DEF_YES) ? DEF_NO : DEF_YES;
tx_segs_txd = DEF_NO;
while (tx_done == DEF_NO) { /* Tx ALL TCP conn tx Q seg(s) ... */
/* ... allowed by cong ctrls (see Note #1b1). */
tx_seg = DEF_NO;
pseg = pseg_next;
if (pseg != (NET_BUF *)0) {
pseg_hdr = (NET_BUF_HDR *)&pseg->Hdr;
pseg_next = (NET_BUF *) pseg_hdr->NextPrimListPtr;
/* ----------------- CTRL TCP TX ------------------ */
/* Validate tx win cong th's : ... */
if (pconn->TxWinSizeAvail >= pseg_hdr->TCP_SegLenData) {/* ... chk avail tx win >= seg len (see Note #5); */
tx_seg = DEF_YES;
/* ... chk prev'ly tx'd seg(s) [see Note #8a]; ... */
/* ... or TCP conn close seg [see Note #8b]; ... */
tx_seg_close = DEF_BIT_IS_SET(pseg_hdr->TCP_Flags, NET_TCP_FLAG_TX_CLOSE);
tx_th_seg = ((tx_segs_txd == DEF_YES) ||
(tx_seg_close == DEF_YES)) ? DEF_OK : DEF_FAIL;
if (tx_th_seg != DEF_OK) {
/* ... chk MSS th (see Note #7b2Ba1); ... */
tx_data_qd = (NET_TCP_WIN_SIZE)(pconn->TxSeqNbrNextQ - pconn->TxSeqNbrNext);
tx_data_min = (NET_TCP_WIN_SIZE) DEF_MIN(tx_data_qd, pseg_hdr->TCP_SegLenData);
tx_th_q_min = (NET_TCP_WIN_SIZE) DEF_MIN(tx_data_min, pconn->TxWinSizeAvail);
tx_th_mss = (tx_th_q_min >= pconn->MaxSegSizeConn) ? DEF_OK : DEF_FAIL;
if (tx_th_mss != DEF_OK) {
/* ... chk Nagle th (see Note #7b2Ba2); ... */
tx_seg_push = DEF_BIT_IS_SET(pseg_hdr->TCP_Flags, NET_TCP_FLAG_TX_PUSH);
tx_th_nagle = ((pconn->TxWinSizeNagleEn != DEF_DISABLED ) &&
(pconn->TxSeqNbrNext == pconn->TxSeqNbrUnAckd) &&
(tx_seg_push == DEF_YES ) &&
(tx_data_min <= pconn->TxWinSizeAvail)) ? DEF_OK : DEF_FAIL;
if (tx_th_nagle != DEF_OK) {
/* ... chk silly win th (see Note #7b2Ba3); ... */
tx_th_silly_win = (((pconn->TxWinSizeNagleEn == DEF_DISABLED ) ||
(pconn->TxSeqNbrNext == pconn->TxSeqNbrUnAckd)) &&
(tx_th_q_min >= pconn->TxWinSizeMinTh)) ? DEF_OK : DEF_FAIL;
if (tx_th_silly_win != DEF_OK) {
/* ... chk push timeout (see Note #7b2Ba4). */
if (tx_seg_push == DEF_YES) { /* If data seg pushed (see Note #7b2Ba4A), ... */
if (tx_q_timeout == DEF_NO) { /* ... & no cur timeout (see Note #7b2Ba4B1b2), ... */
/* ... & tx Q tmr NOT yet cfg'd, ... */
if (pconn->TxQ_SillyWinTmr == (NET_TMR *)0) {
timeout_tick = ((NET_TMR_TICK)pconn->TxWinSillyWinTimeout_ms * NET_TMR_TIME_TICK_PER_SEC)
/ DEF_TIME_NBR_mS_PER_SEC;
pconn->TxQ_SillyWinTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_TxConnTxQ_TimeoutSillyWin,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
/* ... & tx Q tmr avail, ... */
if (err == NET_TMR_ERR_NONE) {
tx_seg = DEF_NO; /* ... dly tx seg (see Note #7b2Ba4B1); ... */
} /* ... else tx seg (see Note #7b2Ba4B2). */
} else { /* Else tx Q tmr already cfg'd, ... */
tx_seg = DEF_NO; /* ... dly tx seg (see Note #7b2Ba4B1). */
}
}
} else { /* If data seg NOT pushed, ... */
tx_seg = DEF_NO; /* ... dly tx seg (see Note #7b2Ba4A1). */
}
}
}
}
}
}
}
/*$PAGE*/
/* ----------------- TX TCP SEGS ------------------ */
if (tx_seg == DEF_YES) { /* If avail & rdy, tx Q seg(s). */
/* ------------ UPDATE TCP CONN TX Q's ------------ */
/* Move seg from tx Q to re-tx Q : */
if (pseg_next != (NET_BUF *)0) { /* If tx Q next seg(s) avail, ... */
/* ... update TCP conn tx Q. */
pseg_next_hdr = (NET_BUF_HDR *)&pseg_next->Hdr;
pseg_next_hdr->PrevPrimListPtr = (void *) 0;
pconn->TxQ_Head = (NET_BUF *) pseg_next;
} else { /* Else clr tx Q. */
pconn->TxQ_Head = (NET_BUF *)0;
pconn->TxQ_Tail = (NET_BUF *)0;
tx_tmr_free = DEF_YES;
}
pseg_hdr->PrevPrimListPtr = (void *)pconn->ReTxQ_Tail;
pseg_hdr->NextPrimListPtr = (void *)0;
if (pconn->ReTxQ_Tail != (NET_BUF *)0) { /* If re-tx Q NOT empty, ... */
/* ... append seg(s) @ Q tail (see Note #4b). */
pbuf_q_tail = (NET_BUF *) pconn->ReTxQ_Tail;
pbuf_q_tail_hdr = (NET_BUF_HDR *)&pbuf_q_tail->Hdr;
pbuf_q_tail_hdr->NextPrimListPtr = (void *) pseg;
pconn->ReTxQ_Tail = (NET_BUF *) pseg;
} else { /* Else add seg to empty re-tx Q. */
pconn->ReTxQ_Head = (NET_BUF *) pseg;
pconn->ReTxQ_Tail = (NET_BUF *) pseg;
}
if (pconn->ReTxQ_Tmr == (NET_TMR *)0) { /* If unavail, get & update re-tx Q tmr. */
NetTCP_TxConnReTxQ_TimeoutSet(pconn, DEF_NO, close_code, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
/* --------------- UPDATE TCP CONN ---------------- */
/* Update TCP conn tx seq nbr(s). */
pconn->TxSeqNbrNext += (NET_TCP_SEQ_NBR)pseg_hdr->TCP_SegLen;
/* Update TCP conn tx win ctrls (see Note #3a2). */
NetTCP_TxConnWinSizeHandlerCongCtrl((NET_TCP_CONN *) pconn,
(NET_BUF_HDR *) 0,
(NET_TCP_ACK_CODE) NET_TCP_CONN_RX_ACK_NONE,
(NET_TCP_WIN_SIZE) pseg_hdr->TCP_SegLenData,
(NET_TCP_WIN_CODE) NET_TCP_CONN_TX_WIN_DEC,
(NET_ERR *)&err);
if ( err != NET_TCP_ERR_NONE) {
*perr = NET_TCP_ERR_CONN_FAULT;
return;
}
/*$PAGE*/
/* --------- PREPARE TCP TX DATA/ACK SEG ---------- */
/* Prepare TCP seg addrs. */
src_port = (NET_TCP_PORT_NBR)pseg_hdr->TCP_UDP_PortSrc;
src_addr = (NET_IP_ADDR )pseg_hdr->IP_AddrSrc;
dest_port = (NET_TCP_PORT_NBR)pseg_hdr->TCP_UDP_PortDest;
dest_addr = (NET_IP_ADDR )pseg_hdr->IP_AddrDest;
/* Prepare TCP seq nbrs. */
seq_nbr = (NET_TCP_SEQ_NBR )pseg_hdr->TCP_SeqNbr;
ack_nbr = (NET_TCP_SEQ_NBR )pconn->RxSeqNbrNext;
/* Prepare TCP tx flags. */
flags_tcp = pseg_hdr->TCP_Flags;
/* Prepare TCP win size. */
win_size = pconn->RxWinSizeActual;
/* Prepare IP params. */
TOS = pconn->TxIP_TOS;
TTL = pconn->TxIP_TTL;
flags_ip = pconn->TxIP_Flags;
/* Update TCP tx buf ctrls. */
pseg_hdr->TCP_SeqNbrLast = (CPU_INT32U)seq_nbr;
pseg_hdr->TCP_AckNbrLast = (CPU_INT32U)ack_nbr;
pseg_hdr->TCP_SegLenLast = (CPU_INT16U)pseg_hdr->TCP_SegLen;
pseg_hdr->TCP_WinSizeLast = (CPU_INT16U)win_size;
pseg_hdr->TCP_SegReTxCtr = (CPU_INT16U)0;
pseg_hdr->RefCtr++; /* TCP maintains ref until seg ack'd (see Note #9). */
/* ------------- TX TCP DATA/ACK SEG -------------- */
NetTCP_TxPktHandler((NET_BUF *) pseg,
(NET_IP_ADDR ) src_addr,
(NET_TCP_PORT_NBR) src_port,
(NET_IP_ADDR ) dest_addr,
(NET_TCP_PORT_NBR) dest_port,
(NET_TCP_SEQ_NBR ) seq_nbr,
(NET_TCP_SEQ_NBR ) ack_nbr,
(NET_TCP_WIN_SIZE) win_size,
(NET_IP_TOS ) TOS,
(NET_IP_TTL ) TTL,
(CPU_INT16U ) flags_tcp,
(CPU_INT16U ) flags_ip,
(void *) 0,
(void *) 0,
(NET_ERR *)&err_rtn);
switch (err_rtn) {
case NET_TCP_ERR_NONE: /* If NO tx err(s); ... */
tx_segs_txd = DEF_YES; /* ... indicate seg(s) tx'd, ... */
NET_CTR_STAT_INC(NetTCP_StatTxSegConnTxQ_Ctr); /* ... & inc tx seg stat ctr. */
break;
case NET_ERR_INIT_INCOMPLETE: /* Else indicate tx done. */
case NET_ERR_TX:
tx_done = DEF_YES;
break;
case NET_TCP_ERR_TX: /* See Note #12a. */
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, close_code);
*perr = err_rtn;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
} else { /* Else if seg NOT tx'd, ... */
tx_done = DEF_YES; /* ... indicate tx done. */
}
/*$PAGE*/
/* ---------------- SUSPEND TCP TX ---------------- */
if (tx_done == DEF_NO) { /* If tx NOT done .. */
net_rx_nbr = 0;
net_rx_avail = Net_RxPktIsAvail(net_rx_nbr);
if (net_rx_avail == DEF_YES) { /* .. & net rx avail; .. */
state = pconn->TxQ_State; /* .. save TCP conn tx Q state, .. */
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN_SUSPEND; /* .. set TCP conn tx Q state to SUSPEND; .. */
NetOS_Unlock();
do {
Net_TxSuspend(); /* .. suspend tx to handle net rx (see Note #10b2A) */
net_rx_nbr++;
net_rx_avail = Net_RxPktIsAvail(net_rx_nbr);
} while (net_rx_avail == DEF_YES); /* .. while net rx avail (see Note #10b2A1). */
NetOS_Lock(&err);
if ( err != NET_OS_ERR_NONE) {
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, close_code);
*perr = NET_TCP_ERR_CONN_CLOSE;
return;
}
switch (pconn->TxQ_State) { /* Validate TCP conn tx Q state. */
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* If still SUSPEND state, .. */
pconn->TxQ_State = state; /* .. restore TCP conn tx Q state. */
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED: /* If CLOSED state, close TCP conn. */
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
default:
NetTCP_ConnClose(pconn, pbuf_hdr, pconn->ConnCloseAppFlag, close_code);
*perr = NET_TCP_ERR_CONN_CLOSE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
}
}
/* --------------- COMPLETE TCP TX ---------------- */
if (tx_segs_txd != DEF_YES) { /* If NO tx Q seg(s) tx'd, ... */
if (tx_ack == DEF_YES) { /* ... but tx ack req'd; ... */
/* ... tx TCP conn ack (see Note #1c1). */
NetTCP_TxConnAck(pconn, pbuf_hdr, tx_ack_code, close_code, &err_rtn);
}
} else { /* Else if ANY tx Q seg(s) tx'd; .. */
NetTCP_TxConnTxQ_TimeoutIdleClr(pconn); /* .. clr tx Q idle tmr (see Note #1c2), .. */
NetTCP_TxConnAckDlyReset(pconn, DEF_YES); /* .. reset ack dly ctrls, .. */
tx_tmr_free = DEF_YES; /* .. free tx Q tmr. */
}
if (tx_tmr_free == DEF_YES) { /* If free tx Q tmr req'd, .. */
if (pconn->TxQ_SillyWinTmr != (NET_TMR *)0) { /* .. & tx Q tmr avail, .. */
if (tx_q_timeout == DEF_NO) { /* .. & NOT timed out, .. */
/* .. free tx Q tmr. */
NetTmr_Free(pconn->TxQ_SillyWinTmr);
}
pconn->TxQ_SillyWinTmr = (NET_TMR *)0;
}
}
*perr = err_rtn; /* Rtn err from tx handler(s). */
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnTxQ_TimeoutIdle()
*
* Description : (1) (a) Handle TCP connection's transmit queue idle timeout ... :
*
* (1) Clear TCP connection's transmit idle timer See Note #4aA1
* (2) Reset TCP connection's transmit congestion window controls See Note #2a
* (3) Reset TCP connection's transmit round-trip time controls See Note #2b
*
* (b) ... for the following states :
*
* (1) ESTABLISHED
* (2) FIN-WAIT-1
* (3) CLOSING
* (4) CLOSE-WAIT
* (5) LAST-ACK
*
*
* Argument(s) : pconn_timeout Pointer to TCP connection (see Note #3b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_TxConnTxQ_TimeoutIdleSet().
*
* Note(s) : (2) (a) RFC #2581, Section 4.1 states that "after TCP has been idle for a relatively long period
* of time ... use slow start to restart transmission" :
*
* (1) (A) "When TCP has not received a segment for more than one retransmission timeout," ...
* (B) "cwnd is reduced to the value of the restart window."
*
* (2) However, RFC #2581, Section 4.1 re-states that "using the last time a segment was
* received to determine whether or not to decrease cwnd fails to deflate cwnd in the
* common case of persistent ... connections ... The reception of [segments] makes the
* test for an idle connection fail, and allows the TCP to begin transmission with a
* possibly inappropriately large cwnd."
*
* (A) "Therefore, ... if the TCP has not sent data ... in an interval exceeding the
* retransmission timeout" ...
*
* (B) "a TCP SHOULD set cwnd to no more than RW before beginning transmission."
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Note #2e1'.
*
* (b) Similarly, although NO RFC specifies that a TCP connection's RTT average & deviation
* should be reset following a TCP transmit idle timeout; it seems reasonable to reset a
* TCP connection's RTT average & deviation controls whenever a TCP connection's transmit
* is idle for a period exceeding the re-transmit timeout.
*
* See also 'NetTCP_TxConnRTT_RTO_Calc() Note #2a4B'.
*$PAGE*
* (3) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (4) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) ... :
*
* (A) TCP connection transmit queue idle timer ('TxQ_IdleTmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared prior to next handler function(s) as an extra precaution to avoiding
* re-freeing the timer (see Note #4a2B).
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_TX_IDLE
*
* (5) Certain network connections MUST periodically suspend network transmit(s) to handle
* network receive packet(s). To protect TCP connections from transmit corruption while
* suspended, ALL TCP data transmits & TCP transmit queue handling MUST be blocked for
* suspended connections until the connection is no longer suspended.
*
* However, handling the TCP connection's transmit queue idle timeout is permitted since
* NO TCP data is transmitted & the TCP connection's transmit queue is NOT handled (see
* Note #1a).
*
* See also 'NetTCP_TxConnTxQ() Note #10b2A2',
* 'NetTCP_TxConnTxQ_TimeoutSillyWin() Note #5',
* 'NetTCP_TxConnReTxQ_Timeout() Note #5',
* & 'NetTCP_TxConnWinSizeZeroWinTimeout() Note #5'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnTxQ_TimeoutIdle (void *pconn_timeout)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NET_TCP_CLOSE_CODE close_code;
#endif
NET_TCP_CONN *pconn;
NET_ERR err;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #3b2A. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_TX_IDLE); /* See Note #4b1. */
/* ------------ VALIDATE TCP CONN ------------- */
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CONN: /* See Note #1. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* See Note #5. */
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' warning. */
}
#endif
/*$PAGE*/
/* ---- HANDLE TCP CONN TX Q IDLE TIMEOUT ----- */
pconn->TxQ_IdleTmr = (NET_TMR *)0; /* Clr tx Q idle tmr (see Note #4a2A1). */
/* Reset tx win ctrls (see Note #2a2B). */
NetTCP_TxConnWinSizeHandlerCongCtrl((NET_TCP_CONN *) pconn,
(NET_BUF_HDR *) 0,
(NET_TCP_ACK_CODE) NET_TCP_CONN_RX_ACK_NONE,
(NET_TCP_WIN_SIZE) 0,
(NET_TCP_WIN_CODE) NET_TCP_CONN_TX_WIN_RESET,
(NET_ERR *)&err);
/* Reset RTT ctrls (see Note #2b). */
NetTCP_TxConnRTT_RTO_Calc(pconn, NET_TCP_CONN_TX_RTT_RESET, NET_TCP_TX_RTT_NONE, NET_TCP_TX_RTT_NONE);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnTxQ_TimeoutIdleSet()
*
* Description : (1) Start TCP connection's transmit queue idle timeout for the following states :
*
* (a) SYN-RECEIVED
* (b) SYN-SENT
* (c) ESTABLISHED
* (d) FIN-WAIT-1
* (e) CLOSING
* (f) CLOSE-WAIT
* (g) LAST-ACK
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandlerReTxQ().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerReTxQ().
*
* Note(s) : (2) (a) RFC #2581, Section 4.1 states that "after TCP has been idle for a relatively long period
* of time ... use slow start to restart transmission" :
*
* (1) "If the TCP has not sent data in an interval exceeding the retransmission timeout" ...
* (2) "cwnd is reduced to ... no more than ... the value of the restart window."
*
* See also 'NetTCP_TxConnTxQ_TimeoutIdle() Note #2a'.
*
* (b) However, if NO network timer is available to time the transmit queue idle interval, the
* TCP connection SHOULD be immediately slow started.
*********************************************************************************************************
*/
static void NetTCP_TxConnTxQ_TimeoutIdleSet (NET_TCP_CONN *pconn)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TMR_TICK timeout_tick;
NET_ERR err;
/*$PAGE*/
/* ------------ VALIDATE TCP CONN ------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #1a. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD: /* See Note #1b. */
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
break;
case NET_TCP_CONN_STATE_CONN: /* See Note #1c. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' warning. */
}
/* ------ START TCP CONN TX Q IDLE TMR ------- */
timeout_tick = pconn->TxRTT_RTO_tick; /* Tx Q idle timeout = RTO (see Note #2a1). */
if (pconn->TxQ_IdleTmr == (NET_TMR *)0) { /* If tx Q idle tmr NOT avail, ... */
pconn->TxQ_IdleTmr = NetTmr_Get((void *) pconn, /* ... get tx Q idle tmr. */
(CPU_FNCT_PTR) NetTCP_TxConnTxQ_TimeoutIdle,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
} else { /* Else set tx Q idle tmr. */
NetTmr_Set((NET_TMR *) pconn->TxQ_IdleTmr,
(CPU_FNCT_PTR) NetTCP_TxConnTxQ_TimeoutIdle,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
}
if (err != NET_TMR_ERR_NONE) { /* If any err(s), ... */
/* ... reset tx win ctrls (see Note #2b). */
NetTCP_TxConnWinSizeHandlerCongCtrl((NET_TCP_CONN *) pconn,
(NET_BUF_HDR *) 0,
(NET_TCP_ACK_CODE) NET_TCP_CONN_RX_ACK_NONE,
(NET_TCP_WIN_SIZE) 0,
(NET_TCP_WIN_CODE) NET_TCP_CONN_TX_WIN_RESET,
(NET_ERR *)&err);
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnTxQ_TimeoutIdleClr()
*
* Description : (1) Clear TCP connection's transmit queue idle timer for the following states :
*
* (a) ESTABLISHED
* (b) FIN-WAIT-1
* (c) CLOSING
* (d) CLOSE-WAIT
* (e) LAST-ACK
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnTxQ().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnTxQ().
*
* Note(s) : (2) (a) RFC #2581, Section 4.1 states that "after TCP has been idle for a relatively long period
* of time ... use slow start to restart transmission" :
*
* (1) "If the TCP has not sent data in an interval exceeding the retransmission timeout" ...
* (2) "cwnd is reduced to ... no more than ... the value of the restart window."
*
* See also 'NetTCP_TxConnTxQ_TimeoutIdle() Note #2a'.
*
* (b) (1) However, if the TCP connection's re-transmit queue is NOT empty, then TCP data has
* has been transmitted & is awaiting acknowledgement.
*
* (2) Therefore, NO transmit queue idle timeout is currently needed.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnTxQ_TimeoutIdleClr (NET_TCP_CONN *pconn)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_BOOLEAN tmr_free;
/* ------------ VALIDATE TCP CONN ------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' warning. */
case NET_TCP_CONN_STATE_CONN: /* See Note #1. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND:
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
return; /* Prevent 'break NOT reachable' warning. */
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' warning. */
}
/* ------- CLR TCP CONN TX Q IDLE TMR -------- */
tmr_free = (pconn->ReTxQ_Head != (NET_BUF *)0) ? DEF_YES : DEF_NO;
if (tmr_free == DEF_YES) { /* If re-tx Q NOT empty (see Note #2b1), ... */
if (pconn->TxQ_IdleTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->TxQ_IdleTmr); /* ... free tx Q idle tmr (see Note #2b2). */
pconn->TxQ_IdleTmr = (NET_TMR *)0;
}
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnTxQ_TimeoutSillyWin()
*
* Description : (1) (a) Handle TCP connection's transmit queue silly window timeout ... :
*
* (1) Clear TCP connection's transmit silly window persist timer See Note #4aA1
* (2) Transmit TCP connection's transmit data See Note #2
*
* (b) ... for the following states :
*
* (1) ESTABLISHED
* (2) FIN-WAIT-1
* (3) CLOSING
* (4) CLOSE-WAIT
* (5) LAST-ACK
*
*
* Argument(s) : pconn_timeout Pointer to TCP connection (see Note #3b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_TxConnTxQ().
*
* Note(s) : (2) RFC #1122, Section 4.2.3.4 states that on "timeout ... force transmission of data,
* overriding the SWS avoidance algorithm".
*
* See also 'NetTCP_TxConnTxQ() Note #7b2Bb'.
*
* (3) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (4) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) ... :
*
* (A) TCP connection transmit silly window persist timer ('TxQ_SillyWinTmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared prior to next handler function(s) as an extra precaution to
* avoiding re-freeing the timer (see Note #4a2B).
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN
*
* (5) Certain network connections MUST periodically suspend network transmit(s) to handle
* network receive packet(s). To protect TCP connections from transmit corruption while
* suspended, ALL TCP data transmits & TCP transmit queue handling MUST be blocked for
* suspended connections until the connection is no longer suspended.
*
* (a) The transmit queue silly window timeout is re-configured with one timer tick to
* ensure that a non-zero delay is implemented.
*
* (b) If NO timer is available, a TCP connection will NOT be able to re-schedule the
* transmission of its TCP transmit queue data. Thus, the TCP transmit queue data
* will be delayed until triggered by any received acknowledgement packets or by
* additional data transmits from the applications layer.
*
* See also 'NetTCP_TxConnTxQ() Note #10b2A2',
* 'NetTCP_TxConnTxQ_TimeoutIdle() Note #5',
* 'NetTCP_TxConnReTxQ_Timeout() Note #5',
* & 'NetTCP_TxConnWinSizeZeroWinTimeout() Note #5'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnTxQ_TimeoutSillyWin (void *pconn_timeout)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CLOSE_CODE close_code;
NET_TMR_TICK timeout_tick;
NET_ERR err;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #3b2A. */
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN); /* See Note #4b1. */
/* -------------- VALIDATE TCP CONN --------------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
#endif
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CONN: /* See Note #1. */
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
break;
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* See Note #5. */
timeout_tick = (NET_TMR_TICK)1; /* See Note #5a. */
pconn->TxQ_SillyWinTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_TxConnTxQ_TimeoutSillyWin,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
(void)err; /* Ignore transitory rsrc err(s) [see Note #5b]. */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/*$PAGE*/
/* ---- HANDLE TCP CONN TX Q SILL WIN TIMEOUT ----- */
pconn->TxQ_SillyWinTmr = (NET_TMR *)0; /* Clr tx Q silly win tmr (see Note #4a2A1). */
NetTCP_TxConnTxQ((NET_TCP_CONN *) pconn, /* Tx Q data (see Note #2). */
(NET_BUF_HDR *) 0,
(NET_TCP_ACK_CODE ) NET_TCP_CONN_TX_ACK_NONE,
(CPU_BOOLEAN ) DEF_YES,
(NET_TCP_CLOSE_CODE) close_code,
(NET_ERR *)&err); /* Ignore ALL tx err(s), transitory or fatal. */
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnReTxQ()
*
* Description : (1) Re-transmit TCP data segment(s) from TCP connection re-transmit queue :
*
* (a) Update TCP connection :
* (1) Update TCP connection's re-transmit queue timeout :
* (A) Update TCP connection's re-transmit queue timer See Note #2b
* (B) Reset TCP connection's transmit round-trip time See Note #2b2A2
* controls
* (2) Update TCP connection's transmit congestion controls :
* (A) Update TCP connection's transmit congestion window See Note #5
* (B) Reset TCP connection's delayed acknowledgement controls See Note #6
*
* (b) Prepare TCP segment re-transmit :
* (1) Prepare unchanged TCP segment for re-transmit See Note #7
*
* (2) Prepare updated TCP segment for re-transmit :
* (A) TCP segment sequence numbers
* (B) TCP segment window size
* (C) TCP segment addresses
* (D) TCP segment transmit flags
* (E) IP datagram parameters
* (F) Update TCP segment's last transmit values :
* (1) Sequence Number
* (2) Acknowledgement Number
* (3) Segment Length
* (4) Window Size
* (G) Unlink TCP segment packet buffer from any other network layer(s)
* (H) Update TCP segment packet buffer controls
*
* (c) Re-transmit TCP segment See Note #2a
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnReTxQ_Timeout(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*
* re_tx_q_timeout Indicate whether the TCP connection re-transmit queue timed out :
*
* DEF_NO TCP connection re-transmit queue did
* NOT time out.
* DEF_YES TCP connection re-transmit queue
* timed out.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection re-transmit queue successfully handled.
* NET_TCP_ERR_RE_TX_SEG_TH TCP connection closed due to excessive retransmission.
*
* --- RETURNED BY NetTCP_TxConnReTxQ_TimeoutSet() : ----
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* -------- RETURNED BY NetTCP_TxPktHandler() : ---------
* ------------- RETURNED BY NetIP_ReTx() : -------------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_ERR_TX Transmit error.
*
* -------- RETURNED BY NetTCP_TxPktHandler() : ---------
* NET_TCP_ERR_TX TCP transmit error (see Note #11a).
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnReTxQ_Timeout(),
* NetTCP_TxConnWinSizeHandlerCongCtrl().
*$PAGE*
* Note(s) : (2) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : RETRANSMISSION TIMEOUT'
* states that "for any state if the retransmission timeout expires on a segment in
* the retransmission queue" :
*
* (A) RFC #1122, Section 4.2.3.1 reiterates that "retransmission of SYN segments
* SHOULD use the same algorithm as data segments".
*
* (a) "Send the segment at the front of the retransmission queue."
*
* (A) RFC #2988, Section 5.4 reiterates that "when the retransmission timer
* expires ... retransmit the earliest segment that has not been acknowledged
* by the TCP receiver".
*
* (1) RFC #1122, Section 4.2.2.16 states that "a TCP receiver SHOULD NOT shrink the
* window ... However, a sending TCP MUST be robust against window shrinking ...
* If this happens, the sender SHOULD NOT send new data, but SHOULD retransmit
* normally the old unacknowledged data between SND.UNA and SND.UNA+SND.WND. The
* sender MAY also retransmit old data beyond SND.UNA+SND.WND, but SHOULD NOT time
* out the connection if data beyond the right window edge is not acknowledged".
*
* Therefore, ALL data segments previously transmitted & awaiting acknowledgement
* in a TCP connections' re-transmit queue may be re-transmitted regardless of the
* TCP connection's current transmit congestion control window size or the remote
* host's receive window size.
*
* (2) (A) RFC #2581, Section 3.2 states that "the fast retransmit algorithm uses the
* arrival of 3 duplicate ACKs ... as an indication that a segment has been
* lost ... [and] performs a retransmission of what appears to be the missing
* segment".
*
* (B) RFC #1122, Section 4.2.2.21 reiterates that "'fast retransmit' ... uses the
* redundant ACK's to deduce that a segment has been lost ... If more than a
* threshold number of such ACK's is received, then the segment containing the
* octets starting at SEG.ACK is assumed to have been lost and is retransmitted".
*
* (b) "Reinitialize the retransmission timer."
*
* (1) RFC #2988, Section 5 states that "an implementation MUST manage the retransmission
* timer(s) in such a way that a segment is never retransmitted too early, i.e. less
* than one RTO after the previous transmission of that segment".
*
* (A) "The following is the RECOMMENDED algorithm for managing the retransmission
* timer" :
*
* (1) "Every time a packet containing data is sent (including a retransmission),
* if the timer is not running, start it running so that it will expire after
* RTO seconds (for the current value of RTO)."
*
* Therefore, the TCP connection re-transmit queue timer is reset whenever a
* segment is re-transmitted.
*
* (2) "When all outstanding data has been acknowledged, turn off the retransmission
* timer."
*
* (3) "When an ACK is received that acknowledges new data, restart the retransmission
* timer so that it will expire after RTO seconds (for the current value of RTO)."
*
* (B) "When the retransmission timer expires, do the following" :
*
* (5) "The host MUST set RTO <- RTO * 2 ('back off the timer')."
*
* See also Note #2b2A1.
*
* (6) "Start the retransmission timer, such that it expires after RTO seconds
* (for the value of RTO after the doubling operation)."
*$PAGE*
* (2) (A) (1) RFC #1122, Section 4.2.3.1 reiterates that an "implementation MUST also
* include 'exponential backoff' for successive RTO values for the same
* segment".
*
* (a) RFC #2988, Section 5.5 states that "when the retransmission timer
* expires ... the host MUST set RTO <- RTO * 2 ('back off the timer')".
*
* Thus, the TCP retransmission timer exponential back-off scalar
* value is 2.
*
* (b) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2,
* Page 299 reiterates that "this doubling is called an 'exponential
* backoff'".
*
* See also 'NetTCP_TxConnRTT_RTO_Calc() Note #2b2'.
*
* (2) RFC #2988, Section 5 adds "that a TCP implementation MAY clear SRTT [TCP
* smoothed round-trip time] and RTTVAR [TCP round-trip time variance] after
* backing off the timer multiple times as it is likely that the current SRTT
* and RTTVAR are bogus in this situation. Once SRTT and RTTVAR are cleared
* they should be initialized with the next RTT sample taken".
*
* See also 'NetTCP_TxConnRTT_RTO_Calc() Note #2a4A'.
*
* (B) (1) (a) RFC #2581, Section 3.2 states that "after receiving 3 duplicate ACKs
* ... the fast retransmit algorithm ... performs a retransmission of
* what appears to be the missing segment, without waiting for the
* retransmission timer to expire".
*
* (b) RFC #1122, Section 4.2.2.21 reiterates that with "'fast retransmit' ...
* the [lost] segment ... is retransmitted, without awaiting a timeout".
*
* (2) If a segment is re-transmitted due to the TCP fast re-transmit algorithm
* & NOT due to the TCP connection's re-transmit queue timer expiring, the
* TCP connection's re-transmit queue timer is :
*
* (a) NOT backed-off because the re-transmit queue See Note #2b1B
* timer did NOT expire
* (b) Restarted with its current RTO value See Note #2b1A1
*
* (3) RFC #1122, Section 4.2.3.5 states that "excessive retransmission of the same segment
* by TCP indicates some failure of the remote host or the Internet path ... The following
* procedure MUST be used to handle excessive retransmissions of data segments" :
*
* (c) "When the number of transmissions of the same segment reaches a threshold ...
* close the connection."
*
* See also 'NetTCP_RxPktConnHandlerReTxQ() Note #7'.
*
* (4) RFC #2988, Section 3 states that "TCP MUST use Karn's algorithm ... for taking RTT samples.
* That is, RTT samples MUST NOT be made using segments that were retransmitted (and thus for
* which it is ambiguous whether the reply was for the first instance of the packet or a later
* instance)".
*
* (a) To ensure implementation of Karn's algorithm, while ANY re-transmitted segment(s)
* remain unacknowledged in a TCP connection's re-transmit queue :
*
* (1) (A) NO RTT calculations are performed; ... See Note #4
*
* (B) The TCP connection's re-transmit timeout :
* (1) MAY be backed-off ... See Note #2b1B5
* OR
* (2) MAY be latched at a previously backed-off value; See Note #2b1B6
* BUT
* (3) MUST NOT be updated by RTT calculations. See Note #4a1A
*
* (2) Each time a TCP connection re-transmits a segment, the TCP connection advances
* its un-re-transmitted sequence number to the TCP connection's next sequence
* number to transmit. This ensures that NO RTT or RTO calculations are performed
* until ALL re-transmitted data is acknowledged & remove from the TCP connection's
* re-transmit queue.
*
* (5) RFC #2581, Section 3.1 states that "when a TCP sender detects segment loss using the
* retransmission timer, the value of ssthresh [TCP transmit congestion control slow start
* threshold] ... [and] cwnd [TCP transmit congestion control window] MUST be set".
*
* See also 'NetTCP_TxConnWinSizeHandlerCongCtrl() Notes #2c2A5a & #2c2A5b'.
*
* (6) A TCP connection's delayed acknowledgement controls :
*
* (a) SHOULD be reset whenever a TCP connection re-transmits data segment(s) since
* any re-transmit always transmits an accompanying acknowledgement;
* (b) MAY be reset whenever a TCP connection re-transmits a connection request
* segment since NO delayed acknowledgement controls should be active.
*
* See also 'NetTCP_TxConnAckDlyReset() Note #1'.
*$PAGE*
* (7) RFC #1122, Section 4.2.2.15 states that "if a retransmitted packet is identical to the
* original packet (which implies not only that the data boundaries have not changed, but
* also that the window and acknowledgment fields of the header have not changed), then
* the same IP Identification field MAY be used".
*
* In other words, if the following TCP segment header values are unchanged since the
* last transmission of the TCP segment, then the TCP segment may be transmitted without
* re-calculation of the TCP header :
*
* (a) Sequence Number
* (b) Acknowledgement Number
* (c) Segment Length
* (d) Window Size
*
* (8) (a) Some network interfaces require a minimum packet size & may also require that
* packets smaller than the minimum packet size be appended with trailing pad
* octets. Therefore, all network transmit packets MUST be prepared to satisfy
* a possible network interface minimum packet size requirement.
*
* (b) To ensure that TCP re-transmit segments will be properly prepared to satisfy
* a network interface minimum packet size requirement, the following equations
* are used to validate a TCP re-transmit segment size :
*
* (A) (1) TCP Re-transmit Segment Size = Segment's Re-transmit Protocol Header Sizes +
* Segment's Remaining Segment Data Size
*
* (2) = Segment's Previous Protocol Header Sizes +
* Segment's Remaining Segment Data Size
*
* (3) = (Segment's Previous Total Packet Size -
* Segment's Previous Data Size) +
* Segment's Remaining Segment Data Size
*
* (B) (1) TCP Re-transmit Minimum Segment Size = Network Interface Minimum Packet Size
*
* (2) [(Segment's Total Packet Size -
* Segment's Data Size) +
* Segment's Minimum Segment Data Size ] = Network Interface Minimum Packet Size
*
* (3) Segment's Minimum Segment Data Size = Network Interface Minimum Packet Size -
* (Segment's Total Packet Size -
* Segment's Data Size)
*
* (1) Equation #8bA2 subtly assumes that the TCP re-transmit segment's network
* protocol header sizes equal the segment's previously transmitted network
* protocol header sizes. In other words, it is assumed that a TCP transmit
* segment's network protocol header sizes will remain constant for the
* segment's initial transmission & any subsequent retransmissions.
*
* This assumption is true if & only if the TCP segment is re-transmitted
* with no changes in any of the segment's network protocol header sizes,
* which typically vary only for changes in the network protocol header
* types or in the number of network protocol header options.
*
* #### However, since TCP segments that have already been transmitted can
* NOT modify their segment data (see 'NetTCP_TxConnAppData() Note #10a'),
* it seems reasonable that TCP segments that have already been transmitted
* will NOT likely modify their network protocol header types & SHOULD NOT
* modify their network protocol header options.
*
* #### Therefore, it seems reasonable that TCP segments that have already
* been transmitted will NOT likely vary their network protocol header sizes.
* Thus, TCP segments may validate their re-transmit segment size versus any
* possible network interface minimum packet size requirement based on their
* previously transmitted network protocol header & packet sizes.
*
* (2) (A) Equation #8bB calculates a TCP re-transmit segment's minimum data size
* as required by a possible network interface minimum packet size. If
* the TCP re-transmit segment's data size is smaller than the network
* interface minimum packet size, the network buffer MUST be checked for
* sufficient & available trailing octets, as required by the network
* interface layer to append pad octets.
*
* (B) (1) (a) (1) If the TCP re-transmit segment's minimum data size is smaller
* than the required network interface minimum packet size ...
* AND
* (2) there is insufficient network buffer octets available for
* the network interface layer to append pad octets, ...
*
* (b) then the TCP segment's remaining data octets MUST be moved to
* the network buffer's transmit index to provide sufficient
* network buffer data octets for the network interface layer to
* append pad octets.
*
* (2) A network interface that appends cleared trailing pad octets MAY be
* optimized to skip clearing the trailing pad octets if the network
* buffer's memory clear flag is set. Since a partially-acknowledged
* TCP segment's network buffer contains previously acknowledged data
* octets, the network buffer's memory clear flag MUST be cleared to
* ensure that the network interface layer clears the trailing pad
* octets.
*$PAGE*
* (9) If a packet buffer's unlink function is available, it is assumed that the function ...
*
* (a) Correctly unlinks the packet buffer from any other network protocol layers
* AND
* (b) Correctly updates the network buffer's reference counter to decrement the
* number of network protocol layers that no longer maintain a reference to
* the packet buffer.
* AND
* (c) Clears both the unlink function & object pointers.
*
* (10) Increment network buffer's reference counter to include the TCP segment STILL enqueued
* to the TCP connection's re-transmit queue as a reference to the network buffer.
*
* (11) (a) Since segments enqueued to a TCP connection's transmit queue have already been
* reported as transmitted to the application & since no mechanism exists for a TCP
* connection to re-request previously transmitted data, any TCP connection whose
* transmit queue(s) becomes corrupted MUST be closed to force the application layer
* to abort &/or recover from the corrupted data.
*
* (b) For any internal errors where the TCP connection's transmit queue is NOT corrupted,
* the TCP connection is NOT closed.
*
* See also 'NetTCP_TxConnAppData() Note #10'
* & 'NetTCP_TxConnTxQ() Note #12'.
*********************************************************************************************************
*/
static void NetTCP_TxConnReTxQ (NET_TCP_CONN *pconn,
CPU_BOOLEAN re_tx_q_timeout,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_STAT_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_BUF *pseg;
NET_BUF_HDR *pseg_hdr;
NET_IP_TOS TOS;
NET_IP_TTL TTL;
NET_IP_ADDR src_addr;
NET_IP_ADDR dest_addr;
NET_TCP_PORT_NBR src_port;
NET_TCP_PORT_NBR dest_port;
NET_TCP_SEQ_NBR seq_nbr;
NET_TCP_SEQ_NBR ack_nbr;
NET_TCP_SEG_SIZE seg_len;
NET_TCP_WIN_SIZE win_size;
NET_BUF_SIZE seg_len_tot;
NET_BUF_SIZE seg_len_hdr;
NET_BUF_SIZE seg_len_data_min;
NET_BUF_SIZE buf_size_max;
NET_BUF_SIZE data_ix_cur;
NET_BUF_SIZE data_ix_re_tx;
NET_BUF_SIZE data_len_cur;
CPU_INT16U flags_tcp;
CPU_INT16U flags_ip;
CPU_INT08U *pdata_re_tx;
CPU_FNCT_PTR unlink_fnct;
CPU_BOOLEAN seg_chngd;
CPU_BOOLEAN seg_updated;
CPU_BOOLEAN seg_data_moved;
NET_ERR err;
/*$PAGE*/
/* ----------------- VALIDATE RE-TX Q ----------------- */
if (pconn->ReTxQ_Head == (NET_BUF *)0) {
*perr = NET_TCP_ERR_NONE;
return;
}
pseg = pconn->ReTxQ_Head; /* Re-tx seg @ head of re-tx Q (see Note #2a). */
pseg_hdr = &pseg->Hdr;
pseg_hdr->TCP_SegReTxCtr++;
if (pseg_hdr->TCP_SegReTxCtr >= pconn->TxSegReTxTh) { /* If nbr re-tx's >= th, close TCP conn (see Note #3). */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
*perr = NET_TCP_ERR_RE_TX_SEG_TH;
return;
}
/* ----------------- UPDATE TCP CONN ------------------ */
if (re_tx_q_timeout != DEF_NO) { /* If re-tx Q timeout, ... */
/* ... back-off re-tx Q timeout (see Note #2b1B5) ... */
NetTCP_TxConnRTT_RTO_Calc(pconn, NET_TCP_CONN_TX_RTT_BACKOFF, NET_TCP_TX_RTT_NONE, NET_TCP_TX_RTT_NONE);
#if 0 /* Implemented with backoff (see Note #2b2A2). */
/* ... & reset RTT ctrls (see Note #2b2A2). */
NetTCP_TxConnRTT_RTO_Calc(pconn, NET_TCP_CONN_TX_RTT_RESET, NET_TCP_TX_RTT_NONE, NET_TCP_TX_RTT_NONE);
#endif
}
/* Update re-tx Q tmr (see Note #2b1A1). */
NetTCP_TxConnReTxQ_TimeoutSet(pconn, re_tx_q_timeout, close_code, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* Adv un-re-tx'd seq(s) to ... */
pconn->TxSeqNbrUnReTxd = pconn->TxSeqNbrNext; /* ... not-yet-tx'd seq(s) [see Note #4a2]. */
if (re_tx_q_timeout != DEF_NO) { /* If re-tx Q timeout, ... */
/* ... update tx cong win (see Note #5). */
NetTCP_TxConnWinSizeHandlerCongCtrl((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(NET_TCP_ACK_CODE)NET_TCP_CONN_RX_ACK_NONE,
(NET_TCP_WIN_SIZE)0,
(NET_TCP_WIN_CODE)NET_TCP_CONN_TX_WIN_TIMEOUT,
(NET_ERR *)perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
NetTCP_TxConnAckDlyReset(pconn, DEF_YES); /* Reset ack dly ctrls (see Note #6). */
/*$PAGE*/
/* -------------- PREPARE TCP RE-TX SEG --------------- */
/* Prepare TCP seq nbrs. */
seq_nbr = (NET_TCP_SEQ_NBR )pseg_hdr->TCP_SeqNbr;
ack_nbr = (NET_TCP_SEQ_NBR )pconn->RxSeqNbrNext;
seg_len = (NET_TCP_SEG_SIZE)pseg_hdr->TCP_SegLen;
/* Prepare TCP win size. */
win_size = (NET_TCP_WIN_SIZE)pconn->RxWinSizeActual;
/* Chk for re-tx seg update (see Note #7). */
seg_updated = ((pseg_hdr->TCP_SeqNbrLast != seq_nbr ) ||
(pseg_hdr->TCP_AckNbrLast != ack_nbr ) ||
(pseg_hdr->TCP_SegLenLast != seg_len ) ||
(pseg_hdr->TCP_WinSizeLast != win_size)) ? DEF_YES : DEF_NO;
seg_data_moved = DEF_NO;
seg_len_tot = (NET_BUF_SIZE)(pseg_hdr->TotLen - /* Seg cur tot len = prev'ly tx'd/ack'd pkt tot len - */
pseg_hdr->DataLen + /* ... prev'ly tx'd/ack'd pkt data len + */
pseg_hdr->TCP_SegLenData); /* ... rem'ing seg data len */
/* ... (see Note #8bA). */
if (seg_len_tot < NET_IF_PKT_SIZE_MIN) { /* If TCP re-tx seg tot len ... */
/* ... < min IF pkt size (see Note #8b2B1a2), ... */
/* ... calc min IF seg data len (see Note #8bB); ... */
seg_len_hdr = pseg_hdr->TotLen - pseg_hdr->DataLen;
seg_len_data_min = NET_IF_FRAME_MIN_SIZE - seg_len_hdr;
buf_size_max = NetBuf_GetMaxSize((NET_BUF *)pseg,
(NET_BUF_SIZE)pseg_hdr->DataIx);
if (seg_len_data_min > buf_size_max) { /* ... & if min IF seg data len ... */
/* ... > max buf size (see Note #8b2B1a2), ... */
data_ix_cur = (NET_BUF_SIZE) pseg_hdr->DataIx;
data_ix_re_tx = (NET_BUF_SIZE) NET_BUF_DATA_TX_IX;
data_len_cur = (NET_BUF_SIZE) pseg_hdr->TCP_SegLenData;
pdata_re_tx = (CPU_INT08U *)&pseg->Data[data_ix_re_tx];
NetBuf_DataRd((NET_BUF *) pseg, /* ... rd rem'ing TCP seg data ... */
(NET_BUF_SIZE) data_ix_cur,
(NET_BUF_SIZE) data_len_cur,
(CPU_INT08U *) pdata_re_tx, /* ... & move to base re-tx ix (see Note #8b2B1b). */
(NET_ERR *)&err);
if (err != NET_BUF_ERR_NONE) { /* See Note #11a. */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
*perr = NET_TCP_ERR_CONN_FAULT;
return;
}
DEF_BIT_CLR(pseg_hdr->Flags, NET_BUF_FLAG_CLR_MEM); /* MUST clr buf mem clr flag (see Note #8b2B2). */
seg_data_moved = DEF_YES;
}
}
seg_chngd = ((seg_updated != DEF_NO) ||
(seg_data_moved != DEF_NO)) ? DEF_YES : DEF_NO;
/*$PAGE*/
if (seg_chngd != DEF_NO) { /* If chng'd, prepare seg for re-tx (see Note #1b2). */
/* Prepare TCP seg addrs. */
src_port = (NET_TCP_PORT_NBR)pseg_hdr->TCP_UDP_PortSrc;
src_addr = (NET_IP_ADDR )pseg_hdr->IP_AddrSrc;
dest_port = (NET_TCP_PORT_NBR)pseg_hdr->TCP_UDP_PortDest;
dest_addr = (NET_IP_ADDR )pseg_hdr->IP_AddrDest;
/* Prepare TCP tx flags. */
flags_tcp = pseg_hdr->TCP_Flags;
/* Prepare IP params. */
TOS = pconn->TxIP_TOS;
TTL = pconn->TxIP_TTL;
flags_ip = pconn->TxIP_Flags;
/* Update re-tx seg's last tx ctrls (see Note #1b2F). */
pseg_hdr->TCP_SeqNbrLast = (CPU_INT32U)seq_nbr;
pseg_hdr->TCP_AckNbrLast = (CPU_INT32U)ack_nbr;
pseg_hdr->TCP_SegLenLast = (CPU_INT16U)seg_len;
pseg_hdr->TCP_WinSizeLast = (CPU_INT16U)win_size;
/* Reset protocol & tot len for re-tx. */
pseg_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
pseg_hdr->TotLen = pseg_hdr->DataLen;
}
unlink_fnct = pseg_hdr->UnlinkFnctPtr;
if (unlink_fnct != (CPU_FNCT_PTR)0) { /* If unlink fnct avail, .. */
unlink_fnct((void *)pseg); /* .. unlink seg from other layer(s) [see Note #9]. */
}
if (pseg_hdr->RefCtr <= 1) {
pseg_hdr->RefCtr++; /* TCP STILL maintains ref to seg (see Note #10). */
}
/* ---------------- RE-TX TCP CONN SEG ---------------- */
if (seg_updated == DEF_NO) { /* If seg NOT updated, */
NetIP_ReTx((NET_BUF *)pseg, /* ... re-tx unchng'd seg (see Note #7). */
(NET_ERR *)perr);
if (*perr != NET_IP_ERR_NONE) {
return;
}
} else { /* Else re-tx updated seg. */
NetTCP_TxPktHandler((NET_BUF *)pseg,
(NET_IP_ADDR )src_addr,
(NET_TCP_PORT_NBR)src_port,
(NET_IP_ADDR )dest_addr,
(NET_TCP_PORT_NBR)dest_port,
(NET_TCP_SEQ_NBR )seq_nbr,
(NET_TCP_SEQ_NBR )ack_nbr,
(NET_TCP_WIN_SIZE)win_size,
(NET_IP_TOS )TOS,
(NET_IP_TTL )TTL,
(CPU_INT16U )flags_tcp,
(CPU_INT16U )flags_ip,
(void *)0,
(void *)0,
(NET_ERR *)perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
case NET_ERR_INIT_INCOMPLETE:
case NET_ERR_TX: /* Ignore transitory tx err(s). */
break;
case NET_TCP_ERR_TX: /* See Note #11a. */
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
NET_CTR_STAT_INC(NetTCP_StatTxSegConnReTxQ_Ctr);
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnReTxQ_Timeout()
*
* Description : (1) (a) Handle TCP connection re-transmit queue timeout ... :
*
* (1) Clear TCP connection's re-transmit timer See Note #4aA1
* (2) Handle TCP connection re-transmit See Note #2
*
* (b) ... for the following synchronization/connected states :
*
* (1) SYN-RECEIVED
* (2) SYN-SENT
* (3) ESTABLISHED
* (4) FIN-WAIT-1
* (5) CLOSING
* (6) CLOSE-WAIT
* (7) LAST-ACK
*
*
* Argument(s) : pconn_timeout Pointer to TCP connection to perform re-transmit (see Note #3b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_TxConnReTxQ_TimeoutSet().
*
* Note(s) : (2) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : RETRANSMISSION TIMEOUT'
* states that "if the retransmission timeout expires ... send the segment at the
* front of the retransmission queue ... [and] reinitialize the retransmission timer".
*
* See also 'NetTCP_TxConnReTxQ() Note #2'.
*
* (3) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (4) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) ... :
*
* (A) TCP connection re-transmit queue timer ('ReTxQ_Tmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared prior to next handler function(s) as an extra precaution to
* avoiding re-freeing the timer (see Note #4a2B).
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_RE_TX
*
* (5) Certain network connections MUST periodically suspend network transmit(s) to handle
* network receive packet(s). To protect TCP connections from transmit corruption while
* suspended, ALL TCP data transmits & TCP transmit queue handling MUST be blocked for
* suspended connections until the connection is no longer suspended.
*
* However, handling the TCP connection's re-transmit timeout is permitted since NO TCP
* data is transmitted & the TCP connection's transmit queue is NOT handled (see Note #1a).
*
* See also 'NetTCP_TxConnTxQ() Note #10b2A2',
* 'NetTCP_TxConnTxQ_TimeoutIdle() Note #5',
* 'NetTCP_TxConnTxQ_TimeoutSillyWin() Note #5',
* & 'NetTCP_TxConnWinSizeZeroWinTimeout() Note #5'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnReTxQ_Timeout (void *pconn_timeout)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CLOSE_CODE close_code;
NET_ERR err;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #3b2A. */
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_RE_TX); /* See Note #4b1. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE TCP CONN ----------------- */
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED:
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_SYNC_RXD: /* See Note #1. */
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
switch (pconn->TxQ_State) {
case NET_TCP_TX_Q_STATE_CONN:
case NET_TCP_TX_Q_STATE_CONN_CLOSING:
case NET_TCP_TX_Q_STATE_CONN_SUSPEND: /* See Note #5. */
break;
case NET_TCP_TX_Q_STATE_NONE:
case NET_TCP_TX_Q_STATE_CLOSED:
case NET_TCP_TX_Q_STATE_CONN_CLOSED:
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* --------- HANDLE TCP CONN RE-TX Q TIMEOUT ---------- */
pconn->ReTxQ_Tmr = (NET_TMR *)0; /* Clr re-tx Q tmr (see Note #4a2A1). */
NetTCP_TxConnReTxQ(pconn, DEF_YES, close_code, &err); /* Handle re-tx Q (see Note #2). */
(void)err; /* Ignore ALL re-tx err(s), transitory or fatal. */
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnReTxQ_TimeoutSet()
*
* Description : (1) (a) Set TCP connection's re-transmit queue timer for the following synchronization/
* connected states :
*
* (1) CLOSED
* (2) LISTEN
* (3) SYN-RECEIVED
* (4) SYN-SENT
* (5) ESTABLISHED
* (6) FIN-WAIT-1
* (7) CLOSING
* (8) CLOSE-WAIT
* (9) LAST-ACK
*
* (A) (1) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : RETRANSMISSION
* TIMEOUT' reiterates that "for any state if the retransmission timeout expires
* on a segment in the retransmission queue ... reinitialize the retransmission
* timer".
*
* (b) However, since a TCP connection's transmit & re-transmit queue SHOULD be closed for
* the following states, it does NOT seem reasonable to set or reset a TCP connection's
* re-transmit queue timer for these states :
*
* (1) FIN-WAIT-2
* (2) TIME-WAIT
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnSync(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnReTxQ(),
* NetTCP_RxPktConnHandlerReTxQ().
*
* re_tx_q_timeout Indicate whether the TCP connection re-transmit queue timed out :
*
* DEF_NO TCP connection re-transmit queue did
* NOT time out.
* DEF_YES TCP connection re-transmit queue
* timed out.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection re-transmit queue timer
* successfully set.
* NET_TCP_ERR_CONN_NOT_USED TCP connection NOT currently used.
* NET_TCP_ERR_CONN_FAULT TCP connection fault; connection(s) aborted.
* NET_TCP_ERR_INVALID_CONN_STATE Invalid TCP connection state.
* NET_TCP_ERR_INVALID_CONN_OP Invalid TCP connection operation.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnSync(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnReTxQ(),
* NetTCP_RxPktConnHandlerReTxQ().
*
* Note(s) : none.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnReTxQ_TimeoutSet (NET_TCP_CONN *pconn,
CPU_BOOLEAN re_tx_q_timeout,
NET_TCP_CLOSE_CODE close_code,
NET_ERR *perr)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TMR_TICK timeout_tick;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------- VALIDATE TCP CONN STATE -------------- */
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_FREE:
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
*perr = NET_TCP_ERR_CONN_NOT_USED;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_FIN_WAIT_2: /* See Note #1b. */
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidOpCtr);
*perr = NET_TCP_ERR_INVALID_CONN_OP;
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_STATE_CLOSED: /* See Note #1a. */
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
break;
case NET_TCP_CONN_STATE_NONE:
default:
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)close_code);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidStateCtr);
*perr = NET_TCP_ERR_INVALID_CONN_STATE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/* ------------ SET TCP CONN RE-TX Q TMR ------------- */
timeout_tick = pconn->TxRTT_RTO_tick;
if ((pconn->ReTxQ_Tmr != (NET_TMR *)0) && /* If re-tx Q tmr avail .. */
(re_tx_q_timeout == DEF_NO)) { /* .. but NOT timed out, .. */
NetTmr_Set((NET_TMR *) pconn->ReTxQ_Tmr, /* .. reset re-tx Q tmr. */
(CPU_FNCT_PTR) NetTCP_TxConnReTxQ_Timeout,
(NET_TMR_TICK) timeout_tick,
(NET_ERR *)&err);
} else { /* Else get re-tx Q tmr. */
pconn->ReTxQ_Tmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_TxConnReTxQ_Timeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
}
if ( err != NET_TMR_ERR_NONE) { /* #### On err, handle re-tx Q?; close TCP conn? */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
*perr = NET_TCP_ERR_CONN_FAULT;
return;
}
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnPrepareSegAddrs()
*
* Description : Prepare TCP transmit segment addresses from TCP connection addresses.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnAppData();
* checked in NetTCP_TxConnSync(),
* NetTCP_TxConnClose(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe().
*
* psrc_port Pointer to variable buffer that will receive the return source port number
* --------- (see Note #1), if NO errors.
*
* Argument validated in NetTCP_TxConnAppData(),
* NetTCP_TxConnSync(),
* NetTCP_TxConnClose(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe().
*
* psrc_addr Pointer to variable buffer that will receive the return source address
* --------- (see Note #1), if NO errors.
*
* Argument validated in NetTCP_TxConnAppData(),
* NetTCP_TxConnSync(),
* NetTCP_TxConnClose(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe().
*
* src_port_len Size of the variable buffer that will receive the return source port number.
*
* src_addr_len Size of the variable buffer that will receive the return source address.
*
* pdest_port Pointer to variable buffer that will receive the return destination port number
* ---------- (see Note #1), if NO errors.
*
* Argument validated in NetTCP_TxConnAppData(),
* NetTCP_TxConnSync(),
* NetTCP_TxConnClose(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe().
*
* pdest_addr Pointer to variable buffer that will receive the return destination address
* ---------- (see Note #1), if NO errors.
*
* Argument validated in NetTCP_TxConnAppData(),
* NetTCP_TxConnSync(),
* NetTCP_TxConnClose(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe().
*
* dest_port_len Size of the variable buffer that will receive the return destination port number.
*
* dest_addr_len Size of the variable buffer that will receive the return destination address.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP connection addresses successfully
* prepared.
*
* NET_CONN_ERR_INVALID_FAMILY Invalid connection family.
* NET_CONN_ERR_INVALID_ADDR Invalid TCP connection address.
* NET_CONN_ERR_INVALID_ADDR_LEN Invalid TCP connection address length.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnAppData(),
* NetTCP_TxConnSync(),
* NetTCP_TxConnClose(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe().
*
* Note(s) : (1) Variable buffers to receive the returned port & address values may start on any CPU address,
* word-aligned or not.
*
* See also 'net_util.h NETWORK DATA VALUE MACRO'S Note #2b'.
*
* (2) The 'NET_CONN_CFG_FAMILY' pre-processor 'else'-conditional code will never be compiled/linked
* since 'net_conn.h' ensures that the family type configuration constant (NET_CONN_CFG_FAMILY)
* is configured with an appropriate family type value (see 'net_conn.h CONFIGURATION ERRORS').
* The 'else'-conditional code is included for completeness & as an extra precaution in case
* 'net_conn.h' is incorrectly modified.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxConnPrepareSegAddrs (NET_TCP_CONN *pconn,
CPU_INT08U *psrc_port,
CPU_INT08U *psrc_addr,
CPU_INT16U src_port_len,
CPU_INT16U src_addr_len,
CPU_INT08U *pdest_port,
CPU_INT08U *pdest_addr,
CPU_INT16U dest_port_len,
CPU_INT16U dest_addr_len,
NET_ERR *perr)
{
NET_CONN_ID conn_id;
NET_CONN_ADDR_LEN addr_len;
CPU_INT08U addr[NET_CONN_CFG_ADDR_LEN];
CPU_INT08U port[NET_CONN_CFG_ADDR_LEN];
CPU_INT08U addr_local[NET_CONN_CFG_ADDR_LEN];
CPU_INT08U addr_remote[NET_CONN_CFG_ADDR_LEN];
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* ---------------- VALIDATE ADDR LENS ---------------- */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
if (src_port_len != NET_CONN_ADDR_IP_LEN_PORT) {
*perr = NET_CONN_ERR_INVALID_ADDR_LEN;
return;
}
if (src_addr_len != NET_CONN_ADDR_IP_LEN_ADDR) {
*perr = NET_CONN_ERR_INVALID_ADDR_LEN;
return;
}
if (dest_port_len != NET_CONN_ADDR_IP_LEN_PORT) {
*perr = NET_CONN_ERR_INVALID_ADDR_LEN;
return;
}
if (dest_addr_len != NET_CONN_ADDR_IP_LEN_ADDR) {
*perr = NET_CONN_ERR_INVALID_ADDR_LEN;
return;
}
#else /* See Note #2. */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
#else /* Prevent compiler warnings. */
(void)&src_port_len;
(void)&src_addr_len;
(void)&dest_port_len;
(void)&dest_addr_len;
#endif
/*$PAGE*/
/* ------------------ PREPARE ADDRS ------------------- */
conn_id = pconn->ID_Conn;
addr_len = sizeof(addr_local);
NetConn_AddrLocalGet((NET_CONN_ID ) conn_id, /* Get local/src addr. */
(CPU_INT08U *)&addr_local[0],
(NET_CONN_ADDR_LEN *)&addr_len,
(NET_ERR *)&err);
if (err != NET_CONN_ERR_NONE) {
*perr = NET_CONN_ERR_INVALID_ADDR;
return;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (addr_len != NET_CONN_CFG_ADDR_LEN) {
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_CONN_ERR_INVALID_ADDR_LEN;
return;
}
#endif
addr_len = sizeof(addr_remote);
NetConn_AddrRemoteGet((NET_CONN_ID ) conn_id, /* Get remote/dest addr. */
(CPU_INT08U *)&addr_remote[0],
(NET_CONN_ADDR_LEN *)&addr_len,
(NET_ERR *)&err);
if (err != NET_CONN_ERR_NONE) {
*perr = NET_CONN_ERR_INVALID_ADDR;
return;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (addr_len != NET_CONN_CFG_ADDR_LEN) {
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_CONN_ERR_INVALID_ADDR_LEN;
return;
}
#endif
/* Prepare src/dest addrs (see Note #1). */
#if (NET_CONN_CFG_FAMILY == NET_CONN_FAMILY_IP_V4_SOCK)
Mem_Copy((void *)&port[0],
(void *)&addr_local[NET_CONN_ADDR_IP_IX_PORT],
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_PORT);
Mem_Copy((void *)&addr[0],
(void *)&addr_local[NET_CONN_ADDR_IP_IX_ADDR],
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
NET_UTIL_VAL_COPY_GET_NET_16(psrc_port, &port[0]);
NET_UTIL_VAL_COPY_GET_NET_32(psrc_addr, &addr[0]);
Mem_Copy((void *)&port[0],
(void *)&addr_remote[NET_CONN_ADDR_IP_IX_PORT],
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_PORT);
Mem_Copy((void *)&addr[0],
(void *)&addr_remote[NET_CONN_ADDR_IP_IX_ADDR],
(CPU_SIZE_T) NET_CONN_ADDR_IP_LEN_ADDR);
NET_UTIL_VAL_COPY_GET_NET_16(pdest_port, &port[0]);
NET_UTIL_VAL_COPY_GET_NET_32(pdest_addr, &addr[0]);
#else /* See Note #2. */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )DEF_YES,
(NET_TCP_CLOSE_CODE)NET_TCP_CONN_CLOSE_ALL);
*perr = NET_CONN_ERR_INVALID_FAMILY;
return;
#endif
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTT_Init()
*
* Description : Initialize TCP connection's transmit round-trip time (RTT) controls.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTT_Reset(),
* NetTCP_TxConnRTT_RTO_Init().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnRTT_Reset(),
* NetTCP_TxConnRTT_RTO_Init().
*
* Note(s) : (1) (A) RFC #1122, Section 4.2.3.1 states that "the following values SHOULD be
* used to initialize the estimation parameters for a new connection" :
*
* (a) RTT = 0 seconds
*
* where
* RTT Round-Trip Time
*
* (1) Furthermore, RFC #1122, Section 4.2.3.1.(b) states that "the
* smoothed variance is to be initialized to the value that will
* result in" these values.
*
* (B) However, since RFC #2988, Section 2.2 amends the RFC #1122, Section
* 4.2.3.1 RTT initialization; the smoothed RTT average & deviation do
* NOT truly require explicit initialization. Nonetheless, these RTT
* values are initialized to conform with RFC #1122, Section 4.2.3.1.
*********************************************************************************************************
*/
static void NetTCP_TxConnRTT_Init (NET_TCP_CONN *pconn)
{
/* Init RTT (see Note #1). */
pconn->TxRTT_Avg_ms_scaled = NET_TCP_TX_RTT_AVG_INIT_MS_SCALED; /* Init RTT avg (see Note #1Aa). */
pconn->TxRTT_Dev_ms_scaled = NET_TCP_TX_RTT_DEV_INIT_MS_SCALED; /* Init RTT dev (see Note #1A1). */
NetTCP_TxConnRTT_CalcUpdate(pconn);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTT_Reset()
*
* Description : Reset TCP connection's transmit round-trip time (RTT) controls.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTT_RTO_Calc().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnRTT_RTO_Calc().
*
* Note(s) : (1) (a) RFC #2988, Section 5 states "that a TCP implementation MAY clear SRTT and
* RTTVAR after backing off the timer multiple times as it is likely that the
* current SRTT and RTTVAR are bogus in this situation. Once SRTT and RTTVAR
* are cleared they should be initialized with the next RTT sample taken".
*
* (b) RFC #2581, Section 4.1 states that "after TCP has been idle for ... an
* interval exceeding the retransmission timeout ... use slow start to
* restart transmission".
*
* Similarly, although NO RFC specifies that a TCP connection's RTT average &
* deviation should be reset following a TCP transmit idle timeout; it seems
* reasonable to reset a TCP connection's RTT average & deviation controls
* whenever a TCP connection's transmit is idle for a period exceeding the
* re-transmit timeout.
*
* See also 'NetTCP_TxConnRTT_RTO_Calc() Note #2a4'.
*********************************************************************************************************
*/
static void NetTCP_TxConnRTT_Reset (NET_TCP_CONN *pconn)
{
NetTCP_TxConnRTT_Init(pconn);
pconn->TxRTT_RTO_State = NET_TCP_TX_RTT_RTO_STATE_RESET;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTT_CalcUpdate()
*
* Description : Update TCP connection's transmit round-trip time (RTT) control calculations.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTT_Init(),
* NetTCP_TxConnRTT_RTO_Calc().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnRTT_Init(),
* NetTCP_TxConnRTT_RTO_Calc().
*
* Note(s) : (1) A TCP connection's transmit round-trip time controls should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's transmit round-trip time average (in scaled milliseconds)
* ['TxRTT_Avg_ms_scaled']
*
* (b) TCP connection's transmit round-trip time deviation (in scaled milliseconds)
* ['TxRTT_Dev_ms_scaled']
*********************************************************************************************************
*/
static void NetTCP_TxConnRTT_CalcUpdate (NET_TCP_CONN *pconn)
{
pconn->TxRTT_Avg_ms = (NET_TCP_TIMEOUT_MS)(pconn->TxRTT_Avg_ms_scaled / NET_TCP_TX_RTT_SCALE);
pconn->TxRTT_Dev_ms = (NET_TCP_TIMEOUT_MS)(pconn->TxRTT_Dev_ms_scaled / NET_TCP_TX_RTT_SCALE);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTO_Init()
*
* Description : (1) Initialize TCP connection's re-transmit timeout (RTO) controls :
*
* (a) Initialize RTO See Note #2
* (b) Configure RTO maximum timeout See Note #3
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTT_RTO_Init().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnRTT_RTO_Init().
*
* Note(s) : (2) RFC #1122, Section 4.2.3.1 states that "the following values SHOULD be
* used to initialize the estimation parameters for a new connection" :
*
* (b) RTO = 3 seconds
*
* where
* RTO Retransmission Timeout
*
* (A) RFC #2988, Section 2.1 reiterates that "until a round-trip time (RTT)
* measurement has been made ... the sender SHOULD set RTO <- 3 seconds".
*
* (3) A TCP connection's re-transmit timeout controls should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's maximum re-transmit timeout (in seconds) ['TxRTT_RTO_Max_sec']
* [see 'NetTCP_TxConnRTO_CfgMaxTimeout() Note #2a']
*********************************************************************************************************
*/
static void NetTCP_TxConnRTO_Init (NET_TCP_CONN *pconn)
{
pconn->TxRTT_RTO_ms_scaled = NET_TCP_TX_RTT_RTO_INIT_MS_SCALED; /* Init RTO (see Note #2). */
NetTCP_TxConnRTO_CalcUpdate(pconn);
NetTCP_TxConnRTO_CfgMaxTimeout(pconn); /* Cfg RTO max timeout (see Note #3). */
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTO_CfgMaxTimeout()
*
* Description : Configure TCP connection's maximum re-transmit timeout (RTO).
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTO_Init(),
* NetTCP_ConnCfgReTxMaxTimeout().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnRTO_Init(),
* NetTCP_ConnCfgReTxMaxTimeout().
*
* Note(s) : (1) (a) RFC #2988, Section 2.4 states that "a maximum value MAY be placed on RTO provided
* it is at least 60 seconds".
*
* (b) RFC #1122, Section 4.2.3.1 states that "the recommended ... RTO ... upper bound
* should be 2*MSL".
*
* (c) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2, Page 299 states
* that "the timeout value ... [has] an upper limit of 64 seconds".
*
* (2) A TCP connection's maximum re-transmit timeouts (in scaled milliseconds or milliseconds)
* should NOT be updated until after the following TCP connection control(s) have been
* configured :
*
* (a) TCP connection's maximum re-transmit timeout (in seconds) ['TxRTT_RTO_Max_sec']
* [see 'NetTCP_ConnClr() Note #11'
* & 'NetTCP_ConnCfgReTxMaxTimeout() Note #1']
*********************************************************************************************************
*/
static void NetTCP_TxConnRTO_CfgMaxTimeout (NET_TCP_CONN *pconn)
{
pconn->TxRTT_RTO_Max_ms_scaled = (NET_TCP_TX_RTT_MS_SCALED)pconn->TxRTT_RTO_Max_sec * NET_TCP_TX_RTT_MS_SCALE;
pconn->TxRTT_RTO_Max_ms = (NET_TCP_TIMEOUT_MS )pconn->TxRTT_RTO_Max_sec * DEF_TIME_NBR_mS_PER_SEC;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTO_CalcUpdate()
*
* Description : Update TCP connection's re-transmit timeout (RTO) control calculations.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTO_Init(),
* NetTCP_TxConnRTT_RTO_Calc().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnRTO_Init(),
* NetTCP_TxConnRTT_RTO_Calc().
*
* Note(s) : (1) A TCP connection's re-transmit timeout controls should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's re-transmit timeout (in scaled milliseconds)
* ['TxRTT_RTO_ms_scaled']
*********************************************************************************************************
*/
static void NetTCP_TxConnRTO_CalcUpdate (NET_TCP_CONN *pconn)
{
pconn->TxRTT_RTO_ms = (NET_TCP_TIMEOUT_MS )(pconn->TxRTT_RTO_ms_scaled / NET_TCP_TX_RTT_SCALE);
pconn->TxRTT_RTO_sec = (NET_TCP_TIMEOUT_SEC)(pconn->TxRTT_RTO_ms_scaled / NET_TCP_TX_RTT_MS_SCALE);
pconn->TxRTT_RTO_tick = ((NET_TMR_TICK ) pconn->TxRTT_RTO_ms * NET_TMR_TIME_TICK_PER_SEC) / DEF_TIME_NBR_mS_PER_SEC;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTO_CalcBackOff()
*
* Description : Calculate next backed-off re-transmit timeout (RTO) value.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_TxConnRTT_RTO_Calc(),
* NetTCP_TxConnWinSizeZeroWinHandler().
*
* rto_ms Current re-transmit timeout value (in milliseconds).
*
* Return(s) : Backed-off re-transmit timeout value (in milliseconds).
*
* Caller(s) : NetTCP_TxConnRTT_RTO_Calc(),
* NetTCP_TxConnWinSizeZeroWinHandler().
*
* Note(s) : (1) (a) RFC #1122, Section 4.2.3.1 states that an "implementation MUST also include
* 'exponential backoff' for successive RTO values for the same segment".
*
* (1) RFC #2988, Section 5.5 states that "when the retransmission timer expires
* ... the host MUST set RTO <- RTO * 2 ('back off the timer')".
*
* Thus, the TCP retransmission timer exponential back-off scalar value is 2.
*
* (2) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2, Page 299
* reiterates that "this doubling is called an 'exponential backoff'".
*
* (b) (1) RFC #2988, Section 2.4 adds that "a maximum value MAY be placed on RTO
* provided it is at least 60 seconds".
*
* (2) RFC #1122, Section 4.2.3.1 states that "the recommended ... RTO ... upper
* bound should be 2*MSL".
*
* (3) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2, Page 299
* states that "the timeout value is doubled for each retransmission, with an
* upper limit of 64 seconds".
*
* See also 'NetTCP_TxConnRTO_CfgMaxTimeout() Note #1'.
*
* (2) RFC #1122, Section 4.2.2.17 states that "zero-window probe[s] ... SHOULD increase
* exponentially the interval between successive probes ... Exponential backoff is
* recommended ... similar to ... the retransmission algorithm, and it may be possible
* to combine the two procedures in the implementation".
*********************************************************************************************************
*/
static NET_TCP_TIMEOUT_MS NetTCP_TxConnRTO_CalcBackOff (NET_TCP_CONN *pconn,
NET_TCP_TIMEOUT_MS rto_ms)
{
NET_TCP_TIMEOUT_MS rto_ms_backoff_calcd;
NET_TCP_TIMEOUT_MS rto_ms_backoff;
/* Calc backed-off RTO timeout value (see Note #1a). */
rto_ms_backoff_calcd = (rto_ms < pconn->TxRTT_RTO_Max_ms)
? (rto_ms * NET_TCP_TX_RTO_TIMEOUT_BACKOFF_SCALAR)
: pconn->TxRTT_RTO_Max_ms;
/* Limit backed-off RTO timeout value (see Note #1b). */
rto_ms_backoff = DEF_MIN(rto_ms_backoff_calcd, pconn->TxRTT_RTO_Max_ms);
return (rto_ms_backoff);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTT_RTO_Init()
*
* Description : Initialize TCP connection's transmit round-trip time (RTT) & re-transmit timeout (RTO) values.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnCfg().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnCfg().
*
* Note(s) : (1) A TCP connection's re-transmit timeout controls should NOT be updated until
* after the following TCP connection control(s) have been configured :
*
* (a) TCP connection's maximum re-transmit timeout (in seconds) ['TxRTT_RTO_Max_sec']
* [see 'NetTCP_TxConnRTO_Init() Note #3']
*********************************************************************************************************
*/
static void NetTCP_TxConnRTT_RTO_Init (NET_TCP_CONN *pconn)
{
NetTCP_TxConnRTT_Init(pconn);
NetTCP_TxConnRTO_Init(pconn);
pconn->TxRTT_RTO_State = NET_TCP_TX_RTT_RTO_STATE_INIT;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxConnRTT_RTO_Calc()
*
* Description : (1) Calculate TCP connection's transmit round-trip time (RTT) & re-transmit timeout (RTO) values :
*
* (a) Perform requested RTT/RTO calculation operation(s)
* (b) Prepare & perform RTT calculations
* (c) Prepare & perform RTO calculations
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandlerReTxQ(),
* NetTCP_TxConnReTxQ(),
* NetTCP_TxConnTxQ_TimeoutIdle().
*
* calc_code Indicate which TCP connection's transmit round-trip time calculations to perform
* (see Note #1a) :
*
* NET_TCP_CONN_TX_RTT_INIT Initialize TCP connection's transmit
* round-trip time controls
* (see 'NetTCP_TxConnRTT_Init() Note #1'
* & 'NetTCP_TxConnRTO_Init() Note #2').
* NET_TCP_CONN_TX_RTT_RESET Reset TCP connection's transmit
* round-trip time controls.
*
* NET_TCP_CONN_TX_RTT_CALC Calculate & update TCP connection's transmit
* round-trip time controls.
*
* NET_TCP_CONN_TX_RTT_BACKOFF Back-off & update TCP connection's transmit
* round-trip time controls for a TCP re-
* transmit timeout.
*
* rtt_ts_txd_ms Round-trip timestamp when transmitted (in milliseconds).
*
* rtt_ts_rxd_ms Round-trip timestamp when received (in milliseconds).
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerReTxQ(),
* NetTCP_TxConnReTxQ(),
* NetTCP_TxConnTxQ_TimeoutIdle().
*$PAGE*
* Note(s) : (2) (a) (1) RFC #2988, Section 2 states that "the rules governing the computation of SRTT
* (smoothed round-trip time), RTTVAR RTTVAR (round-trip time variation), and RTO
* are as follows" :
*
* (A) RFC #2988, Section 2.2 states that for "the first RTT measurement R ...
* the host MUST set" :
*
* (1) SRTT <- R
* (2) RTTVAR <- R/2
* (3) RTO <- SRTT + max(G, K * RTTVAR)
*
* where
* SRTT RTT Smoothed Average
* RTTVAR RTT Variance/Deviation
* RTO Retransmission Timeout
* R RTT First Measurement
* (4) R = R * 1 RTT First Average Gain
* (5) R/2 = R * 1/2 RTT First Deviation Gain
* G RTT Clock Granularity (resolution)
* (6) K = 4 RTT-RTO Gain
*
*
* (B) RFC #2988, Section 2.3 states that for "subsequent RTT measurement R' ...
* a host MUST set" :
*
* (1) RTTVAR <- (1 - beta ) * RTTVAR + beta * |SRTT - R'|
* (2) SRTT <- (1 - alpha) * SRTT + alpha * R'
* (3) RTO <- SRTT + max(G, K * RTTVAR)
*
* where
* SRTT RTT Smoothed Average
* RTTVAR RTT Variance/Deviation
* RTO Retransmission Timeout
* R' RTT Subsequent Measurement(s)
* (4) alpha = 1/8 RTT-Average Gain
* (5) beta = 1/4 RTT-Deviation Gain
* G RTT Clock Granularity (resolution)
* (6) K = 4 RTT-RTO Gain
*
*
* (a) RFC #2988, Section 2.3 states tht "updating RTTVAR and SRTT MUST be
* computed in ... order ... [since] the value of SRTT used in the update
* to RTTVAR is its value before updating SRTT itself".
*
* (b) To reduce the total number of operations for both RTT calculations,
* the equations SHOULD be factored & rearranged as follows :
*
* (1) (A) RTTVAR <- (1 - beta) * RTTVAR + beta * |SRTT - R'|
*
* (B) RTTVAR <- RTTVAR - beta * RTTVAR + beta * |SRTT - R'|
*
* (C) RTTVAR <- RTTVAR + beta * (|SRTT - R'| - RTTVAR)
*
* (D) RTTVAR <- RTTVAR + beta * (|R' - SRTT| - RTTVAR)
*
*
* (2) (A) SRTT <- (1 - alpha) * SRTT + alpha * R'
*
* (B) SRTT <- SRTT - alpha * SRTT + alpha * R'
*
* (C) SRTT <- SRTT + alpha * (R' - SRTT)
*
*
* (2) (A) RFC #793, Section 3.7 'Data Communication : Retransmission Timeout' states
* that "the Round Trip Time (RTT) ... [is] the elapsed time between" :
*
* (1) "sending a data octet with a particular sequence number and" ...
* (2) "receiving an acknowledgment that covers that sequence number" ...
* (3) "(segments sent do not have to match segments received)".
*
* (B) (1) RFC #2988, Section 3 adds that :
*
* (a) "Traditionally, TCP implementations have taken one RTT measurement at
* a time (typically once per RTT)."
* (b) "A TCP implementation MUST take at least one RTT measurement per RTT
* (unless that is not possible per Karn's algorithm) [see Note #2a5]".
* (c) "For fairly modest congestion window sizes research suggests that
* timing each segment does not lead to a better RTT estimator."
* (d) "Additionally, when multiple samples are taken per RTT the alpha and
* beta ... may keep an inadequate RTT history."
*
* (2) RFC #2988, Section 1 states that "in some situations it may be beneficial
* for a TCP sender to be more conservative than the algorithms detailed in
* this document allow. However, a TCP MUST NOT be more aggressive than the
* ... algorithms allow".
*
* Thus, the following TCP algorithm(s) are permitted; even if the algorithms
* delay or decrease the number of received acknowledgements, which thereby
* increases the measured time values for RTT samples :
*
* (a) Karn's Algorithm See Note #2a5
* (b) TCP Delayed Acknowledgements See 'NetTCP_TxConnAck() Note #6'
*$PAGE*
* (3) Jacobson/Karels, "Congestion Avoidance and Control", Appendix A.2 states that RTT
* calculations "should be done in integer arithmetic". RFC #2988, Section 2.3 adds
* that RTT calculations "SHOULD be computed using ... 1/8 and ... 1/4" gains (see
* Notes #2a1B4 & #2a1B5).
*
* (4) (A) RFC #2988, Section 5 states "that a TCP implementation MAY clear SRTT and
* RTTVAR after backing off the timer multiple times as it is likely that the
* current SRTT and RTTVAR are bogus in this situation. Once SRTT and RTTVAR
* are cleared they should be initialized with the next RTT sample taken per
* [Note #2a1A] rather than using [Note #2a1B]".
*
* (B) RFC #2581, Section 4.1 states that "after TCP has been idle for ... an
* interval exceeding the retransmission timeout ... use slow start to
* restart transmission".
*
* Similarly, although NO RFC specifies that a TCP connection's RTT average &
* deviation should be reset following a TCP transmit idle timeout; it seems
* reasonable to reset a TCP connection's RTT average & deviation controls
* whenever a TCP connection's transmit is idle for a period exceeding the
* re-transmit timeout.
*
* See also 'NetTCP_TxConnTxQ_TimeoutIdle() Note #2a'.
*
* (5) RFC #2988, Section 3 states that "TCP MUST use Karn's algorithm ... for
* taking RTT samples. That is, RTT samples MUST NOT be made using segments
* that were retransmitted (and thus for which it is ambiguous whether the reply
* was for the first instance of the packet or a later instance)".
*
* (b) (1) (A) (1) RFC #2988, Section 2.4 states that "whenever RTO is computed, if it
* is less than 1 second then the RTO SHOULD be rounded up to 1 second".
*
* (a) This amends RFC #1122, Section 4.2.3.1 which previously stated
* that "the recommended ... RTO ... lower bound ... SHOULD be
* measured in fractions of a second".
*
* (2) RFC #2988, Section 4 states that "there is no requirement for the
* clock granularity G used for computing RTT measurements ... However,
* if the K*RTTVAR term in the RTO calculation equals zero, the variance
* term MUST be rounded to G seconds".
*
* See also Notes #2a1A3 & #2a1B3.
*
* (B) (1) RFC #2988, Section 2.4 adds that "a maximum value MAY be placed on
* RTO provided it is at least 60 seconds".
*
* (2) RFC #1122, Section 4.2.3.1 states that "the recommended ... RTO ...
* upper bound should be 2*MSL".
*
* (3) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2,
* Page 299 states that "the timeout value ... [has] an upper limit of
* 64 seconds".
*
* See also 'net_tcp.c NetTCP_TxConnRTO_CfgMaxTimeout() Note #1'.
*
* (2) RFC #1122, Section 4.2.3.1 reiterates that an "implementation MUST also
* include 'exponential backoff' for successive RTO values for the same
* segment".
*
* (a) RFC #2988, Section 5.5 states that "when the retransmission timer
* expires ... the host MUST set RTO <- RTO * 2 ('back off the timer')".
*
* Thus, the TCP retransmission timer exponential back-off scalar
* value is 2.
*
* (b) Stevens, TCP/IP Illustrated, Volume 1, 8th Printing, Section 21.2,
* Page 299 reiterates that "this doubling is called an 'exponential
* backoff'".
*
* See also 'NetTCP_TxConnRTO_CalcBackOff() Note #1'.
*********************************************************************************************************
*/
static void NetTCP_TxConnRTT_RTO_Calc (NET_TCP_CONN *pconn,
NET_TCP_CALC_CODE calc_code,
NET_TCP_TX_RTT_TS_MS rtt_ts_txd_ms,
NET_TCP_TX_RTT_TS_MS rtt_ts_rxd_ms)
{
NET_TCP_TIMEOUT_MS timeout_ms;
NET_TMR_TICK timeout_tick;
NET_TCP_TX_RTT_MS rtt_cur_ms;
NET_TCP_TX_RTT_MS_SCALED rtt_cur_ms_scaled;
NET_TCP_TX_RTT_MS_SCALED rtt_err_ms_scaled;
NET_TCP_TX_RTT_MS_SCALED rtt_err_ms_scaled_abs;
NET_TCP_TX_RTT_MS_SCALED rtt_avg_ms_scaled;
NET_TCP_TX_RTT_MS_SCALED rtt_dev_ms_scaled;
NET_TCP_TX_RTT_MS_SCALED rtt_dev_ms_scaled_gain;
NET_TCP_TX_RTT_MS_SCALED rtt_dev_ms_scaled_min;
NET_TCP_TX_RTT_MS_SCALED rto_ms_scaled;
/*$PAGE*/
/* -------------- PERFORM CALC CODE --------------- */
switch (calc_code) {
case NET_TCP_CONN_TX_RTT_CALC:
break;
case NET_TCP_CONN_TX_RTT_BACKOFF: /* Back-off RTO (see Note #2b2). */
timeout_ms = (NET_TCP_TIMEOUT_MS ) NetTCP_TxConnRTO_CalcBackOff(pconn, pconn->TxRTT_RTO_ms);
timeout_tick = ((NET_TMR_TICK ) timeout_ms * NET_TMR_TIME_TICK_PER_SEC) / DEF_TIME_NBR_mS_PER_SEC;
pconn->TxRTT_RTO_ms = (NET_TCP_TIMEOUT_MS ) timeout_ms;
pconn->TxRTT_RTO_sec = (NET_TCP_TIMEOUT_SEC)(timeout_ms / DEF_TIME_NBR_mS_PER_SEC);
pconn->TxRTT_RTO_tick = (NET_TMR_TICK ) timeout_tick;
/* 'break' intentionally omitted; do NOT move from */
/* ... following case : 'NET_TCP_CONN_TX_RTT_RESET'.*/
case NET_TCP_CONN_TX_RTT_RESET: /* See Note #2a4. */
NetTCP_TxConnRTT_Reset(pconn);
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_TCP_CONN_TX_RTT_INIT:
default:
NetTCP_TxConnRTT_RTO_Init(pconn);
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* -------------- PREPARE RTT CALCS --------------- */
switch (pconn->TxRTT_RTO_State) {
case NET_TCP_TX_RTT_RTO_STATE_INIT:
case NET_TCP_TX_RTT_RTO_STATE_RESET:
case NET_TCP_TX_RTT_RTO_STATE_CALC:
rtt_cur_ms = (NET_TCP_TX_RTT_MS )(rtt_ts_rxd_ms - rtt_ts_txd_ms);
rtt_cur_ms_scaled = (NET_TCP_TX_RTT_MS_SCALED)(rtt_cur_ms * NET_TCP_TX_RTT_SCALE);
break;
case NET_TCP_TX_RTT_RTO_STATE_NONE:
case NET_TCP_TX_RTT_RTO_STATE_RE_TX: /* See Note #2a5. */
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* -------------- PERFORM RTT CALCS --------------- */
switch (pconn->TxRTT_RTO_State) {
case NET_TCP_TX_RTT_RTO_STATE_INIT: /* Init RTT calcs (see Notes #2a1A1 & #2a1A2). */
case NET_TCP_TX_RTT_RTO_STATE_RESET:
rtt_avg_ms_scaled = (rtt_cur_ms_scaled * NET_TCP_TX_RTT_GAIN_AVG_INIT_NUMER)
/ NET_TCP_TX_RTT_GAIN_AVG_INIT_DENOM;
rtt_dev_ms_scaled = (rtt_cur_ms_scaled * NET_TCP_TX_RTT_GAIN_DEV_INIT_NUMER)
/ NET_TCP_TX_RTT_GAIN_DEV_INIT_DENOM;
pconn->TxRTT_RTO_State = NET_TCP_TX_RTT_RTO_STATE_CALC;
break;
case NET_TCP_TX_RTT_RTO_STATE_CALC: /* Update RTT calcs (see Notes #2a1Bb1D & #2a1Bb2C).*/
rtt_err_ms_scaled = rtt_cur_ms_scaled - pconn->TxRTT_Avg_ms_scaled;
rtt_err_ms_scaled_abs = DEF_ABS(rtt_err_ms_scaled);
rtt_dev_ms_scaled = pconn->TxRTT_Dev_ms_scaled + (((rtt_err_ms_scaled_abs - pconn->TxRTT_Dev_ms_scaled) * NET_TCP_TX_RTT_GAIN_DEV_NUMER)
/ NET_TCP_TX_RTT_GAIN_DEV_DENOM);
rtt_avg_ms_scaled = pconn->TxRTT_Avg_ms_scaled + ((rtt_err_ms_scaled * NET_TCP_TX_RTT_GAIN_AVG_NUMER)
/ NET_TCP_TX_RTT_GAIN_AVG_DENOM);
break;
case NET_TCP_TX_RTT_RTO_STATE_NONE:
case NET_TCP_TX_RTT_RTO_STATE_RE_TX: /* See Note #2a5. */
default:
return; /* Prevent 'break NOT reachable' compiler warning. */
}
/* ------------------ UPDATE RTT ------------------ */
pconn->TxRTT_Avg_ms_scaled = rtt_avg_ms_scaled;
pconn->TxRTT_Dev_ms_scaled = rtt_dev_ms_scaled;
NetTCP_TxConnRTT_CalcUpdate(pconn);
/*$PAGE*/
/* ------------------- CALC RTO ------------------- */
/* Calc RTO (see Note #2a1B3). */
rtt_dev_ms_scaled_gain = (pconn->TxRTT_Dev_ms_scaled * NET_TCP_TX_RTT_GAIN_RTO_NUMER)
/ NET_TCP_TX_RTT_GAIN_RTO_DENOM;
/* Limit RTT dev (see Note #2b1A2). */
rtt_dev_ms_scaled_min = DEF_MAX(NET_TCP_TX_RTT_TS_CLK_MS_SCALED,
rtt_dev_ms_scaled_gain);
rto_ms_scaled = pconn->TxRTT_Avg_ms_scaled + rtt_dev_ms_scaled_min;
/* Limit RTO (see Note #2b1). */
if (rto_ms_scaled < NET_TCP_TX_RTO_MIN_TIMEOUT_MS_SCALED) {
rto_ms_scaled = NET_TCP_TX_RTO_MIN_TIMEOUT_MS_SCALED;
}
if (rto_ms_scaled > pconn->TxRTT_RTO_Max_ms_scaled) {
rto_ms_scaled = pconn->TxRTT_RTO_Max_ms_scaled;
}
/* ------------------ UPDATE RTO ------------------ */
pconn->TxRTT_RTO_ms_scaled = rto_ms_scaled;
NetTCP_TxConnRTO_CalcUpdate(pconn);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktHandler()
*
* Description : (1) Prepare & transmit TCP packets :
*
* (a) Validate transmit packet
* (b) Transmit TCP packet
* (c) Free transmit packet buffer(s)
* (d) Update transmit statistics
*
*
* Argument(s) : pbuf Pointer to network buffer to transmit TCP packet.
*
* src_addr Source IP address.
*
* src_port Source TCP port.
*
* dest_addr Destination IP address.
*
* dest_port Destination TCP port.
*
* seq_nbr TCP segment sequence number.
*
* ack_nbr TCP segment acknowledgement sequence number.
*
* win_size TCP receive window advertisement size.
*
* TOS Specific TOS to transmit TCP/IP packet
* (see 'net_ip.h IP HEADER TYPE OF SERVICE (TOS) DEFINES').
*
* TTL Specific TTL to transmit TCP/IP packet (see RFC #1122, Section 3.2.1.7) :
*
* NET_IP_HDR_TTL_MIN 1 minimum TTL transmit value
* NET_IP_HDR_TTL_MAX 255 maximum TTL transmit value
* NET_IP_HDR_TTL_DFLT default TTL transmit value
* NET_IP_HDR_TTL_NONE 0 replace with default TTL
*
* flags_tcp Flags to select TCP transmit options; bit-field flags logically OR'd :
*
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_FIN Set TCP 'FIN' flag.
* NET_TCP_FLAG_TX_SYNC Set TCP 'SYN' flag.
* NET_TCP_FLAG_TX_RESET Set TCP 'RESET' flag.
* NET_TCP_FLAG_TX_PUSH Set TCP 'PUSH' flag.
* NET_TCP_FLAG_TX_ACK Set TCP 'ACK' flag.
* NET_TCP_FLAG_TX_URGENT Set TCP 'URGENT' flag.
*
* flags_ip Flags to select IP transmit options; bit-field flags logically OR'd :
*
* NET_IP_FLAG_NONE No IP transmit flags selected.
* NET_IP_FLAG_TX_DONT_FRAG Set IP 'Don't Frag' flag.
*
* popts_tcp Pointer to one or more TCP options configuration data structures :
*
* NULL NO TCP transmit options configuration.
* NET_TCP_OPT_CFG_MAX_SEG_SIZE TCP Maximum Segment Size options configuration.
*
* popts_ip Pointer to one or more IP options configuration data structures :
*
* NULL NO IP transmit options configuration.
* NET_IP_OPT_CFG_ROUTE_TS Route &/or Internet Timestamp options configuration.
* NET_IP_OPT_CFG_SECURITY Security options configuration
* (see 'net_ip.c Note #1f').
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP segments(s) successfully prepared & transmitted
* to IP layer.
* NET_TCP_ERR_TX TCP transmit error; TCP segment buffer(s) discarded.
*
* ----------- RETURNED BY NetTCP_TxPkt() : -----------
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_ERR_TX Transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnSync(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset(),
* NetTCP_TxConnProbe(),
* NetTCP_TxConnTxQ(),
* NetTCP_TxConnReTxQ_Timeout().
*
* Note(s) : (2) Network buffer already freed by lower layer; only increment error counter.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxPktHandler (NET_BUF *pbuf,
NET_IP_ADDR src_addr,
NET_TCP_PORT_NBR src_port,
NET_IP_ADDR dest_addr,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
NET_IP_TOS TOS,
NET_IP_TTL TTL,
CPU_INT16U flags_tcp,
CPU_INT16U flags_ip,
void *popts_tcp,
void *popts_ip,
NET_ERR *perr)
{
#if (((NET_CTR_CFG_STAT_EN == DEF_ENABLED) || \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED)) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_BUF_HDR *pbuf_hdr;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE PTR ------------------- */
if (pbuf == (NET_BUF *)0) {
NetTCP_TxPktDiscard(pbuf, perr);
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
#endif
/* --------------- VALIDATE TX TCP PKT ---------------- */
pbuf_hdr = &pbuf->Hdr;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
NetTCP_TxPktValidate(pbuf,
pbuf_hdr,
src_port,
dest_port,
seq_nbr,
ack_nbr,
win_size,
flags_tcp,
popts_tcp,
perr);
switch (*perr) {
case NET_TCP_ERR_NONE:
break;
case NET_ERR_INVALID_PROTOCOL:
case NET_BUF_ERR_INVALID_IX:
case NET_TCP_ERR_INVALID_LEN_DATA:
case NET_TCP_ERR_INVALID_PORT_NBR:
case NET_TCP_ERR_INVALID_FLAG:
case NET_TCP_ERR_INVALID_OPT_TYPE:
case NET_TCP_ERR_INVALID_OPT_CFG:
default:
NetTCP_TxPktDiscard(pbuf, &err);
*perr = NET_TCP_ERR_TX;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
#endif
/*$PAGE*/
/* -------------------- TX TCP PKT -------------------- */
NetTCP_TxPkt(pbuf,
pbuf_hdr,
src_addr,
src_port,
dest_addr,
dest_port,
seq_nbr,
ack_nbr,
win_size,
TOS,
TTL,
flags_tcp,
flags_ip,
popts_tcp,
popts_ip,
perr);
/* ---------- FREE TX PKT / UPDATE TX STATS ----------- */
switch (*perr) {
case NET_IP_ERR_NONE:
NET_CTR_STAT_INC(NetTCP_StatTxSegCtr);
*perr = NET_TCP_ERR_NONE;
break;
case NET_ERR_TX:
NET_CTR_ERR_INC(NetTCP_ErrTxPktDiscardedCtr); /* See Note #2. */
return; /* Prevent 'break NOT reachable' compiler warning. */
case NET_ERR_INIT_INCOMPLETE:
case NET_TCP_ERR_INVALID_LEN_HDR:
case NET_TCP_ERR_INVALID_OPT_TYPE:
case NET_TCP_ERR_INVALID_OPT_LEN:
case NET_BUF_ERR_INVALID_IX:
case NET_BUF_ERR_INVALID_LEN:
case NET_UTIL_ERR_NULL_PTR:
case NET_UTIL_ERR_NULL_SIZE:
case NET_UTIL_ERR_INVALID_PROTOCOL:
default:
NetTCP_TxPktDiscard(pbuf, &err);
*perr = NET_TCP_ERR_TX;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktValidate()
*
* Description : (1) Validate TCP transmit packet parameters & options :
*
* (a) Packets with the following invalid parameters will be "silently discarded" :
*
* (1) Protocols other than supported protocols :
* (A) BSD Sockets
* (B) TCP See Note #2
*
* (2) Data Length
* (3) Source Port
* (4) Destination Port
* (5) Flags
*
* (b) The following parameters are inherently assumed to be valid :
*
* (1) Sequence Number
* (2) Acknowledgement Number
* (3) Receive Window Size
*
*
* Argument(s) : pbuf Pointer to network buffer to transmit TCP packet.
* ---- Argument checked in NetTCP_TxPktHandler().
*
* pbuf_hdr Pointer to network buffer header.
* -------- Argument validated in NetTCP_TxPktHandler().
*
* src_port Source TCP port.
*
* dest_port Destination TCP port.
*
* seq_nbr TCP segment sequence number.
*
* ack_nbr TCP segment acknowledgement sequence number.
*
* win_size TCP receive window advertisement size.
*
* flags_tcp Flags to select TCP transmit options; bit-field flags logically OR'd :
*
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_FIN Set TCP 'FIN' flag.
* NET_TCP_FLAG_TX_SYNC Set TCP 'SYN' flag.
* NET_TCP_FLAG_TX_RESET Set TCP 'RESET' flag.
* NET_TCP_FLAG_TX_PUSH Set TCP 'PUSH' flag.
* NET_TCP_FLAG_TX_ACK Set TCP 'ACK' flag.
* NET_TCP_FLAG_TX_URGENT Set TCP 'URGENT' flag.
*
* popts_tcp Pointer to one or more TCP options configuration data structures :
*
* NULL NO TCP transmit options configuration.
* NET_TCP_OPT_CFG_MAX_SEG_SIZE TCP Maximum Segment Size options configuration.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE Transmit packet validated.
* NET_ERR_INVALID_PROTOCOL Invalid/unknown protocol type.
* NET_BUF_ERR_INVALID_IX Invalid or insufficient buffer index.
* NET_TCP_ERR_INVALID_LEN_DATA Invalid protocol/data length.
* NET_TCP_ERR_INVALID_PORT_NBR Invalid TCP port number.
* NET_TCP_ERR_INVALID_FLAG Invalid TCP flag(s).
*
* - RETURNED BY NetTCP_TxPktValidateOpt() : -
* NET_TCP_ERR_INVALID_OPT_TYPE Invalid TCP option type.
* NET_TCP_ERR_INVALID_OPT_CFG Invalid TCP option configuration.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxPktHandler().
*
* Note(s) : none.
*********************************************************************************************************
*/
/*$PAGE*/
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static void NetTCP_TxPktValidate (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_TCP_PORT_NBR src_port,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
CPU_INT16U flags_tcp,
void *popts_tcp,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_INT16U ix;
CPU_INT16U len;
CPU_INT16U flag_mask;
CPU_BOOLEAN flags_tcp_fin_syn;
/* ----------------- VALIDATE PROTOCOL ---------------- */
switch (pbuf_hdr->ProtocolHdrType) {
case NET_PROTOCOL_TYPE_APP:
case NET_PROTOCOL_TYPE_SOCK:
case NET_PROTOCOL_TYPE_TCP:
ix = (CPU_INT16U)pbuf_hdr->DataIx;
len = (CPU_INT16U)pbuf_hdr->DataLen;
break;
case NET_PROTOCOL_TYPE_NONE:
default:
NET_CTR_ERR_INC(NetTCP_ErrTxInvalidProtocolCtr);
*perr = NET_ERR_INVALID_PROTOCOL;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
if (ix == NET_BUF_IX_NONE) {
NET_CTR_ERR_INC(NetTCP_ErrTxInvalidBufIxCtr);
*perr = NET_BUF_ERR_INVALID_IX;
return;
}
if (ix < NET_TCP_HDR_SIZE_MAX) {
NET_CTR_ERR_INC(NetTCP_ErrTxInvalidBufIxCtr);
*perr = NET_BUF_ERR_INVALID_IX;
return;
}
/* -------------- VALIDATE TOT DATA LEN --------------- */
if (len != pbuf_hdr->TotLen) {
NET_CTR_ERR_INC(NetTCP_ErrTxHdrDataLenCtr);
*perr = NET_TCP_ERR_INVALID_LEN_DATA;
return;
}
/* ---------------- VALIDATE TCP PORTS ---------------- */
if (src_port == NET_TCP_PORT_NBR_RESERVED) {
NET_CTR_ERR_INC(NetTCP_ErrTxHdrPortSrcCtr);
*perr = NET_TCP_ERR_INVALID_PORT_NBR;
return;
}
if (dest_port == NET_TCP_PORT_NBR_RESERVED) {
NET_CTR_ERR_INC(NetTCP_ErrTxHdrPortDestCtr);
*perr = NET_TCP_ERR_INVALID_PORT_NBR;
return;
}
/*$PAGE*/
/* ---------------- VALIDATE TCP FLAGS ---------------- */
flag_mask = NET_TCP_FLAG_NONE |
NET_TCP_FLAG_TX_CLOSE |
NET_TCP_FLAG_TX_SYNC |
NET_TCP_FLAG_TX_RESET |
NET_TCP_FLAG_TX_PUSH |
NET_TCP_FLAG_TX_ACK |
NET_TCP_FLAG_TX_URGENT;
if ((flags_tcp & ~flag_mask) != NET_TCP_FLAG_NONE) { /* If any invalid flags req'd, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrFlagsCtr);
*perr = NET_TCP_ERR_INVALID_FLAG;
return;
}
#if 1 /* ???? Allow invalid 'SYN'/'FIN' flag combo? */
flag_mask = NET_TCP_FLAG_TX_SYNC |
NET_TCP_FLAG_TX_FIN;
flags_tcp_fin_syn = DEF_BIT_IS_SET(flags_tcp, flag_mask);
if (flags_tcp_fin_syn != DEF_NO) { /* If invalid 'SYN'/'FIN' flag combo req'd, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrFlagsCtr);
*perr = NET_TCP_ERR_INVALID_FLAG;
return;
}
#endif
/* ---------------- VALIDATE TCP OPTS ----------------- */
if (popts_tcp != (void *)0) {
NetTCP_TxPktValidateOpt(popts_tcp, flags_tcp, perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
}
/* ------------- IGNORE VALID TCP FIELDS -------------- */
(void)&seq_nbr; /* Prevent compiler warnings. */
(void)&ack_nbr;
(void)&win_size;
*perr = NET_TCP_ERR_NONE;
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktValidateOpt()
*
* Description : Validate TCP transmit option configurations.
*
* (1) TCP transmit options MUST be configured by appropriate transmit options configuration
* data structure(s) passed via 'popts_tcp'; see 'net_tcp.h TCP HEADER OPTION CONFIGURATION
* DATA TYPES' for TCP options configuration.
*
* (2) TCP header allows for a maximum option size of 40 octets (see 'net_tcp.h TCP HEADER
* OPTIONS DEFINES Note #3').
*
*
* Argument(s) : popts_tcp Pointer to one or more TCP options configuration data structures (see Note #1) :
*
* NULL NO TCP transmit options configuration.
* NET_TCP_OPT_CFG_MAX_SEG_SIZE TCP Maximum Segment Size options configuration.
*
* flags_tcp Flags to select TCP transmit options; bit-field flags logically OR'd :
*
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_FIN Set TCP 'FIN' flag.
* NET_TCP_FLAG_TX_SYNC Set TCP 'SYN' flag.
* NET_TCP_FLAG_TX_RESET Set TCP 'RESET' flag.
* NET_TCP_FLAG_TX_PUSH Set TCP 'PUSH' flag.
* NET_TCP_FLAG_TX_ACK Set TCP 'ACK' flag.
* NET_TCP_FLAG_TX_URGENT Set TCP 'URGENT' flag.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP transmit option configurations validated.
* NET_TCP_ERR_INVALID_OPT_TYPE Invalid TCP option type.
* NET_TCP_ERR_INVALID_OPT_CFG Invalid TCP option configuration.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxPktValidate().
*
* Note(s) : (3) (a) See 'net_tcp.h TCP HEADER OPTIONS DEFINES' for supported TCP options' summary.
*
* (b) See 'net_tcp.c Note #1c' for unsupported TCP options.
*
* (4) The following TCP transmit options MUST be configured exclusively--i.e. only a single
* of each of the following TCP options may be configured for any one TCP segment :
*
* (a) NET_TCP_OPT_CFG_TYPE_MAX_SEG_SIZE
*********************************************************************************************************
*/
/*$PAGE*/
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static void NetTCP_TxPktValidateOpt (void *popts_tcp,
CPU_INT16U flags_tcp,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_INT08U opt_len_size;
CPU_INT08U opt_len;
CPU_INT08U opt_nbr_max_seg_size;
NET_TYPE *popt_cfg_type;
void *popt_cfg;
void *popt_next;
opt_len_size = 0;
opt_nbr_max_seg_size = 0;
popt_cfg = popts_tcp;
while (popt_cfg != (void *)0) {
popt_cfg_type = (NET_TYPE *)popt_cfg;
switch (*popt_cfg_type) {
case NET_TCP_OPT_CFG_TYPE_MAX_SEG_SIZE: /* ----------------- MAX SEG SIZE OPT ----------------- */
if (opt_nbr_max_seg_size > 0) { /* If > 1 max seg size opt, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrOptCfgCtr);
*perr = NET_TCP_ERR_INVALID_OPT_CFG;
return;
}
opt_nbr_max_seg_size++;
NetTCP_TxPktValidateOptMaxSegSize(popt_cfg, &opt_len, &popt_next, flags_tcp, perr);
break;
#if 0 /* --------------- UNSUPPORTED TCP OPTS --------------- */
/* See Note #3b. */
case NET_TCP_OPT_CFG_TYPE_WIN_SCALE:
case NET_TCP_OPT_CFG_TYPE_SACK_PERMIT:
case NET_TCP_OPT_CFG_TYPE_SACK:
case NET_TCP_OPT_CFG_TYPE_ECHO_REQ:
case NET_TCP_OPT_CFG_TYPE_ECHO_REPLY:
case NET_TCP_OPT_CFG_TYPE_TS:
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_OPT_CFG_TYPE_NONE'. */
#endif
case NET_TCP_OPT_CFG_TYPE_NONE: /* ----------------- INVALID TCP OPTS ----------------- */
default:
NET_CTR_ERR_INC(NetTCP_ErrTxOptTypeCtr);
*perr = NET_TCP_ERR_INVALID_OPT_TYPE;
return; /* Prevent 'break NOT reachable' compiler warning. */
}
if (*perr != NET_TCP_ERR_NONE) {
return;
}
opt_len_size += opt_len;
if (opt_len_size > NET_TCP_HDR_OPT_SIZE_MAX) { /* If tot opt len exceeds max opt len, rtn err. */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrOptLenCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return;
}
popt_cfg = popt_next; /* Validate next cfg opt. */
}
*perr = NET_TCP_ERR_NONE;
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktValidateOptMaxSegSize()
*
* Description : Validate TCP Maximum Segment Size option configuration.
*
* (1) See 'net_tcp.h TCP MAXIMUM SEGMENT SIZE OPTION CONFIGURATION DATA TYPE' for valid
* TCP Maximum Segment Size option configuration.
*
* (2) Return option values.
*
*
* Argument(s) : popt_tcp Pointer to TCP Maximum Segment Size option configuration data structure.
* -------- Argument checked in NetTCP_TxPktValidateOpt().
*
* popt_len Pointer to variable that will receive the TCP Maximum Segment Size option length
* -------- (in octets).
*
* Argument validated in NetTCP_TxPktValidateOpt().
*
* popt_next Pointer to variable that will receive the pointer to the next TCP transmit option.
* --------- Argument validated in NetTCP_TxPktValidateOpt().
*
* flags_tcp Flags to select TCP transmit options; bit-field flags logically OR'd :
*
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_FIN Set TCP 'FIN' flag.
* NET_TCP_FLAG_TX_SYNC Set TCP 'SYN' flag.
* NET_TCP_FLAG_TX_RESET Set TCP 'RESET' flag.
* NET_TCP_FLAG_TX_PUSH Set TCP 'PUSH' flag.
* NET_TCP_FLAG_TX_ACK Set TCP 'ACK' flag.
* NET_TCP_FLAG_TX_URGENT Set TCP 'URGENT' flag.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP Maximum Segment Size option
* configuration validated.
* NET_TCP_ERR_INVALID_OPT_TYPE Invalid TCP option type.
* NET_TCP_ERR_INVALID_OPT_CFG Invalid TCP option configuration.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxPktValidateOpt().
*
* Note(s) : (3) RFC #793, Section 3.1 'Header Format : Options : Maximum Segment Size' states that a
* TCP Maximum Segment Size option "must only be sent in the initial connection request
* (i.e., in segments with the SYN control bit set)".
*********************************************************************************************************
*/
/*$PAGE*/
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
static void NetTCP_TxPktValidateOptMaxSegSize (void *popt_tcp,
CPU_INT08U *popt_len,
void **popt_next,
CPU_INT16U flags_tcp,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_OPT_CFG_MAX_SEG_SIZE *popt_cfg_max_seg_size;
CPU_BOOLEAN flags_tcp_syn;
popt_cfg_max_seg_size = (NET_TCP_OPT_CFG_MAX_SEG_SIZE *)popt_tcp;
/* ------------------ VALIDATE TYPE ------------------- */
if (popt_cfg_max_seg_size->Type != NET_TCP_OPT_CFG_TYPE_MAX_SEG_SIZE) {
NET_CTR_ERR_INC(NetTCP_ErrTxOptTypeCtr);
*perr = NET_TCP_ERR_INVALID_OPT_TYPE;
return;
}
/* -------------- VALIDATE MAX SEG SIZE --------------- */
/* If max seg size > max, rtn err. */
if (popt_cfg_max_seg_size->MaxSegSize > NET_TCP_MAX_SEG_SIZE_MAX) {
NET_CTR_ERR_INC(NetTCP_ErrTxHdrOptCfgCtr);
*perr = NET_TCP_ERR_INVALID_OPT_CFG;
return;
}
/* -------------- VALIDATE OPT CFG/CTRL --------------- */
flags_tcp_syn = DEF_BIT_IS_SET(flags_tcp, NET_TCP_HDR_FLAG_SYNC);
if (flags_tcp_syn != DEF_YES) { /* If 'SYN' bit NOT set, rtn err (see Note #3). */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrOptCfgCtr);
*perr = NET_TCP_ERR_INVALID_OPT_CFG;
return;
}
/* ------------------- RTN OPT VALS ------------------- */
*popt_len = NET_TCP_HDR_OPT_LEN_MAX_SEG_SIZE;
*popt_next = popt_cfg_max_seg_size->NextOptPtr;
*perr = NET_TCP_ERR_NONE;
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPkt()
*
* Description : (1) Prepare TCP header & transmit TCP packet to IP layer :
*
* (a) Prepare TCP options (if any)
* (b) Calculate TCP header buffer controls
* (c) Prepare TCP header
* (d) Transmit TCP packet
*
*
* Argument(s) : pbuf Pointer to network buffer to transmit TCP packet.
* ---- Argument checked in NetTCP_TxPktHandler().
*
* pbuf_hdr Pointer to network buffer header.
* -------- Argument validated in NetTCP_TxPktHandler().
*
* src_addr Source IP address.
*
* src_port Source TCP port.
* -------- Argument checked in NetTCP_TxPktValidate().
*
* dest_addr Destination IP address.
*
* dest_port Destination TCP port.
* --------- Argument checked in NetTCP_TxPktValidate().
*
* seq_nbr TCP segment sequence number.
* ------- Argument validated in NetTCP_TxPktValidate().
*
* ack_nbr TCP segment acknowledgement sequence number.
* ------- Argument validated in NetTCP_TxPktValidate().
*
* win_size TCP receive window advertisement size.
* -------- Argument validated in NetTCP_TxPktValidate().
*
* TOS Specific TOS to transmit TCP/IP packet
* (see 'net_ip.h IP HEADER TYPE OF SERVICE (TOS) DEFINES').
*
* TTL Specific TTL to transmit TCP/IP packet (see RFC #1122, Section 3.2.1.7) :
*
* NET_IP_HDR_TTL_MIN 1 minimum TTL transmit value
* NET_IP_HDR_TTL_MAX 255 maximum TTL transmit value
* NET_IP_HDR_TTL_DFLT default TTL transmit value
* NET_IP_HDR_TTL_NONE 0 replace with default TTL
*
* flags_tcp Flags to select TCP transmit options; bit-field flags logically OR'd :
* ---------
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_FIN Set TCP 'FIN' flag.
* NET_TCP_FLAG_TX_SYNC Set TCP 'SYN' flag.
* NET_TCP_FLAG_TX_RESET Set TCP 'RESET' flag.
* NET_TCP_FLAG_TX_PUSH Set TCP 'PUSH' flag.
* NET_TCP_FLAG_TX_ACK Set TCP 'ACK' flag.
* NET_TCP_FLAG_TX_URGENT Set TCP 'URGENT' flag.
*
* Argument checked in NetTCP_TxPktValidate().
*
* flags_ip Flags to select IP transmit options; bit-field flags logically OR'd :
*
* NET_IP_FLAG_NONE No IP transmit flags selected.
* NET_IP_FLAG_TX_DONT_FRAG Set IP 'Don't Frag' flag.
*
* popts_tcp Pointer to one or more TCP options configuration data structures :
* ---------
* NULL NO TCP transmit options configuration.
* NET_TCP_OPT_CFG_MAX_SEG_SIZE TCP Maximum Segment Size options configuration.
*
* Argument checked in NetTCP_TxPktValidate().
*$PAGE*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_INVALID_LEN_HDR Invalid TCP header length.
*
* - RETURNED BY NetTCP_TxPktPrepareOpt() : -
* NET_TCP_ERR_INVALID_OPT_TYPE Invalid TCP option type.
* NET_TCP_ERR_INVALID_OPT_LEN Invalid TCP option length.
*
* - RETURNED BY NetTCP_TxPktPrepareHdr() : -
* NET_BUF_ERR_INVALID_IX Invalid/insufficient buffer index.
* NET_BUF_ERR_INVALID_LEN Invalid buffer length.
* NET_UTIL_ERR_NULL_PTR Check-sum passed a NULL pointer.
* NET_UTIL_ERR_NULL_SIZE Check-sum passed a zero size.
* NET_UTIL_ERR_INVALID_PROTOCOL Invalid data packet protocol.
*
* -------- RETURNED BY NetIP_Tx() : --------
* NET_IP_ERR_NONE TCP/IP packet successfully transmitted.
* NET_ERR_INIT_INCOMPLETE Network initialization NOT complete.
* NET_ERR_TX Transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxPktHandler().
*
* Note(s) : none.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxPkt (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
NET_IP_ADDR src_addr,
NET_TCP_PORT_NBR src_port,
NET_IP_ADDR dest_addr,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
NET_IP_TOS TOS,
NET_IP_TTL TTL,
CPU_INT16U flags_tcp,
CPU_INT16U flags_ip,
void *popts_tcp,
void *popts_ip,
NET_ERR *perr)
{
CPU_INT08U tcp_opt_len_size;
CPU_INT16U tcp_hdr_len_size;
NET_TCP_OPT_SIZE tcp_hdr_opts[NET_TCP_HDR_OPT_NBR_MAX];
/* ----------------- PREPARE TCP OPTS ----------------- */
if (popts_tcp != (void *)0) {
tcp_opt_len_size = NetTCP_TxPktPrepareOpt((void *) popts_tcp,
(CPU_INT08U *)&tcp_hdr_opts[0],
(NET_ERR *) perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
} else {
tcp_opt_len_size = 0;
}
/* ---------------- CALC TCP HDR CTRLS ---------------- */
/* Calc tot TCP hdr len (in octets). */
tcp_hdr_len_size = (CPU_INT16U)(NET_TCP_HDR_SIZE_MIN + tcp_opt_len_size);
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (tcp_hdr_len_size > NET_TCP_HDR_SIZE_MAX) {
*perr = NET_TCP_ERR_INVALID_LEN_HDR;
return;
}
#endif
/* ----------------- PREPARE TCP HDR ------------------ */
NetTCP_TxPktPrepareHdr(pbuf,
pbuf_hdr,
tcp_hdr_len_size,
tcp_opt_len_size,
src_addr,
src_port,
dest_addr,
dest_port,
seq_nbr,
ack_nbr,
win_size,
flags_tcp,
&tcp_hdr_opts[0],
perr);
if (*perr != NET_TCP_ERR_NONE) {
return;
}
/* -------------------- TX TCP PKT -------------------- */
NetIP_Tx(pbuf,
src_addr,
dest_addr,
TOS,
TTL,
flags_ip,
popts_ip,
perr);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktPrepareOpt()
*
* Description : (1) Prepare TCP header with TCP transmit options :
*
* (a) Prepare ALL TCP options from configuration
* data structure(s)
* (b) Pad remaining TCP header octets See RFC #793, Section 3.1
* 'Header Format : Padding'
*
* (2) TCP transmit options MUST be configured by appropriate options configuration data
* structure(s) passed via 'popts_tcp'; see 'net_tcp.h TCP HEADER OPTION CONFIGURATION
* DATA TYPES' for TCP options configuration.
*
*
* Argument(s) : popts_tcp Pointer to one or more TCP options configuration data structures :
* ---------
* NULL NO TCP transmit options configuration.
* NET_TCP_OPT_CFG_MAX_SEG_SIZE TCP Maximum Segment Size options configuration.
*
* Argument checked in NetTCP_TxPkt().
*
* popt_hdr Pointer to TCP transmit option buffer to prepare TCP options.
* -------- Argument validated in NetTCP_TxPkt().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP header options successfully prepared.
* NET_TCP_ERR_INVALID_OPT_TYPE Invalid TCP option type.
* NET_TCP_ERR_INVALID_OPT_LEN Invalid TCP option length.
*
* Return(s) : Total TCP option length (in octets), if NO errors.
*
* 0, otherwise.
*
* Caller(s) : NetTCP_TxPkt().
*
* Note(s) : (3) Transmit arguments & options validated in NetTCP_TxPktValidate()/NetTCP_TxPktValidateOpt() :
* (a) Assumes ALL transmit arguments & options are valid.
* (b) Assumes total transmit options' lengths are valid.
*
* (4) TCP header allows for a maximum option size of 40 octets (see 'net_tcp.h TCP HEADER
* OPTIONS DEFINES Note #3').
*
* (5) (a) RFC # 793, Section 3.1 'Options' states that each option is "a multiple of 8 bits
* in length" and "may begin on any octet boundary".
*
* (b) Since TCP options are NOT required or guaranteed to align multi-octet words on
* appropriate word boundaries, ALL TCP options are prepared a single octet at a time.
*
* (6) Default case already invalidated in NetTCP_TxPktValidateOpt(). However, the default
* case is included as an extra precaution in case any of the TCP transmit options types
* are incorrectly modified.
*********************************************************************************************************
*/
/*$PAGE*/
static CPU_INT08U NetTCP_TxPktPrepareOpt (void *popts_tcp,
CPU_INT08U *popt_hdr,
NET_ERR *perr)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_INT08U tcp_opt_len_tot;
CPU_INT08U tcp_opt_len;
CPU_INT08U *popt_cfg_hdr;
NET_TYPE *popt_cfg_type;
void *popt_next;
void *popt_cfg;
tcp_opt_len_tot = 0;
popt_cfg = popts_tcp;
popt_cfg_hdr = popt_hdr;
/* ----------------- PREPARE TCP OPTS ----------------- */
while (popt_cfg != (void *)0) { /* Prepare ALL cfg'd TCP opts (see Note #1a). */
popt_cfg_type = (NET_TYPE *)popt_cfg;
switch (*popt_cfg_type) {
case NET_TCP_OPT_CFG_TYPE_MAX_SEG_SIZE:
NetTCP_TxPktPrepareOptMaxSegSize(popt_cfg, popt_cfg_hdr, &tcp_opt_len, &popt_next, perr);
break;
#if 0 /* --------------- UNSUPPORTED TCP OPTS --------------- */
case NET_TCP_OPT_CFG_TYPE_WIN_SCALE:
case NET_TCP_OPT_CFG_TYPE_SACK_PERMIT:
case NET_TCP_OPT_CFG_TYPE_SACK:
case NET_TCP_OPT_CFG_TYPE_ECHO_REQ:
case NET_TCP_OPT_CFG_TYPE_ECHO_REPLY:
case NET_TCP_OPT_CFG_TYPE_TS:
/* 'break' intentionally omitted; do NOT move from the */
/* ... following case : 'NET_TCP_OPT_CFG_TYPE_NONE'. */
#endif
case NET_TCP_OPT_CFG_TYPE_NONE: /* ----------------- INVALID TCP OPTS ----------------- */
default: /* See Note #6. */
NET_CTR_ERR_INC(NetTCP_ErrTxOptTypeCtr);
*perr = NET_TCP_ERR_INVALID_OPT_TYPE;
return (0); /* Prevent 'break NOT reachable' compiler warning. */
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (*perr != NET_TCP_ERR_NONE) { /* See Note #3a. */
return (0);
}
if (tcp_opt_len_tot > NET_TCP_HDR_OPT_SIZE_MAX) { /* See Note #3b. */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrOptLenCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return (0);
}
#endif
tcp_opt_len_tot += tcp_opt_len;
popt_cfg_hdr += tcp_opt_len;
popt_cfg = popt_next; /* Prepare next cfg opt. */
}
/* ------------------- PAD TCP HDR -------------------- */
if (tcp_opt_len_tot > 0) {
/* Pad rem'ing TCP hdr octets (see Note #1b). */
while ((tcp_opt_len_tot % NET_TCP_HDR_OPT_SIZE_WORD) &&
(tcp_opt_len_tot <= NET_TCP_HDR_OPT_SIZE_MAX )) {
*popt_cfg_hdr = NET_TCP_HDR_OPT_PAD;
popt_cfg_hdr++;
tcp_opt_len_tot++;
}
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (tcp_opt_len_tot > NET_TCP_HDR_OPT_SIZE_MAX) { /* See Note #3b. */
NET_CTR_ERR_INC(NetTCP_ErrTxHdrOptLenCtr);
*perr = NET_TCP_ERR_INVALID_OPT_LEN;
return (0);
}
#endif
}
*perr = NET_TCP_ERR_NONE;
return (tcp_opt_len_tot);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktPrepareOptMaxSegSize()
*
* Description : (1) Prepare TCP header with TCP Maximum Segment Size option :
*
* (a) Prepare TCP Maximum Segment Size option
* (b) Return option values
*
*
* Argument(s) : popts_tcp Pointer to TCP Maximum Segment Size option configuration data structure.
* --------- Argument checked in NetTCP_TxPkt().
*
* popt_hdr Pointer to TCP transmit option buffer to prepare TCP Maximum Segment Size option.
* -------- Argument validated in NetTCP_TxPkt().
*
* popt_len Pointer to variable that will receive the returned TCP option length (in octets).
* -------- Argument validated in NetTCP_TxPktPrepareOpt().
*
* popt_next Pointer to variable that will receive the pointer to the next TCP transmit option.
* -------- Argument validated in NetTCP_TxPktPrepareOpt().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP Maximum Segment Size option successfully
* prepared.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxPktPrepareOpt().
*
* Note(s) : (2) See 'net_tcp.h TCP HEADER OPTIONS DEFINES Note #2b1' for TCP Maximum Segment Size
* option summary.
*
* (3) Transmit arguments & options validated in NetTCP_TxPktValidate()/NetTCP_TxPktValidateOpt() :
* (a) Assumes ALL transmit arguments & options are valid.
* (b) Assumes total transmit options' lengths are valid.
*
* (4) (a) RFC # 793, Section 3.1 'Options' states that each option is "a multiple of 8 bits
* in length" and "may begin on any octet boundary".
*
* (b) Since TCP options are NOT required or guaranteed to align multi-octet words on
* appropriate word boundaries, ALL TCP options are prepared a single octet at a time.
*
* (5) #### 'perr' may NOT be necessary (remove if unnecessary).
*********************************************************************************************************
*/
static void NetTCP_TxPktPrepareOptMaxSegSize (void *popts_tcp,
CPU_INT08U *popt_hdr,
CPU_INT08U *popt_len,
void **popt_next,
NET_ERR *perr)
{
NET_TCP_OPT_CFG_MAX_SEG_SIZE *popt_cfg_max_seg_size;
CPU_INT08U *popt_cfg_hdr;
CPU_INT08U opt_len;
CPU_INT08U max_seg_size_hi;
CPU_INT08U max_seg_size_lo;
/* ------------- PREPARE MAX SEG SIZE OPT ------------- */
popt_cfg_max_seg_size = (NET_TCP_OPT_CFG_MAX_SEG_SIZE *)popts_tcp;
popt_cfg_hdr = popt_hdr;
opt_len = NET_TCP_HDR_OPT_LEN_MAX_SEG_SIZE;
max_seg_size_hi = (CPU_INT08U)(popt_cfg_max_seg_size->MaxSegSize >> DEF_OCTET_NBR_BITS);
max_seg_size_lo = (CPU_INT08U) popt_cfg_max_seg_size->MaxSegSize;
*popt_cfg_hdr = NET_TCP_HDR_OPT_MAX_SEG_SIZE; /* Prepare opt type. */
popt_cfg_hdr++;
*popt_cfg_hdr = opt_len; /* Prepare opt len. */
popt_cfg_hdr++;
*popt_cfg_hdr = max_seg_size_hi; /* Prepare max seg size val. */
popt_cfg_hdr++;
*popt_cfg_hdr = max_seg_size_lo;
/* ------------------- RTN OPT VALS ------------------- */
*popt_len = opt_len;
*popt_next = popt_cfg_max_seg_size->NextOptPtr;
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktPrepareHdr()
*
* Description : (1) Prepare TCP header :
*
* (a) Update network buffer's protocol index & length controls.
*
* (b) Prepare the transmit packet's following TCP header fields :
*
* (1) Source Port
* (2) Destination Port
* (3) Sequence Number
* (4) Acknowledgement Number
* (5) Header Length/Flags
* (6) Window Advertisement
* (7) Check-Sum See Note #3
* (8) Urgent Pointer See Note #2
* (9) Options
*
* (c) Convert the following TCP header fields from host-order to network-order :
*
* (1) Source Port
* (2) Destination Port
* (3) Sequence Number
* (4) Acknowledgement Number
* (5) Header Length/Flags
* (6) Window Advertisement
* (7) Check-Sum See Note #3e
* (8) Urgent Pointer See Note #2
*
* (d) Get TCP packet RTT timestamp transmitted. See 'NetTCP_TxConnRTT_RTO_Calc()
* Note #2a2A1'
*
*$PAGE*
* Argument(s) : pbuf Pointer to network buffer to transmit TCP packet.
* ---- Argument checked in NetTCP_TxPktHandler().
*
* pbuf_hdr Pointer to network buffer header.
* -------- Argument validated in NetTCP_TxPktHandler().
*
* tcp_hdr_len_tot Total TCP header length.
* --------------- Argument checked in NetTCP_TxPkt().
*
* tcp_opt_len_tot Total TCP header options' length.
* --------------- Argument checked in NetTCP_TxPktPrepareOpt().
*
* src_addr Source IP address.
*
* src_port Source TCP port.
* -------- Argument checked in NetTCP_TxPktValidate().
*
* dest_addr Destination IP address.
*
* dest_port Destination TCP port.
* --------- Argument checked in NetTCP_TxPktValidate().
*
* seq_nbr TCP segment sequence number.
* ------- Argument validated in NetTCP_TxPktValidate().
*
* ack_nbr TCP segment acknowledgement sequence number.
* ------- Argument validated in NetTCP_TxPktValidate().
*
* win_size TCP receive window advertisement size.
* -------- Argument validated in NetTCP_TxPktValidate().
*
* flags_tcp Flags to select TCP transmit options; bit-field flags logically OR'd :
* ---------
* NET_TCP_FLAG_NONE No TCP transmit flags selected.
* NET_TCP_FLAG_TX_FIN Set TCP 'FIN' flag.
* NET_TCP_FLAG_TX_SYNC Set TCP 'SYN' flag.
* NET_TCP_FLAG_TX_RESET Set TCP 'RESET' flag.
* NET_TCP_FLAG_TX_PUSH Set TCP 'PUSH' flag.
* NET_TCP_FLAG_TX_ACK Set TCP 'ACK' flag.
* NET_TCP_FLAG_TX_URGENT Set TCP 'URGENT' flag.
*
* Argument checked in NetTCP_TxPktValidate().
*
* ptcp_hdr_opts Pointer to TCP options buffer.
* ------------- Argument checked in NetTCP_TxPktPrepareOpt().
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_TCP_ERR_NONE TCP header successfully prepared.
*
* ----------- RETURNED BY NetBuf_DataWr() : ------------
* NET_BUF_ERR_INVALID_IX Invalid buffer index for transmit options.
* NET_BUF_ERR_INVALID_LEN Invalid buffer length for transmit options.
*
* - RETURNED BY NetUtil_16BitOnesCplChkSumDataCalc() : -
* NET_UTIL_ERR_NULL_PTR Check-sum passed a NULL pointer.
* NET_UTIL_ERR_NULL_SIZE Check-sum passed a zero size.
* NET_UTIL_ERR_INVALID_PROTOCOL Invalid data packet protocol.
* NET_BUF_ERR_INVALID_IX Invalid buffer index.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxPkt().
*$PAGE*
* Note(s) : (2) Urgent pointer & data NOT supported (see 'net_tcp.c Note #1b').
*
* (3) (a) TCP header Check-Sum MUST be calculated AFTER the entire TCP header has been prepared.
* In addition, ALL multi-octet words are converted from host-order to network-order
* since "the sum of 16-bit integers can be computed in either byte order" [RFC #1071,
* Section 2.(B)].
*
* (b) TCP header Check-Sum field MUST be cleared to '0' BEFORE the TCP header Check-Sum is
* calculated (see RFC #793, Section 3.1 'Header Format : Checksum').
*
* (c) (1) In addition to the TCP segment header & data, the TCP Check-Sum calculation
* includes "a 96-bit pseudo header conceptually prefixed to the TCP header ...
* [which] contains the Source Address, the Destination Address, the Protocol,
* and TCP length" (see RFC #793, Section 3.1 'Header Format : Checksum').
*
* (2) Since network check-sum functions REQUIRE that 16-bit one's-complement check-
* sum calculations be performed on headers & data arranged in network-order (see
* 'net_util.c NetUtil_16BitOnesCplChkSumDataCalc() Note #3'), TCP pseudo-header
* values MUST be set or converted to network-order.
*
* (d) RFC #793, Section 3.1 'Header Format : Checksum' specifies that "if a segment contains
* an odd number of header and text octets ... the last octet is padded ... with zeros to
* form a 16-bit word for checksum purposes".
*
* See also 'net_util.c NetUtil_16BitSumDataCalc() Note #8'.
*
* (e) The TCP header Check-Sum field is returned in network-order & MUST NOT be re-
* converted back to host-order (see 'net_util.c NetUtil_16BitOnesCplChkSumDataCalc()
* Note #4').
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_TxPktPrepareHdr (NET_BUF *pbuf,
NET_BUF_HDR *pbuf_hdr,
CPU_INT16U tcp_hdr_len_tot,
CPU_INT08U tcp_opt_len_tot,
NET_IP_ADDR src_addr,
NET_TCP_PORT_NBR src_port,
NET_IP_ADDR dest_addr,
NET_TCP_PORT_NBR dest_port,
NET_TCP_SEQ_NBR seq_nbr,
NET_TCP_SEQ_NBR ack_nbr,
NET_TCP_WIN_SIZE win_size,
CPU_INT16U flags_tcp,
CPU_INT32U *ptcp_hdr_opts,
NET_ERR *perr)
{
NET_TCP_HDR *ptcp_hdr;
NET_TCP_PSEUDO_HDR tcp_pseudo_hdr;
CPU_INT16U tcp_hdr_len;
CPU_INT16U tcp_flags;
CPU_INT16U tcp_hdr_len_flags;
CPU_INT16U tcp_opt_ix;
NET_CHK_SUM tcp_chk_sum;
/* ----------------- UPDATE BUF CTRLS ----------------- */
pbuf_hdr->TCP_UDP_HdrLen = tcp_hdr_len_tot;
pbuf_hdr->TCP_UDP_HdrDataIx = pbuf_hdr->DataIx - pbuf_hdr->TCP_UDP_HdrLen;
pbuf_hdr->TotLen += (NET_BUF_SIZE)pbuf_hdr->TCP_UDP_HdrLen;
pbuf_hdr->TCP_UDP_TotLen = (CPU_INT16U )pbuf_hdr->TotLen;
pbuf_hdr->TCP_UDP_DataLen = (CPU_INT16U )pbuf_hdr->DataLen;
pbuf_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_TCP;
/* ----------------- PREPARE TCP HDR ------------------ */
ptcp_hdr = (NET_TCP_HDR *)&pbuf->Data[pbuf_hdr->TCP_UDP_HdrDataIx];
/* ---------------- PREPARE TCP PORTS ----------------- */
NET_UTIL_VAL_COPY_SET_NET_16(&ptcp_hdr->PortSrc, &src_port);
NET_UTIL_VAL_COPY_SET_NET_16(&ptcp_hdr->PortDest, &dest_port);
/* --------------- PREPARE TCP SEQ NBRS --------------- */
NET_UTIL_VAL_COPY_SET_NET_32(&ptcp_hdr->SeqNbr, &seq_nbr);
NET_UTIL_VAL_COPY_SET_NET_32(&ptcp_hdr->AckNbr, &ack_nbr);
/* ------------ PREPARE TCP HDR LEN/FLAGS ------------- */
tcp_hdr_len = pbuf_hdr->TCP_UDP_HdrLen / NET_TCP_HDR_LEN_WORD_SIZE;
tcp_hdr_len <<= NET_TCP_HDR_LEN_SHIFT;
tcp_flags = NET_TCP_HDR_FLAG_NONE;
tcp_flags |= flags_tcp;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
tcp_hdr_len &= NET_TCP_HDR_LEN_MASK;
tcp_flags &= NET_TCP_HDR_FLAG_MASK;
#endif
tcp_hdr_len_flags = tcp_hdr_len | tcp_flags;
NET_UTIL_VAL_COPY_SET_NET_16(&ptcp_hdr->HdrLen_Flags, &tcp_hdr_len_flags);
/* ----------------- PREPARE TCP WIN ------------------ */
NET_UTIL_VAL_COPY_SET_NET_16(&ptcp_hdr->WinSize, &win_size);
/* -------------- PREPARE TCP URGENT PTR -------------- */
/* See Note #2. */
NET_UTIL_VAL_SET_NET_16(&ptcp_hdr->UrgentPtr, NET_TCP_HDR_URG_PTR_NONE);
/*$PAGE*/
/* ----------------- PREPARE TCP OPTS ----------------- */
if (tcp_opt_len_tot > 0) {
tcp_opt_ix = pbuf_hdr->TCP_UDP_HdrDataIx + NET_TCP_HDR_OPT_IX;
NetBuf_DataWr((NET_BUF *)pbuf,
(NET_BUF_SIZE)tcp_opt_ix,
(NET_BUF_SIZE)tcp_opt_len_tot,
(CPU_INT08U *)ptcp_hdr_opts,
(NET_ERR *)perr);
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
if (*perr != NET_BUF_ERR_NONE) {
return;
}
#endif
}
/* --------------- PREPARE TCP CHK SUM ---------------- */
NET_UTIL_VAL_SET_NET_16(&ptcp_hdr->ChkSum, 0x0000); /* Clr TCP chk sum (see Note #3b). */
/* Cfg TCP chk sum pseudo-hdr (see Note #3c). */
tcp_pseudo_hdr.AddrSrc = (NET_IP_ADDR)NET_UTIL_HOST_TO_NET_32(src_addr);
tcp_pseudo_hdr.AddrDest = (NET_IP_ADDR)NET_UTIL_HOST_TO_NET_32(dest_addr);
tcp_pseudo_hdr.Zero = (CPU_INT08U )0x00;
tcp_pseudo_hdr.Protocol = (CPU_INT08U )NET_IP_HDR_PROTOCOL_TCP;
tcp_pseudo_hdr.TotLen = (CPU_INT16U )NET_UTIL_HOST_TO_NET_16(pbuf_hdr->TCP_UDP_TotLen);
/* Calc TCP chk sum. */
tcp_chk_sum = NetUtil_16BitOnesCplChkSumDataCalc((void *) pbuf,
(void *)&tcp_pseudo_hdr,
(CPU_INT16U) NET_TCP_PSEUDO_HDR_SIZE,
(NET_ERR *) perr);
if (*perr != NET_UTIL_ERR_NONE) {
return;
}
NET_UTIL_VAL_COPY_16(&ptcp_hdr->ChkSum, &tcp_chk_sum); /* Copy TCP chk sum in net order (see Note #3e). */
/* ---------------- GET TCP RTT TX TS ----------------- */
pbuf_hdr->TCP_RTT_TS_Txd_ms = (CPU_INT32U)NetTCP_TxConnRTT_GetTS_ms();
*perr = NET_TCP_ERR_NONE;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_TxPktFree()
*
* Description : Free network buffer(s).
*
* Argument(s) : pbuf_q Pointer to network buffer queue.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerReTxQ(),
* NetTCP_TxConnAck(),
* NetTCP_TxConnReset().
*
* Note(s) : (1) (a) Although TCP Transmit initially requests the network buffer for transmit, the
* TCP layer maintains a reference to the buffer for possible retransmission.
*
* (b) Therefore, even though the network interface layer frees ALL unreferenced
* buffers after successful transmission [see 'net_if_pkt.c NetIF_Pkt_TxPktFree()'
* or 'net_if_char.c NetIF_Char_TxPktFree()'], the TCP layer MUST free transmit
* buffers which are still referenced.
*********************************************************************************************************
*/
static void NetTCP_TxPktFree (NET_BUF *pbuf_q)
{
NetBuf_FreeBufQ_PrimList((NET_BUF *)pbuf_q,
(NET_CTR *)0);
}
/*
*********************************************************************************************************
* NetTCP_TxPktDiscard()
*
* Description : On any Transmit packet errors, discard TCP packet(s) & buffer(s).
*
* Argument(s) : pbuf Pointer to network buffer.
*
* perr Pointer to variable that will receive the return error code from this function :
*
* NET_ERR_TX Transmit error.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_TxConnAppData(),
* NetTCP_TxPktHandler().
*
* Note(s) : (1) Since some TCP Transmit packets are passed the network buffer from other TCP functions,
* they may NOT be the buffers' only references & MUST therefore check buffers' reference
* counter before freeing buffers.
*********************************************************************************************************
*/
static void NetTCP_TxPktDiscard (NET_BUF *pbuf,
NET_ERR *perr)
{
NET_CTR *pctr;
#if (NET_CTR_CFG_ERR_EN == DEF_ENABLED)
pctr = (NET_CTR *)&NetTCP_ErrTxPktDiscardedCtr;
#else
pctr = (NET_CTR *) 0;
#endif
NetBuf_FreeBufQ_PrimList((NET_BUF *)pbuf,
(NET_CTR *)pctr);
*perr = NET_ERR_TX;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfg()
*
* Description : (1) Configure TCP connection's controls :
*
* (a) Configure TCP connection's connection maximum segment size See Note #2
* (b) Configure TCP connection's receive window controls See Note #3
* (c) Configure TCP connection's transmit window controls See Note #4
* (d) Initialize TCP connection's transmit round-trip time &
* re-transmit timeout controls
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_RxPktConnHandlerListen(),
* NetTCP_RxPktConnHandlerSyncTxd(),
* NetTCP_ConnClr().
*
* cfg_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CFG_NONE Perform NO configuration actions.
* NET_TCP_CONN_CFG_ALL Perform ALL configuration actions.
*
* NET_TCP_CONN_CFG_MAX_SEG_SIZE_LOCAL Configure local maximum segment size.
* NET_TCP_CONN_CFG_MAX_SEG_SIZE_REMOTE Configure remote maximum segment size.
* NET_TCP_CONN_CFG_MAX_SEG_SIZE_CONN Configure connection maximum segment size.
* NET_TCP_CONN_CFG_MAX_SEG_SIZE_ALL Configure ALL maximum segment sizes.
*
* NET_TCP_CONN_CFG_WIN_SIZE_RX Configure receive window size(s).
* NET_TCP_CONN_CFG_WIN_SIZE_TX Configure transmit window size(s).
* NET_TCP_CONN_CFG_WIN_SIZE_CONN Configure connection window size(s).
* NET_TCP_CONN_CFG_WIN_SIZE_ALL Configure ALL window sizes.
*
* NET_TCP_CONN_CFG_TX_RTT_RTO Configure transmit round-trip time (RTT)
* & re-transmit timeout (RTO) control(s).
*
* See also 'TCP CONNECTION CONFIGURATION CODE DEFINES'.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerListen(),
* NetTCP_RxPktConnHandlerSyncTxd(),
* NetTCP_ConnClr().
*
* Note(s) : (2) A TCP connection's connection maximum segment size should NOT be updated until
* after certain other TCP connection control(s) have been configured.
*
* See also 'NetTCP_ConnCfgMaxSegSize() Note #3'.
*
* (3) A TCP connection's receive window controls should NOT be updated until after
* certain other TCP connection control(s) have been configured.
*
* See also 'NetTCP_RxConnWinSizeCfg() Note #2'.
*
* (4) A TCP connection's transmit window controls should NOT be updated until after
* certain other TCP connection control(s) have been configured.
*
* See also 'NetTCP_TxConnWinSizeCfg() Note #2'.
*
* (5) A TCP connection's transmit round-trip time & re-transmit timeout controls
* should NOT be updated until after certain other TCP connection control(s)
* have been configured.
*
* See also 'NetTCP_TxConnRTT_RTO_Init() Note #1'.
*********************************************************************************************************
*/
static void NetTCP_ConnCfg (NET_TCP_CONN *pconn,
NET_TCP_CFG_CODE cfg_code)
{
CPU_BOOLEAN cfg_conn_max_seg_size;
CPU_BOOLEAN cfg_conn_win_size;
CPU_BOOLEAN cfg_conn_tx_rtt_rto;
cfg_conn_max_seg_size = DEF_BIT_IS_SET(cfg_code, NET_TCP_CONN_CFG_MAX_SEG_SIZE_CONN);
if (cfg_conn_max_seg_size == DEF_YES) {
NetTCP_ConnCfgMaxSegSize(pconn); /* Cfg conn max seg size (see Note #2). */
}
cfg_conn_win_size = DEF_BIT_IS_SET(cfg_code, NET_TCP_CONN_CFG_WIN_SIZE_ALL);
if (cfg_conn_win_size == DEF_YES) {
NetTCP_RxConnWinSizeCfg(pconn); /* Cfg rx win ctrls (see Note #3). */
NetTCP_TxConnWinSizeCfg(pconn); /* Cfg tx win ctrls (see Note #4). */
}
cfg_conn_tx_rtt_rto = DEF_BIT_IS_SET(cfg_code, NET_TCP_CONN_CFG_TX_RTT_RTO);
if (cfg_conn_tx_rtt_rto == DEF_YES) {
NetTCP_TxConnRTT_RTO_Init(pconn); /* Init tx RTT / RTO ctrls (see Note #5). */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCfgMaxSegSize()
*
* Description : Configure TCP connection's maximum segment size.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnCfg().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnCfg().
*
* Note(s) : (1) RFC #1122, Section 4.2.2.6 states that "the maximum size of a segment that TCP really
* sends, the 'effective send MSS', MUST be the smaller of the send MSS ... and ... less
* than or equal to ... the maximum size ... that can be received".
*
* (2) In order to avoid transmit window deadlock with a remote host's receive window, the
* TCP connection's connection maximum segment size MUST be configured to ensure that
* full, maximum-segment-sized segments will transmit even for receive windows less than
* the default maximum segment size.
*
* (a) RFC #1122, Section 4.2.3.4.(3) states to "send data ... if at least a fraction Fs
* of the maximum window can be sent ... Fs is a fraction whose recommended value is
* 1/2".
*
* Thus, it seems reasonable to calculate & limit the remote host's maximum window
* size by a similar fraction.
*
* (3) A TCP connection's connection maximum segment size should NOT be updated until after
* the following TCP connection control(s) have been configured :
*
* (a) TCP connection's local maximum segment size ('MaxSegSizeLocal')
* [see 'NetTCP_ConnClr() Note #3a']
*
* (b) TCP connection's remote maximum segment size ('MaxSegSizeRemote')
* [see 'NetTCP_RxPktConnHandlerListen() Note #7'
* & 'NetTCP_RxPktConnHandlerSyncTxd() Note #3']
*
* (c) TCP connection's maximum transmit remote window size ('TxWinSizeRemoteMax')
* [see 'NetTCP_RxPktConnHandlerTxWinRemote() Note #1a2A'
* & 'NetTCP_TxConnWinSizeHandlerCongCtrl() Notes #3a2A & #3b']
*********************************************************************************************************
*/
static void NetTCP_ConnCfgMaxSegSize (NET_TCP_CONN *pconn)
{
NET_TCP_WIN_SIZE remote_win_size_th;
NET_TCP_SEG_SIZE remote_max_seg_size;
/* Calc remote max seg size (see Note #2). */
remote_win_size_th = (NET_TCP_WIN_SIZE)(((CPU_INT32U)pconn->TxWinSizeRemoteMax * NET_TCP_TX_SILLY_WIN_NUMER)
/ NET_TCP_TX_SILLY_WIN_DENOM);
remote_max_seg_size = (NET_TCP_SEG_SIZE)DEF_MIN(pconn->MaxSegSizeRemote,
remote_win_size_th);
/* Cfg conn max seg size (see Note #1). */
pconn->MaxSegSizeConn = (NET_TCP_SEG_SIZE)DEF_MIN(pconn->MaxSegSizeLocal,
remote_max_seg_size);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnClose()
*
* Description : (1) Close a TCP connection due to TCP connection fault(s) :
*
* (a) Update TCP connection close statistic(s)
* (b) Transmit TCP connection reset to remote host See Note #4
* (c) Close TCP connection
*
*
* (2) TCP connection closed internally by TCP layer when certain TCP connection parameters
* are corrupted or when certain valid TCP connection operations fail.
*
* (3) Since the mechanisms of TCP connection close are independent of the application layer
* close; TCP connection MAY need to close application layer connection(s).
*
* See also 'NetTCP_ConnCloseHandler() Note #2b'.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in various.
*
* pbuf_hdr Pointer to network buffer header that received TCP packet.
*
* close_conn_app Indicate whether to close application connection (see Note #3):
*
* DEF_YES Close application connection.
* DEF_NO Do NOT close application connection.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* Return(s) : none.
*
* Caller(s) : various.
*
* Note(s) : (4) Although NO RFC directly states to transmit a TCP reset segment when a TCP connection
* fault-closes, it is inferred & seems reasonable that a TCP reset segment SHOULD be
* transmitted whenever a TCP connection closes abnormally from any of the following
* synchronization/connected/closing states :
*
* (a) SYN-RECEIVED
* (b) SYN-SENT
* (c) ESTABLISHED
* (d) FIN-WAIT-1
* (e) FIN-WAIT-2
* (f) CLOSING
* (g) TIME_WAIT
* (h) CLOSE-WAIT
* (i) LAST-ACK
*
* See also 'NetTCP_TxConnReset() Note #3b'.
*
* (5) On any TCP connection handler function fault(s), TCP connection MUST NEVER be re-closed.
*
* See also 'NetTCP_ConnCloseHandler() Note #4'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnClose (NET_TCP_CONN *pconn,
NET_BUF_HDR *pbuf_hdr,
CPU_BOOLEAN close_conn_app,
NET_TCP_CLOSE_CODE close_code)
{
#if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_BOOLEAN tx_reset;
NET_ERR err;
/* ---------- UPDATE CLOSE STATS ---------- */
NET_CTR_ERR_INC(NetTCP_ErrConnCloseCtr);
/* ---------- TX TCP CONN RESET ----------- */
tx_reset = DEF_BIT_IS_SET(close_code, NET_TCP_CONN_CLOSE_CONN_TX_RESET);
if (tx_reset == DEF_YES) { /* Tx TCP conn reset (see Note #4). */
NetTCP_TxConnReset((NET_TCP_CONN *) pconn,
(NET_BUF_HDR *) pbuf_hdr,
(NET_TCP_RESET_CODE) NET_TCP_CONN_TX_RESET_FAULT,
(NET_TCP_CLOSE_CODE) NET_TCP_CONN_CLOSE_NONE, /* MUST NOT re-close TCP conn (see Note #5).*/
(NET_ERR *)&err);
}
/* ------------ CLOSE TCP CONN ------------ */
NetTCP_ConnCloseHandler(pconn, close_conn_app, close_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCloseHandler()
*
* Description : (1) Close a TCP connection :
*
* (a) Close network connection(s) See Note #2
* (b) Free TCP connection
*
*
* (2) (a) TCP connection's network connection(s) MUST be closed BEFORE the TCP connection
* is closed/freed.
*
* (b) TCP connection's application connection(s) :
*
* (1) MAY be CLOSED &/or reset :
*
* (A) For the following TCP connection condition(s), the TCP connection MUST
* close the application connection(s) :
*
* (1) (a) Invalid TCP connection parameters :
* (1) Invalid TCP connection state(s)
* (2) Invalid/corrupted TCP data queue(s) :
* (A) Invalid sequence numbers
* (B) Invalid segment lengths
*
* (b) Fatal TCP transmit fault(s)
* (c) TCP connection closing fault(s)
*
* (2) Invalid network connection configuration
*
* (B) For the following TCP connection condition(s), the TCP connection SHOULD
* close the application connection(s) based on its application close flag
* ('ConnCloseAppFlag') :
*
* (1) Valid TCP connection closing states/timeouts
*
* (C) For the following TCP connection condition(s), the TCP connection MAY --
* but is NOT required to -- close the application connection(s) :
*
* (1) Initial TCP connection configuration/preparation
*
* (2) But possibly NOT freed, since some application connections have NO mechanism
* or API to close an application's reference to the connection.
*
* See also specific application connection close function(s) for additional notes.
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnClose(),
* NetTCP_ConnCloseTimeout(),
* various.
*
* close_conn_app Indicate whether to close application connection (see Note #2b):
*
* DEF_YES Close application connection.
* DEF_NO Do NOT close application connection.
*
* close_code Select which close action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_CLOSE_NONE Perform NO close actions.
* NET_TCP_CONN_CLOSE_ALL Perform ALL close actions.
*
* NET_TCP_CONN_CLOSE_CONN_TX_RESET Perform close connection transmit reset.
* NET_TCP_CONN_CLOSE_CONN_ALL Perform ALL connection close actions.
*
* NET_TCP_CONN_CLOSE_TMR_TX_IDLE Close transmit idle timer.
* NET_TCP_CONN_CLOSE_TMR_TX_SILLY_WIN Close transmit silly window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ZERO_WIN Close transmit zero window persist timer.
* NET_TCP_CONN_CLOSE_TMR_TX_ACK_DLY Close transmit acknowledgement delay timer.
* NET_TCP_CONN_CLOSE_TMR_RE_TX Close re-transmit timer.
* NET_TCP_CONN_CLOSE_TMR_KEEP_ALIVE Close connection keep-alive timer.
* NET_TCP_CONN_CLOSE_TMR_TIMEOUT Close connection timer.
* NET_TCP_CONN_CLOSE_TMR_ALL Close ALL timers.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnClose(),
* NetTCP_ConnCloseTimeout(),
* various.
*
* Note(s) : (3) TCP connection free codes are identical to TCP connection close codes.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES Note #2'.
*
* (4) On any TCP connection close, TCP connection MUST NEVER be re-closed.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnCloseHandler (NET_TCP_CONN *pconn,
CPU_BOOLEAN close_conn_app,
NET_TCP_CLOSE_CODE close_code)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
CPU_BOOLEAN used;
#endif
NET_TCP_FREE_CODE free_code;
/* ------------ VALIDATE TCP CONN CLOSE ----------- */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
used = DEF_BIT_IS_SET(pconn->Flags, NET_TCP_FLAG_USED);
if (used != DEF_YES) {
NET_CTR_ERR_INC(NetTCP_ErrNotUsedCtr);
return;
}
#endif
switch (pconn->ConnState) {
case NET_TCP_CONN_STATE_LISTEN:
case NET_TCP_CONN_STATE_SYNC_RXD:
case NET_TCP_CONN_STATE_SYNC_RXD_PASSIVE:
case NET_TCP_CONN_STATE_SYNC_RXD_ACTIVE:
case NET_TCP_CONN_STATE_SYNC_TXD:
case NET_TCP_CONN_STATE_CONN:
case NET_TCP_CONN_STATE_FIN_WAIT_1:
case NET_TCP_CONN_STATE_FIN_WAIT_2:
case NET_TCP_CONN_STATE_CLOSING:
case NET_TCP_CONN_STATE_TIME_WAIT:
case NET_TCP_CONN_STATE_CLOSE_WAIT:
case NET_TCP_CONN_STATE_LAST_ACK:
case NET_TCP_CONN_STATE_CLOSING_DATA_AVAIL:
break;
case NET_TCP_CONN_STATE_NONE:
case NET_TCP_CONN_STATE_FREE: /* MUST NOT re-close TCP conn if already .. */
case NET_TCP_CONN_STATE_CLOSED: /* .. free/closed (see Note #4). */
default:
return; /* Prevent 'break NOT reachable' warning. */
}
/* ---------------- CLOSE CONN(S) ----------------- */
NetConn_CloseFromTransport(pconn->ID_Conn, close_conn_app);
pconn->ID_Conn = NET_CONN_ID_NONE; /* Clr TCP conn's net conn id. */
/* ---------------- FREE TCP CONN ----------------- */
free_code = (NET_TCP_FREE_CODE)close_code; /* See Note #3. */
NetTCP_ConnFreeHandler(pconn, free_code);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCloseTimeout()
*
* Description : Close a TCP connection on timeout.
*
* Argument(s) : pconn_timeout Pointer to a TCP connection (see Note #1b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_ConnReqClose(),
* various NetTCP_RxPktConnHandler() functions.
*
* Note(s) : (1) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (2) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) ... :
*
* (A) TCP connection timeout timer ('TimeoutTmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared in NetTCP_ConnFreeTmr() via NetTCP_ConnClose(),
* NetTCP_ConnCloseHandler().
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_TIMEOUT
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnCloseTimeout (void *pconn_timeout)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CLOSE_CODE close_code;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #1b2A. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* ---------------- VALIDATE PTR ------------------ */
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
/* ---------------- VALIDATE TYPE ----------------- */
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
#endif
/* ---------------- CLOSE TCP CONN ---------------- */
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_TIMEOUT); /* See Note #2b1. */
if (pconn->ConnCloseTimeoutFaultFlag != DEF_NO) { /* If TCP conn timeout fault, ... */
/* ... fault-close TCP conn. */
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
} else { /* Else close TCP conn. */
NetTCP_ConnCloseHandler((NET_TCP_CONN *)pconn,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnClosingTimeoutDataAvail()
*
* Description : (1) Handle closing TCP connection with available application data :
*
* (a) If TCP connection's application receive queue is now empty,
* close the TCP connection
* (b) If TCP connection's application receive queue is still NOT empty
* after the time-wait timeout, set the user connection timeout
*
* See also 'NetTCP_RxPktConnHandlerFinWait1() Note #2f5A2b',
* 'NetTCP_RxPktConnHandlerFinWait2() Note #2f5B2',
* & 'NetTCP_RxPktConnHandlerClosing() Note #2d2B2a1B2'.
*
*
* Argument(s) : pconn_timeout Pointer to a TCP connection (see Note #2b).
*
* Return(s) : none.
*
* Caller(s) : Referenced in NetTCP_RxPktConnHandlerFinWait1(),
* NetTCP_RxPktConnHandlerFinWait2(),
* NetTCP_RxPktConnHandlerClosing().
*
* Note(s) : (2) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]'
* type functions -- even though network timer API functions cast expiration functions
* to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]').
*
* (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a
* pointer to an object ... may be converted to a pointer to a different object
* ... [but] if the resulting pointer is not correctly aligned ... the behavior
* is undefined".
*
* And since compilers may NOT correctly convert 'void' pointers to non-'void'
* pointer arguments, network timer expiration functions MUST avoid incorrect
* pointer conversion behavior between 'void' pointer parameters & non-'void'
* pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'.
*
* (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted
* to or from a pointer to any ... object ... A pointer to any ... object ...
* may be converted to a pointer to void and back again; the result shall
* compare equal to the original pointer".
*
* (b) Therefore, to correctly convert 'void' pointer objects back to appropriate
* network object pointer objects, network timer expiration functions MUST :
*
* (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ...
* (2) Explicitly cast 'void' pointer arguments to specific object pointers; ...
* (A) ... in this case, a 'NET_TCP_CONN' pointer.
*
* See also 'net_tmr.c NetTmr_Get() Note #3'.
*
* (3) This function is a network timer expiration function :
*
* (a) (1) For the following connection timer(s) ... :
*
* (A) TCP connection timeout timer ('TimeoutTmr')
*
* (2) (A) Clear the timer pointer; ...
* (1) Cleared in NetTCP_ConnFreeTmr() via NetTCP_ConnCloseHandler(),
* NetTCP_ConnClose(); or
* (2) Reset by NetTmr_Get().
*
* (B) but do NOT re-free the timer.
*
* (b) Do NOT set the following close timer flag(s) :
*
* (1) NET_TCP_CONN_CLOSE_TMR_TIMEOUT
*
* (4) RFC #793, Section 3.9 'Event Processing : USER TIMEOUT : USER TIMEOUT' states that
* "for any state if the user timeout expires, flush all queues, signal the user
* 'error : connection aborted due to user timeout' ... [and] enter the CLOSED state".
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnClosingTimeoutDataAvail (void *pconn_timeout)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
NET_TCP_CONN *pconn;
NET_TCP_CLOSE_CODE close_code;
CPU_BOOLEAN data_avail;
NET_TCP_TIMEOUT_SEC timeout_sec;
NET_TMR_TICK timeout_tick;
NET_ERR err;
pconn = (NET_TCP_CONN *)pconn_timeout; /* See Note #2b2A. */
close_code = NET_TCP_CONN_CLOSE_ALL;
DEF_BIT_CLR(close_code, NET_TCP_CONN_CLOSE_TMR_TIMEOUT); /* See Note #3b1. */
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)
/* ---------------- VALIDATE PTR ------------------ */
if (pconn == (NET_TCP_CONN *)0) {
NET_CTR_ERR_INC(NetTCP_ErrNullPtrCtr);
return;
}
/* ---------------- VALIDATE TYPE ----------------- */
if (pconn->Type != NET_TCP_TYPE_CONN) {
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
#endif
/* Closing data avail for half-closed conns ONLY. */
data_avail = ((pconn->ConnCloseCode != NET_CONN_CLOSE_HALF ) ||
((pconn->RxQ_State == NET_TCP_RX_Q_STATE_CONN_CLOSED) &&
(pconn->RxQ_App_Head == (NET_BUF *)0))) ? DEF_NO : DEF_YES;
if (data_avail != DEF_YES) { /* If NO app data avail, ... */
/* ... close TCP conn (see Note #1a). */
NetTCP_ConnCloseHandler((NET_TCP_CONN *)pconn,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
} else { /* Else reset user tmr (see Notes #1b & #4). */
timeout_sec = pconn->TimeoutUser_sec;
timeout_tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC;
pconn->TimeoutTmr = NetTmr_Get((void *) pconn,
(CPU_FNCT_PTR) NetTCP_ConnCloseTimeout,
(NET_TMR_TICK) timeout_tick,
(CPU_INT16U ) NET_TMR_FLAG_NONE,
(NET_ERR *)&err);
if (err != NET_TMR_ERR_NONE) {
NetTCP_ConnClose((NET_TCP_CONN *)pconn,
(NET_BUF_HDR *)0,
(CPU_BOOLEAN )pconn->ConnCloseAppFlag,
(NET_TCP_CLOSE_CODE)close_code);
return;
}
pconn->ConnCloseAppFlag = DEF_YES;
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnFreeHandler()
*
* Description : (1) Free a TCP connection :
*
* (a) Free TCP connection timers
* (b) Free TCP connection packet buffer queues
* (c) Clear TCP connection controls
* (d) Free TCP connection back to TCP connection pool
* (e) Update TCP connection pool statistics
*
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnFree(),
* NetTCP_ConnClose().
*
* free_code Select which free action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_FREE_TMR_NONE Free NO timers.
* NET_TCP_CONN_FREE_TMR_ALL Free ALL timers.
*
* NET_TCP_CONN_FREE_TMR_TX_IDLE Free transmit idle timer.
* NET_TCP_CONN_FREE_TMR_TX_SILLY_WIN Free transmit silly window persist timer.
* NET_TCP_CONN_FREE_TMR_TX_ZERO_WIN Free transmit zero window persist timer.
* NET_TCP_CONN_FREE_TMR_TX_ACK_DLY Free transmit acknowledgement delay timer.
* NET_TCP_CONN_FREE_TMR_RE_TX Free re-transmit timer.
* NET_TCP_CONN_FREE_TMR_KEEP_ALIVE Free connection keep-alive timer.
* NET_TCP_CONN_FREE_TMR_TIMEOUT Free connection timer.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnFree(),
* NetTCP_ConnClose().
*
* Note(s) : (2) ALL network resources linked to the TCP connection MUST be freed PRIOR to TCP connection
* free or discard so that no network resources are lost.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnFreeHandler (NET_TCP_CONN *pconn,
NET_TCP_FREE_CODE free_code)
{
#if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \
(NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \
(CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL))
CPU_SR cpu_sr;
#endif
CPU_BOOLEAN discard;
NET_ERR err;
#if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE TYPE ----------------- */
if (pconn->Type != NET_TCP_TYPE_CONN) {
NetTCP_ConnDiscard(pconn);
NET_CTR_ERR_INC(NetTCP_ErrConnInvalidTypeCtr);
return;
}
#endif
/* -------------- FREE TCP CONN TMRs -------------- */
NetTCP_ConnFreeTmr(pconn, free_code);
/* -------------- FREE TCP CONN Q's --------------- */
NetTCP_ConnFreeBufQ(&pconn->RxQ_Transport_Head, &pconn->RxQ_Transport_Tail);
NetTCP_ConnFreeBufQ(&pconn->RxQ_App_Head , &pconn->RxQ_App_Tail );
NetTCP_ConnFreeBufQ(&pconn->TxQ_Head , &pconn->TxQ_Tail );
NetTCP_ConnFreeBufQ(&pconn->ReTxQ_Head , &pconn->ReTxQ_Tail );
discard = DEF_NO;
NetOS_TCP_RxQ_Clr(pconn->ID, &err); /* Clr TCP conn rx Q. */
if (err != NET_TCP_ERR_NONE) { /* If TCP conn rx Q NOT clr'd, ... */
discard = DEF_YES; /* ... discard TCP conn (see Note #2b). */
}
NetOS_TCP_RxQ_Abort(pconn->ID, &err); /* Abort wait on TCP conn rx Q. */
NetOS_TCP_TxQ_Clr(pconn->ID, &err); /* Clr TCP conn tx Q. */
if (err != NET_TCP_ERR_NONE) { /* If TCP conn tx Q NOT clr'd, ... */
discard = DEF_YES; /* ... discard TCP conn (see Note #2b). */
}
NetOS_TCP_TxQ_Abort(pconn->ID, &err); /* Abort wait on TCP conn tx Q. */
/* ---------- DISCARD TCP CONN ON ERR(S) ---------- */
if (discard != DEF_NO) { /* On TCP conn free err(s), ... */
NetTCP_ConnDiscard(pconn); /* ... discard TCP conn (see Note #2a). */
return;
}
/* ----------------- CLR TCP CONN ----------------- */
pconn->ConnState = NET_TCP_CONN_STATE_FREE; /* Set TCP conn as freed/NOT used. */
DEF_BIT_CLR(pconn->Flags, NET_TCP_FLAG_USED);
#if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED)
NetTCP_ConnClr(pconn);
#endif
/* ---------------- FREE TCP CONN ----------------- */
pconn->NextPtr = (void *)NetTCP_ConnPoolPtr;
NetTCP_ConnPoolPtr = (NET_TCP_CONN *)pconn;
/* ---------- UPDATE TCP CONN POOL STATS ---------- */
NetStat_PoolEntryUsedDec(&NetTCP_ConnPoolStat, &err);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnFreeTmr()
*
* Description : Clear TCP connection's timers.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_ConnFreeHandler(),
* various NetTCP_ConnHandler() functions.
*
* free_code Select which free action(s) to perform; bit-field flags logically OR'd :
*
* NET_TCP_CONN_FREE_TMR_NONE Free NO timers.
* NET_TCP_CONN_FREE_TMR_ALL Free ALL timers.
*
* NET_TCP_CONN_FREE_TMR_TX_IDLE Free transmit idle timer.
* NET_TCP_CONN_FREE_TMR_TX_SILLY_WIN Free transmit silly window persist timer.
* NET_TCP_CONN_FREE_TMR_TX_ZERO_WIN Free transmit zero window persist timer.
* NET_TCP_CONN_FREE_TMR_TX_ACK_DLY Free transmit acknowledgement delay timer.
* NET_TCP_CONN_FREE_TMR_RE_TX Free re-transmit timer.
* NET_TCP_CONN_FREE_TMR_KEEP_ALIVE Free connection keep-alive timer.
* NET_TCP_CONN_FREE_TMR_TIMEOUT Free connection timer.
*
* See also 'TCP CONNECTION CLOSE/FREE CODE DEFINES'.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnFreeHandler(),
* various NetTCP_ConnHandler() functions.
*
* Note(s) : none.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnFreeTmr (NET_TCP_CONN *pconn,
NET_TCP_FREE_CODE free_code)
{
CPU_BOOLEAN free_tmr;
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_TX_IDLE);
if (free_tmr == DEF_YES) {
if (pconn->TxQ_IdleTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->TxQ_IdleTmr);
pconn->TxQ_IdleTmr = (NET_TMR *)0;
}
}
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_TX_SILLY_WIN);
if (free_tmr == DEF_YES) {
if (pconn->TxQ_SillyWinTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->TxQ_SillyWinTmr);
pconn->TxQ_SillyWinTmr = (NET_TMR *)0;
}
}
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_TX_ZERO_WIN);
if (free_tmr == DEF_YES) {
if (pconn->TxQ_ZeroWinTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->TxQ_ZeroWinTmr);
pconn->TxQ_ZeroWinTmr = (NET_TMR *)0;
}
}
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_TX_ACK_DLY);
if (free_tmr == DEF_YES) {
if (pconn->TxAckDlyTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->TxAckDlyTmr);
pconn->TxAckDlyTmr = (NET_TMR *)0;
}
}
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_RE_TX);
if (free_tmr == DEF_YES) {
if (pconn->ReTxQ_Tmr != (NET_TMR *)0) {
NetTmr_Free(pconn->ReTxQ_Tmr);
pconn->ReTxQ_Tmr = (NET_TMR *)0;
}
}
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_KEEP_ALIVE);
if (free_tmr == DEF_YES) {
if (pconn->KeepAliveTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->KeepAliveTmr);
pconn->KeepAliveTmr = (NET_TMR *)0;
}
}
free_tmr = DEF_BIT_IS_SET(free_code, NET_TCP_CONN_FREE_TMR_TIMEOUT);
if (free_tmr == DEF_YES) {
if (pconn->TimeoutTmr != (NET_TMR *)0) {
NetTmr_Free(pconn->TimeoutTmr);
pconn->TimeoutTmr = (NET_TMR *)0;
}
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnFreeBufQ()
*
* Description : Free a TCP connection's buffer queue.
*
* Argument(s) : pbuf_q_head Pointer to a TCP connection buffer queue's head pointer.
*
* pbuf_q_tail Pointer to a TCP connection buffer queue's tail pointer.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerRxQ_Sync(),
* NetTCP_TxConnSync(),
* NetTCP_ConnFreeHandler().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_ConnFreeBufQ (NET_BUF **pbuf_q_head,
NET_BUF **pbuf_q_tail)
{
NET_BUF *pbuf_q;
/* Free buf Q. */
pbuf_q = *pbuf_q_head;
NetBuf_FreeBufQ_PrimList((NET_BUF *)pbuf_q,
(NET_CTR *)0);
/* Clr buf Q ptrs to NULL. */
*pbuf_q_head = (NET_BUF *)0;
*pbuf_q_tail = (NET_BUF *)0;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnClr()
*
* Description : Clear TCP connection controls.
*
* Argument(s) : pconn Pointer to a TCP connection.
* ----- Argument validated in NetTCP_Init(),
* NetTCP_ConnGet(),
* NetTCP_ConnFreeHandler().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_Init(),
* NetTCP_ConnGet(),
* NetTCP_ConnFreeHandler().
*
* Note(s) : (1) Configured in NetTCP_ConnCfg() :
*
* (a) Configured in NetTCP_ConnCfgMaxSegSize().
*
* (b) Configured in NetTCP_RxConnWinSizeCfg() :
* (1) Configured in NetTCP_RxConnWinSizeCfgUpdateTh().
*
* (c) Configured in NetTCP_TxConnWinSizeCfg() :
* (1) Configured in NetTCP_TxConnWinSizeCfgCongCtrl().
* (2) Configured in NetTCP_TxConnWinSizeCfgMinTh().
*
* (d) Initialized in NetTCP_TxConnRTT_RTO_Init().
* (1) Configured in NetTCP_TxConnRTO_CfgMaxTimeout().
*
* (2) See 'NetTCP_RxPktConnHandler() Note #3c'.
*
* (3) (a) See 'net_tcp.h TCP SEGMENT SIZE DEFINES Note #1b1'.
* (b) See 'net_tcp.h TCP SEGMENT SIZE DEFINES Note #1b2'.
*
* (4) See 'net_cfg.h TRANSMISSION CONTROL PROTOCOL LAYER CONFIGURATION Note #2'.
*
* (5) See 'NetTCP_TxConnTxQ() Note #6b2B2'.
*
* (6) See 'net_tcp.h TCP CONGESTION CONTROL DEFINES Note #5b4'.
*
* (7) See 'NetTCP_TxConnWinSizeZeroWinHandler() Note #1b2'.
*
* (8) See 'net_tcp.h TCP CONGESTION CONTROL DEFINES Note #7'.
*
* (9) See 'net_tcp.h TCP CONGESTION CONTROL DEFINES Note #6b'.
*
* (10) See 'NetTCP_TxConnAck() Note #4a4A1'.
*
* (11) See 'NetTCP_ConnCfgReTxMaxTimeout() Note #1'.
*
* (12) See ####
*
* (13) See 'NetTCP_RxPktConnHandlerConn() Note #3a'.
*
* (14) See 'net_tcp.h TCP CONNECTION TIMEOUT DEFINES Note #1b'.
*********************************************************************************************************
*/
/*$PAGE*/
static void NetTCP_ConnClr (NET_TCP_CONN *pconn)
{
NET_TCP_CONN_ID conn_id_tcp;
NET_ERR err;
pconn->NextPtr = (void *)0;
pconn->ID_Conn = NET_CONN_ID_NONE;
pconn->ConnState = NET_TCP_CONN_STATE_FREE;
pconn->ConnCloseCode = NET_CONN_CLOSE_FULL; /* See Note #2. */
pconn->ConnCloseAppFlag = DEF_YES;
pconn->ConnCloseTimeoutFaultFlag = DEF_YES;
pconn->MaxSegSizeLocal = NET_TCP_MAX_SEG_SIZE_DFLT_RX; /* See Note #3a. */
pconn->MaxSegSizeRemote = NET_TCP_MAX_SEG_SIZE_DFLT_TX; /* See Note #3b. */
#if 0 /* See Note #1a. */
pconn->MaxSegSizeConn = NET_TCP_MAX_SEG_SIZE_NONE;
#endif
pconn->RxSeqNbrSync = NET_TCP_SEQ_NBR_NONE;
pconn->RxSeqNbrNext = NET_TCP_SEQ_NBR_NONE;
pconn->RxSeqNbrLast = NET_TCP_SEQ_NBR_NONE;
pconn->RxSeqNbrClose = NET_TCP_SEQ_NBR_NONE;
pconn->RxWinSizeCfgd = NET_TCP_CFG_RX_WIN_SIZE_OCTET; /* See Note #4. */
pconn->RxWinSizeCfgdActualUpdateRem = NET_TCP_WIN_SIZE_NONE;
pconn->RxWinSizeCfgdActual = pconn->RxWinSizeCfgd;
pconn->RxWinSizeCalcd = pconn->RxWinSizeCfgd;
pconn->RxWinSizeActual = pconn->RxWinSizeCfgd;
#if 0 /* See Note #1b1. */
pconn->RxWinSizeUpdateTh = NET_TCP_WIN_SIZE_NONE;
#endif
pconn->RxQ_State = NET_TCP_RX_Q_STATE_CONN_CLOSED;
pconn->RxQ_Transport_Head = (NET_BUF *)0;
pconn->RxQ_Transport_Tail = (NET_BUF *)0;
pconn->RxQ_App_Head = (NET_BUF *)0;
pconn->RxQ_App_Tail = (NET_BUF *)0;
pconn->TxSeqNbrSync = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrNext = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrNextQ = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrUnReTxd = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrUnAckd = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrUnAckdPrev = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrUnAckdAlignDelta = 0;
pconn->TxSeqNbrLast = NET_TCP_SEQ_NBR_NONE;
pconn->TxSeqNbrClose = NET_TCP_SEQ_NBR_NONE;
pconn->TxWinUpdateSeqNbr = NET_TCP_SEQ_NBR_NONE;
pconn->TxWinUpdateAckNbr = NET_TCP_ACK_NBR_NONE;
pconn->TxWinUpdateWinSize = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeCfgd = NET_TCP_CFG_TX_WIN_SIZE_OCTET; /* See Note #4. */
pconn->TxWinSizeCfgdRem = pconn->TxWinSizeCfgd;
pconn->TxWinSizeRemote = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeRemoteMax = pconn->TxWinSizeRemote;
pconn->TxWinSizeRemoteActual = pconn->TxWinSizeRemote;
pconn->TxWinSizeRemoteRem = pconn->TxWinSizeRemote;
pconn->TxWinSizeNagleEn = DEF_ENABLED; /* See Note #5. */
pconn->TxWinSillyWinTimeout_ms = NET_TCP_TX_SILLY_WIN_TIMEOUT_DFLT_MS; /* See Note #6. */
pconn->TxWinZeroWinTimeout_ms = 0; /* See Note #7. */
#if 0 /* See Note #1c. */
pconn->TxWinRxdAckDupCtr = 0;
pconn->TxWinRxdLastSeqNbr = NET_TCP_SEQ_NBR_NONE;
pconn->TxWinRxdLastAckNbr = NET_TCP_ACK_NBR_NONE;
pconn->TxWinRxdLastWinSize = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeSlowStartTh = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeSlowStartThInit = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeCongInit = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeCongCalcdActual = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeCongCalcdCur = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeCongRem = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeAvail = NET_TCP_WIN_SIZE_NONE;
pconn->TxWinSizeMinTh = NET_TCP_WIN_SIZE_NONE;
#endif
/*$PAGE*/
pconn->TxSegReTxTh = NET_TCP_RE_TX_TH_DFLT; /* See Note #8. */
pconn->TxAckDlyTimeout_ms = NET_TCP_CFG_TIMEOUT_CONN_ACK_DLY_MS; /* See Note #9. */
pconn->TxAckDlyTmr = (NET_TMR *)0;
pconn->TxAckDlyCnt = 0;
pconn->TxAckImmedRxdPushEn = DEF_ENABLED; /* See Note #10. */
pconn->TxRTT_RTO_Max_sec = NET_TCP_TX_RTO_MAX_TIMEOUT_DFLT_SEC; /* See Note #11. */
#if 0 /* See Note #1d. */
pconn->TxRTT_Avg_ms_scaled = NET_TCP_TX_RTT_NONE;
pconn->TxRTT_Dev_ms_scaled = NET_TCP_TX_RTT_NONE;
pconn->TxRTT_RTO_ms_scaled = NET_TCP_TX_RTO_NONE;
pconn->TxRTT_RTO_Max_ms_scaled = NET_TCP_TX_RTO_NONE; /* See Note #1d1. */
pconn->TxRTT_Avg_ms = NET_TCP_TX_RTT_NONE;
pconn->TxRTT_Dev_ms = NET_TCP_TX_RTT_NONE;
pconn->TxRTT_RTO_ms = NET_TCP_TX_RTO_NONE;
pconn->TxRTT_RTO_Max_ms = NET_TCP_TX_RTO_NONE; /* See Note #1d1. */
pconn->TxRTT_RTO_sec = NET_TCP_TX_RTO_NONE;
pconn->TxRTT_RTO_tick = NET_TMR_TIME_0S;
pconn->TxRTT_RTO_State = NET_TCP_TX_RTT_RTO_STATE_NONE;
#endif
pconn->TxIP_TOS = NET_IP_TOS_DFLT;
pconn->TxIP_TTL = NET_IP_TTL_DFLT;
pconn->TxIP_Flags = NET_IP_FLAG_NONE;
pconn->TxQ_State = NET_TCP_TX_Q_STATE_CONN_CLOSED;
pconn->TxQ_Head = (NET_BUF *)0;
pconn->TxQ_Tail = (NET_BUF *)0;
pconn->TxQ_IdleTmr = (NET_TMR *)0;
pconn->TxQ_SillyWinTmr = (NET_TMR *)0;
pconn->TxQ_ZeroWinTmr = (NET_TMR *)0;
pconn->ReTxQ_Head = (NET_BUF *)0;
pconn->ReTxQ_Tail = (NET_BUF *)0;
pconn->ReTxQ_Tmr = (NET_TMR *)0;
pconn->KeepAliveTmr = (NET_TMR *)0;
pconn->TimeoutTmr = (NET_TMR *)0;
pconn->TimeoutConn_sec = NET_TCP_CONN_TIMEOUT_CONN_DFLT_SEC; /* See Note #12. */
pconn->TimeoutUser_sec = NET_TCP_CONN_TIMEOUT_USER_DFLT_SEC; /* See Note #13. */
pconn->TimeoutMaxSeg_sec = NET_TCP_CFG_TIMEOUT_CONN_MAX_SEG_SEC; /* See Note #14. */
pconn->Flags = NET_TCP_FLAG_NONE;
NetTCP_ConnCfg(pconn, NET_TCP_CONN_CFG_ALL); /* See Note #1. */
/* -- CFG DFLT TIMEOUT VALS --- */
conn_id_tcp = pconn->ID;
NetOS_TCP_RxQ_TimeoutDflt(conn_id_tcp, &err);
NetOS_TCP_TxQ_TimeoutDflt(conn_id_tcp, &err);
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnCopy()
*
* Description : (1) Copy/clone a TCP connection :
*
* (a) TCP connection state
*
* (b) Receive parameters :
* (1) Receive window size
*
* (c) Transmit parameters :
* (1) Transmit window size
*
* (2) Re-transmit parameters :
* (A) Threshold
* (B) Maximum timeout
*
* (3) IP transmit parameters :
* (A) TOS
* (B) TTL
* (C) IP flags
*
* (d) TCP connection timeout values
*
*
* Argument(s) : pconn_dest Pointer to TCP connection to receive TCP connection copy.
* ---------- Argument validated in NetTCP_RxPktConnHandlerListen().
*
* pconn_src Pointer to TCP connection to copy.
* --------- Argument validated in NetTCP_RxPktConnHandlerListen().
*
* Return(s) : none.
*
* Caller(s) : NetTCP_RxPktConnHandlerListen().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_ConnCopy (NET_TCP_CONN *pconn_dest,
NET_TCP_CONN *pconn_src)
{
pconn_dest->ConnState = pconn_src->ConnState;
pconn_dest->RxWinSizeCfgd = pconn_src->RxWinSizeCfgd;
pconn_dest->TxWinSizeCfgd = pconn_src->TxWinSizeCfgd;
pconn_dest->TxWinSizeNagleEn = pconn_src->TxWinSizeNagleEn;
pconn_dest->TxSegReTxTh = pconn_src->TxSegReTxTh;
pconn_dest->TxAckDlyTimeout_ms = pconn_src->TxAckDlyTimeout_ms;
pconn_dest->TxAckImmedRxdPushEn = pconn_src->TxAckImmedRxdPushEn;
pconn_dest->TxRTT_RTO_Max_sec = pconn_src->TxRTT_RTO_Max_sec;
pconn_dest->TxIP_TOS = pconn_src->TxIP_TOS;
pconn_dest->TxIP_TTL = pconn_src->TxIP_TTL;
pconn_dest->TxIP_Flags = pconn_src->TxIP_Flags;
pconn_dest->TimeoutConn_sec = pconn_src->TimeoutConn_sec;
pconn_dest->TimeoutUser_sec = pconn_src->TimeoutUser_sec;
pconn_dest->TimeoutMaxSeg_sec = pconn_src->TimeoutMaxSeg_sec;
}
/*$PAGE*/
/*
*********************************************************************************************************
* NetTCP_ConnDiscard()
*
* Description : (1) Discard an invalid/corrupted TCP connection :
*
* (a) Discard TCP connection from available TCP connection pool See Note #2
* (b) Update TCP connection pool statistics
*
* (2) Assumes TCP connection is invalid/corrupt & MUST be removed. TCP connection removed
* simply by NOT returning the TCP connection back to the TCP connection pool.
*
*
* Argument(s) : pconn Pointer to an invalid/corrupted TCP connection.
*
* Return(s) : none.
*
* Caller(s) : NetTCP_ConnGet(),
* NetTCP_ConnFree().
*
* Note(s) : none.
*********************************************************************************************************
*/
static void NetTCP_ConnDiscard (NET_TCP_CONN *pconn)
{
NET_ERR stat_err;
/* ----------------- DISCARD TCP CONN ----------------- */
(void)&pconn; /* Prevent compiler warning (see Note #2). */
/* --------------- UPDATE DISCARD STATS --------------- */
NetStat_PoolEntryLostInc(&NetTCP_ConnPoolStat, &stat_err);
}
/*$PAGE*/
/*
*********************************************************************************************************
* MODULE END
*
* Note(s) : (1) See 'MODULE Note #1' & 'net_tcp.h MODULE Note #1'.
*********************************************************************************************************
*/
#endif /* End of TCP module include (see Note #1). */