changer/OS/uc/tcpip/Source/net_tcp.c
Dmitriy 5fe1e5d358 первый коммит
первый коммит
2021-02-08 21:10:39 +03:00

25163 lines
1.3 MiB
Raw Permalink 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). */