mirror of
https://github.com/dimoniche/changer.git
synced 2026-01-30 01:03:30 +03:00
25163 lines
1.3 MiB
25163 lines
1.3 MiB
/*
|
||
*********************************************************************************************************
|
||
* 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). */
|
||
|