/* ********************************************************************************************************* * 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 ICMP LAYER * (INTERNET CONTROL MESSAGE PROTOCOL) * * Filename : net_icmp.c * Version : V1.89 * Programmer(s) : ITJ ********************************************************************************************************* * Note(s) : (1) Supports Internet Control Message Protocol as described in RFC #792 with the following * restrictions/constraints : * * (a) Does NOT support IP forwarding/routing RFC #1122, Section 3.3.1 * * (b) Does NOT support IP multicasting RFC #1122, Section 3.3.7 * * (c) Does NOT support ICMP Address Mask Agent/Server RFC #1122, Section 3.2.2.9 ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #define NET_ICMP_MODULE #include /*$PAGE*/ /* ********************************************************************************************************* * LOCAL DEFINES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL CONSTANTS ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL DATA TYPES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL TABLES ********************************************************************************************************* */ /* ********************************************************************************************************* * LOCAL GLOBAL VARIABLES ********************************************************************************************************* */ /*$PAGE*/ /* ********************************************************************************************************* * LOCAL FUNCTION PROTOTYPES ********************************************************************************************************* */ /* ------------------- RX FNCTS ------------------- */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static void NetICMP_RxPktValidateBuf (NET_BUF_HDR *pbuf_hdr, NET_ERR *perr); #endif static void NetICMP_RxPktValidate (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, NET_ICMP_HDR *picmp_hdr, NET_ERR *perr); static void NetICMP_RxPktFree (NET_BUF *pbuf); static void NetICMP_RxPktDiscard (NET_BUF *pbuf, NET_ERR *perr); /* ------------------- TX FNCTS ------------------- */ static void NetICMP_TxMsgErrValidate (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, NET_IP_HDR *pip_hdr, CPU_INT08U type, CPU_INT08U code, CPU_INT08U ptr, NET_ERR *perr); static void NetICMP_TxMsgReqValidate (CPU_INT08U type, CPU_INT08U code, NET_ERR *perr); static void NetICMP_TxMsgReply (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, NET_ICMP_HDR *picmp_hdr, NET_ERR *perr); static void NetICMP_TxPktFree (NET_BUF *pbuf); static void NetICMP_TxPktDiscard (NET_BUF *pbuf, NET_ERR *perr); /* ---------------- HANDLER FNCTS ----------------- */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuench (NET_BUF *pbuf); static void NetICMP_HandlerTxSrcQuenchClrList(void); static void NetICMP_HandlerTxSrcQuenchClr (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench); static NET_ICMP_TX_SRC_QUENCH *NetICMP_HandlerTxSrcQuenchGet (NET_ERR *perr); static void NetICMP_HandlerTxSrcQuenchFree (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench); static void NetICMP_HandlerTxSrcQuenchRemove (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench); static void NetICMP_HandlerTxSrcQuenchInsert (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench); static void NetICMP_HandlerTxSrcQuenchUnlink (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench); #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchDiscard(NET_ICMP_TX_SRC_QUENCH *ptx_src_quench); #endif #endif /* ********************************************************************************************************* * LOCAL CONFIGURATION ERRORS ********************************************************************************************************* */ /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_Init() * * Description : (1) Initialize Internet Control Message Protocol Layer : * * (a) Initialize ICMP transmit source quench : * (1) Initialize ICMP transmit source quench pool * (2) Initialize ICMP transmit source quench table * (3) Initialize ICMP transmit source quench list pointers * * (b) Initialize ICMP statistics & error counters * * * Argument(s) : none. * * 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) ICMP transmit source quench pool MUST be initialized PRIOR to initializing the pool * with pointers to ICMP transmit source quench entries. ********************************************************************************************************* */ void NetICMP_Init (void) { #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) NET_ICMP_TX_SRC_QUENCH *ptx_src_quench_tbl; NET_ICMP_SRC_QUENCH_QTY i; NET_ERR err; /* -------- INIT ICMP TX SRC QUENCH POOL/STATS -------- */ NetICMP_TxSrcQuenchPoolPtr = (NET_ICMP_TX_SRC_QUENCH *)0; /* Init-clr ICMP tx src quench pool (see Note #2). */ NetStat_PoolInit((NET_STAT_POOL *)&NetICMP_TxSrcQuenchPoolStat, (NET_STAT_POOL_QTY) NET_ICMP_CFG_TX_SRC_QUENCH_SIZE, (NET_ERR *)&err); /* ----------- INIT ICMP TX SRC QUENCH TBL ------------ */ ptx_src_quench_tbl = &NetICMP_TxSrcQuenchTbl[0]; for (i = 0; i < NET_ICMP_CFG_TX_SRC_QUENCH_SIZE; i++) { /* Init each ICMP tx src quench type--NEVER modify. */ ptx_src_quench_tbl->Type = NET_ICMP_TYPE_TX_SRC_QUENCH; ptx_src_quench_tbl->Flags = NET_ICMP_FLAG_NONE; /* Init each ICMP tx src quench as NOT used. */ #if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED) NetICMP_HandlerTxSrcQuenchClr(ptx_src_quench_tbl); #endif /* Free each entry to pool (see Note #2). */ ptx_src_quench_tbl->NextPtr = (void *)NetICMP_TxSrcQuenchPoolPtr; NetICMP_TxSrcQuenchPoolPtr = ptx_src_quench_tbl; ptx_src_quench_tbl++; } /* -------- INIT ICMP TX SRC QUENCH LIST PTRS --------- */ NetICMP_TxSrcQuenchListHead = (NET_ICMP_TX_SRC_QUENCH *)0; NetICMP_TxSrcQuenchListTail = (NET_ICMP_TX_SRC_QUENCH *)0; #endif /*$PAGE*/ /* ------------ INIT ICMP STAT & ERR CTRS ------------- */ NetICMP_TxSeqNbrCtr = 0; #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) NetICMP_StatRxMsgCtr = 0; NetICMP_StatRxMsgProcessedCtr = 0; NetICMP_StatRxMsgErrProcessedCtr = 0; NetICMP_StatRxMsgReqProcessedCtr = 0; NetICMP_StatRxMsgReplyProcessedCtr = 0; NetICMP_StatTxMsgCtr = 0; NetICMP_StatTxMsgErrCtr = 0; NetICMP_StatTxMsgReqCtr = 0; NetICMP_StatTxMsgReplyCtr = 0; #endif #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) NetICMP_ErrRxHdrTypeCtr = 0; NetICMP_ErrRxHdrCodeCtr = 0; NetICMP_ErrRxHdrMsgLenCtr = 0; NetICMP_ErrRxHdrPtrCtr = 0; NetICMP_ErrRxHdrChkSumCtr = 0; NetICMP_ErrRxBroadcastCtr = 0; NetICMP_ErrRxPktDiscardedCtr = 0; NetICMP_ErrTxInvalidLenCtr = 0; NetICMP_ErrTxHdrTypeCtr = 0; NetICMP_ErrTxHdrCodeCtr = 0; NetICMP_ErrTxPktDiscardedCtr = 0; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) NetICMP_ErrNullPtrCtr = 0; NetICMP_ErrNotUsedCtr = 0; NetICMP_ErrInvalidTypeCtr = 0; NetICMP_ErrRxInvalidBufIxCtr = 0; NetICMP_ErrRxHdrDataLenCtr = 0; NetICMP_ErrTxInvalidBufIxCtr = 0; NetICMP_ErrTxHdrPtrCtr = 0; #endif #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) NetICMP_ErrNoneAvailCtr = 0; #endif #endif } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_CfgTxSrcQuenchTh() * * Description : Configure ICMP transmit source quench entry's access-transmit threshold. * * Argument(s) : th Desired number of received IP packets from a specific IP source host that trips * the transmission of an additional ICMP Source Quench Error Message. * * Return(s) : DEF_OK, ICMP transmit source quench threshold configured. * * Caller(s) : Net_InitDflt(), * Application. * * This function is a network protocol suite application interface (API) function & MAY be * called by application function(s). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) CPU_BOOLEAN NetICMP_CfgTxSrcQuenchTh (CPU_INT16U th) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif #if (NET_ICMP_TX_SRC_QUENCH_TH_MIN > DEF_INT_16U_MIN_VAL) if (th < NET_ICMP_TX_SRC_QUENCH_TH_MIN) { th = NET_ICMP_TX_SRC_QUENCH_TH_MIN; } #endif #if (NET_ICMP_TX_SRC_QUENCH_TH_MAX < DEF_INT_16U_MAX_VAL) if (th > NET_ICMP_TX_SRC_QUENCH_TH_MAX) { th = NET_ICMP_TX_SRC_QUENCH_TH_MAX; } #endif CPU_CRITICAL_ENTER(); NetICMP_TxSrcQuenchTxTh_nbr = th; CPU_CRITICAL_EXIT(); return (DEF_OK); } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_Rx() * * Description : (1) Process received messages : * * (a) Validate ICMP packet * (b) Demultiplex ICMP message * (c) Free ICMP packet * (d) Update receive statistics * * (2) Although ICMP data units are typically referred to as 'messages' (see RFC #792, Section * 'Introduction'), the term 'ICMP packet' (see RFC #1983, 'packet') is used for ICMP * Receive until the packet is validated as an ICMP message. * * * Argument(s) : pbuf Pointer to network buffer that received ICMP packet. * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE ICMP message successfully received & processed. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * ---- RETURNED BY NetICMP_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) NetICMP_Rx() blocked until network initialization completes. * * (4) #### ICMP Receive Error/Reply Messages NOT yet implemented : * * (a) Define "User Process" to report ICMP Error Messages to Transport &/or Application Layers. * * (b) Define procedure to demultiplex & enqueue ICMP Reply Messages to Application. * * (1) MUST implement mechanism to de-queue ICMP message data from single, complete * datagram packet buffers or multiple, fragmented packet buffers. ********************************************************************************************************* */ /*$PAGE*/ void NetICMP_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 #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) NET_CTR *pctr; #endif NET_BUF_HDR *pbuf_hdr; NET_ICMP_HDR *picmp_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) { NetICMP_RxPktDiscard(pbuf, perr); NET_CTR_ERR_INC(NetICMP_ErrNullPtrCtr); return; } #endif NET_CTR_STAT_INC(NetICMP_StatRxMsgCtr); /* ----------------- VALIDATE ICMP PKT ---------------- */ pbuf_hdr = &pbuf->Hdr; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) NetICMP_RxPktValidateBuf(pbuf_hdr, perr); /* Validate rx'd buf. */ switch (*perr) { case NET_ICMP_ERR_NONE: break; case NET_ERR_INVALID_PROTOCOL: case NET_BUF_ERR_INVALID_IX: default: NetICMP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } #endif picmp_hdr = (NET_ICMP_HDR *)&pbuf->Data[pbuf_hdr->ICMP_MsgIx]; NetICMP_RxPktValidate(pbuf, pbuf_hdr, picmp_hdr, perr); /* Validate rx'd pkt. */ /*$PAGE*/ /* ------------------ DEMUX ICMP MSG ------------------ */ switch (*perr) { case NET_ICMP_ERR_MSG_TYPE_ERR: /* See Note #4a. */ #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) pctr = &NetICMP_StatRxMsgErrProcessedCtr; #endif break; case NET_ICMP_ERR_MSG_TYPE_REQ: NetICMP_TxMsgReply(pbuf, pbuf_hdr, picmp_hdr, perr); #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) pctr = &NetICMP_StatRxMsgReqProcessedCtr; #endif break; case NET_ICMP_ERR_MSG_TYPE_REPLY: /* See Note #4b. */ #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) pctr = &NetICMP_StatRxMsgReplyProcessedCtr; #endif break; case NET_ICMP_ERR_INVALID_TYPE: case NET_ICMP_ERR_INVALID_CODE: case NET_ICMP_ERR_INVALID_PTR: case NET_ICMP_ERR_INVALID_LEN: case NET_ICMP_ERR_INVALID_LEN_DATA: case NET_ICMP_ERR_INVALID_CHK_SUM: default: NetICMP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } /* --------- FREE ICMP PKT / UPDATE RX STATS ---------- */ switch (*perr) { /* Chk err from NetICMP_TxMsg???(). */ case NET_ICMP_ERR_NONE: NetICMP_RxPktFree(pbuf); NET_CTR_STAT_INC(NetICMP_StatRxMsgProcessedCtr); NET_CTR_STAT_INC(*pctr); break; default: NetICMP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_TxMsgErr() * * Description : (1) Transmit ICMP Error Message in response to received packet with one or more errors : * * (a) Validate ICMP Error Message * * (b) Get buffer for ICMP Error Message : * * (1) Calculate ICMP Error Message buffer size * (2) Copy received packet's IP header & data into ICMP Error Message * (3) Initialize ICMP Error Message buffer controls * * (c) Prepare ICMP Error Message : * * (1) Type See Note #1cA * (2) Code See Note #1cA * (3) Pointer * (4) Unused * (5) Check-Sum * * (A) See 'net_icmp.h ICMP MESSAGE TYPES & CODES Notes #2 & #3' for supported * ICMP message types & codes. * * (d) Transmit ICMP Error Message * * (1) RFC #1122, Section 3.2.2 specifies that "an ICMP error message SHOULD be sent * with normal (i.e., zero) TOS bits". RFC #1349, Section 5.1 confirms that "an * ICMP error message is always sent with the default TOS (0000)". * * (e) Free ICMP Error Message buffer * * (f) Update transmit statistics * * * Argument(s) : pbuf Pointer to network buffer that received a packet with error(s). * * type ICMP Error Message type (see Note #1cA) : * * NET_ICMP_MSG_TYPE_DEST_UNREACH * NET_ICMP_MSG_TYPE_SRC_QUENCH * NET_ICMP_MSG_TYPE_TIME_EXCEED * NET_ICMP_MSG_TYPE_PARAM_PROB * * code ICMP Error Message code (see Note #1cA). * * ptr Pointer to received packet's ICMP error (optional). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE ICMP Error Message successfully transmitted. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * --- RETURNED BY NetICMP_TxPktDiscard() : --- * NET_ERR_TX Transmit error; packet discarded. * * Return(s) : none. * * Caller(s) : various. * * This function is an INTERNAL network protocol suite function & MUST NOT be called by * application function(s). * * Note(s) : (2) NetICMP_TxMsgErr() blocked until network initialization completes. * * (3) (a) The following IP header fields MUST be decoded &/or converted from network-order to host- * order BEFORE any ICMP Error Messages are transmitted (see 'net_ip.c NetIP_RxPktValidate() * Note #3') : * * (1) Header Length * (2) Total Length * (3) Source Address * (4) Destination Address * * (b) The following IP header fields were NOT previously decoded &/or converted from network- * order to host-order & are NOT available : * * (1) IP Data Length * * (4) Default case already invalidated in NetICMP_TxMsgErrValidate(). However, the default * case is included as an extra precaution in case 'type' is incorrectly modified. * * (5) Assumes network buffer's protocol header size is large enough to accomodate ICMP header * size (see 'net_buf.h NETWORK BUFFER INDEX & SIZE DEFINES Note #1'). *$PAGE* * (6) Some buffer controls were previously initialized in NetBuf_Get() when the buffer * was allocated earlier in this function. These buffer controls do NOT need to be * re-initialized but are shown for completeness. * * (7) (a) ICMP message Check-Sum MUST be calculated AFTER the entire ICMP message 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) ICMP message Check-Sum field MUST be cleared to '0' BEFORE the ICMP message Check-Sum * is calculated (see RFC #792, Sections 'Destination Unreachable Message : Checksum', * 'Time Exceeded Message : Checksum', 'Source Quench Message : Checksum', & 'Parameter * Problem Message : Checksum'). * * (c) The ICMP message Check-Sum field is returned in network-order & MUST NOT be re-converted * back to host-order (see 'net_util.c NetUtil_16BitOnesCplChkSumHdrCalc() Note #3b'). * * (8) Network buffer already freed by lower layer; only increment error counter. ********************************************************************************************************* */ void NetICMP_TxMsgErr (NET_BUF *pbuf, CPU_INT08U type, CPU_INT08U code, CPU_INT08U ptr, 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_IP_HDR *pip_hdr; NET_BUF *pmsg_err; NET_BUF_HDR *pmsg_err_hdr; NET_ICMP_HDR_ERR *picmp_hdr_err; NET_ICMP_HDR_PARAM_PROB *picmp_hdr_param_prob; CPU_INT16U msg_size_hdr; CPU_INT16U msg_size_data_ip; CPU_INT16U msg_size_data; CPU_INT16U msg_size_tot; CPU_INT16U msg_ix; CPU_INT16U msg_ix_data; CPU_INT16U msg_chk_sum; NET_ERR err; #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit tx (see Note #2). */ *perr = NET_ERR_INIT_INCOMPLETE; return; } #endif #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE PTR ------------------- */ if (pbuf == (NET_BUF *)0) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); NET_CTR_ERR_INC(NetICMP_ErrNullPtrCtr); return; } #endif /* ------------- VALIDATE ICMP TX ERR MSG ------------- */ pbuf_hdr = &pbuf->Hdr; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (pbuf_hdr->IP_HdrIx == NET_BUF_IX_NONE) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); NET_CTR_ERR_INC(NetICMP_ErrRxInvalidBufIxCtr); return; } #endif pip_hdr = (NET_IP_HDR *)&pbuf->Data[pbuf_hdr->IP_HdrIx]; NetICMP_TxMsgErrValidate(pbuf, pbuf_hdr, pip_hdr, type, code, ptr, &err); if (err != NET_ICMP_ERR_NONE) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); return; } /*$PAGE*/ /* --------------- GET ICMP ERR MSG BUF --------------- */ /* Calc err msg buf size. */ switch (type) { case NET_ICMP_MSG_TYPE_DEST_UNREACH: msg_size_hdr = NET_ICMP_HDR_SIZE_DEST_UNREACH; break; case NET_ICMP_MSG_TYPE_SRC_QUENCH: msg_size_hdr = NET_ICMP_HDR_SIZE_SRC_QUENCH; break; case NET_ICMP_MSG_TYPE_TIME_EXCEED: msg_size_hdr = NET_ICMP_HDR_SIZE_TIME_EXCEED; break; case NET_ICMP_MSG_TYPE_PARAM_PROB: msg_size_hdr = NET_ICMP_HDR_SIZE_PARAM_PROB; break; default: /* See Note #4. */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } if (pbuf_hdr->IP_TotLen >= pbuf_hdr->IP_HdrLen) { /* If IP tot len > IP hdr len & ... */ msg_size_data_ip = pbuf_hdr->IP_TotLen - pbuf_hdr->IP_HdrLen; /* Calc IP data len (see Note #3b1). */ if (msg_size_data_ip >= NET_ICMP_MSG_ERR_DATA_SIZE_MIN_OCTETS) { /* ... ip data >= min ICMP data len, ... */ /* ... get max ICMP err msg len. */ msg_size_data = pbuf_hdr->IP_HdrLen + NET_ICMP_MSG_ERR_DATA_SIZE_MIN_OCTETS; } else { /* Else get max IP tot len. */ msg_size_data = pbuf_hdr->IP_TotLen; } } else { /* Else get max IP tot len. */ msg_size_data = pbuf_hdr->IP_TotLen; } msg_size_tot = msg_size_hdr + msg_size_data; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (NET_BUF_DATA_TX_IX < msg_size_hdr) { /* See Note #5. */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); NET_CTR_ERR_INC(NetICMP_ErrTxInvalidBufIxCtr); return; } #endif msg_ix = NET_BUF_DATA_TX_IX - msg_size_hdr; pmsg_err = NetBuf_Get((NET_BUF_SIZE) msg_size_tot, /* Get err msg buf. */ (NET_BUF_SIZE) msg_ix, (CPU_INT16U ) NET_BUF_FLAG_NONE, (NET_ERR *)&err); if (err != NET_BUF_ERR_NONE) { NetICMP_TxPktDiscard(pmsg_err, perr); return; } msg_ix_data = msg_ix + msg_size_hdr; NetBuf_DataWr((NET_BUF *) pmsg_err, /* Copy rx'd IP hdr & data into ICMP err tx buf. */ (NET_BUF_SIZE) msg_ix_data, (NET_BUF_SIZE) msg_size_data, (CPU_INT08U *) pip_hdr, (NET_ERR *)&err); if (err != NET_BUF_ERR_NONE) { NetICMP_TxPktDiscard(pmsg_err, perr); return; } /* Init err msg buf ctrls. */ pmsg_err_hdr = &pmsg_err->Hdr; pmsg_err_hdr->ICMP_MsgIx = (CPU_INT16U )msg_ix; pmsg_err_hdr->ICMP_MsgLen = (CPU_INT16U )msg_size_tot; pmsg_err_hdr->ICMP_HdrLen = (CPU_INT16U )msg_size_hdr; pmsg_err_hdr->TotLen = (NET_BUF_SIZE)pmsg_err_hdr->ICMP_MsgLen; pmsg_err_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_ICMP; #if 0 /* Init'd in NetBuf_Get() [see Note #6]. */ pmsg_err_hdr->DataIx = NET_BUF_IX_NONE; pmsg_err_hdr->DataLen = 0; #endif /*$PAGE*/ /* --------------- PREPARE ICMP ERR MSG --------------- */ switch (type) { case NET_ICMP_MSG_TYPE_DEST_UNREACH: case NET_ICMP_MSG_TYPE_SRC_QUENCH: case NET_ICMP_MSG_TYPE_TIME_EXCEED: picmp_hdr_err = (NET_ICMP_HDR_ERR *)&pmsg_err->Data[pmsg_err_hdr->ICMP_MsgIx]; picmp_hdr_err->Type = type; picmp_hdr_err->Code = code; /* Clr unused octets. */ Mem_Clr((void *)picmp_hdr_err->Unused, (CPU_SIZE_T)NET_ICMP_HDR_NBR_OCTETS_UNUSED); /* Calc ICMP msg chk sum (see Note #7). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_err->ChkSum, 0x0000); /* Clr chk sum (see Note #7b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumHdrCalc((void *) picmp_hdr_err, (CPU_INT16U) pmsg_err_hdr->ICMP_MsgLen, (NET_ERR *)&err); NET_UTIL_VAL_COPY_16(&picmp_hdr_err->ChkSum, &msg_chk_sum); /* Copy chk sum in net order (see Note #7c).*/ break; case NET_ICMP_MSG_TYPE_PARAM_PROB: picmp_hdr_param_prob = (NET_ICMP_HDR_PARAM_PROB *)&pmsg_err->Data[pmsg_err_hdr->ICMP_MsgIx]; picmp_hdr_param_prob->Type = type; picmp_hdr_param_prob->Code = code; picmp_hdr_param_prob->Ptr = ptr; /* Clr unused octets. */ Mem_Clr((void *)picmp_hdr_param_prob->Unused, (CPU_SIZE_T)NET_ICMP_HDR_NBR_OCTETS_UNUSED_PARAM_PROB); /* Calc ICMP msg chk sum (see Note #7). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_param_prob->ChkSum, 0x0000);/* Clr chk sum (see Note #7b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumHdrCalc((void *) picmp_hdr_param_prob, (CPU_INT16U) pmsg_err_hdr->ICMP_MsgLen, (NET_ERR *)&err); /* Copy chk sum in net order (see Note #7c).*/ NET_UTIL_VAL_COPY_16(&picmp_hdr_param_prob->ChkSum, &msg_chk_sum); break; default: /* See Note #4. */ NetICMP_TxPktDiscard(pmsg_err, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } if (err != NET_UTIL_ERR_NONE) { /* Chk err from NetUtil_16BitOnesCplChkSumHdrCalc(). */ NetICMP_TxPktDiscard(pmsg_err, perr); return; } /* ----------------- TX ICMP ERR MSG ------------------ */ NetIP_Tx((NET_BUF *)pmsg_err, (NET_IP_ADDR)pbuf_hdr->IP_AddrDest, (NET_IP_ADDR)pbuf_hdr->IP_AddrSrc, (NET_IP_TOS )NET_IP_TOS_DFLT, /* See Note #1da. */ (NET_IP_TTL )NET_IP_TTL_DFLT, (CPU_INT16U )NET_IP_FLAG_NONE, (void *)0, (NET_ERR *)perr); /* ------- FREE ICMP ERR MSG / UPDATE TX STATS -------- */ switch (*perr) { case NET_IP_ERR_NONE: NetICMP_TxPktFree(pmsg_err); NET_CTR_STAT_INC(NetICMP_StatTxMsgCtr); NET_CTR_STAT_INC(NetICMP_StatTxMsgErrCtr); break; case NET_ERR_TX: NET_CTR_ERR_INC(NetICMP_ErrTxPktDiscardedCtr); /* See Note #8. */ return; /* Prevent 'break NOT reachable' compiler warning. */ case NET_ERR_INIT_INCOMPLETE: default: NetICMP_TxPktDiscard(pmsg_err, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } *perr = NET_ICMP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_TxMsgReq() * * Description : (1) Transmit ICMP Request Message : * * (a) Validate ICMP Request Message : * * (1) Validate the following arguments : * * (A) Type * (B) Code * * (2) Validation of the following arguments deferred to NetIP_Tx() : * * (A) Type of Service (TOS) See RFC #1349, Section 5.1 * (B) Time-to-Live (TTL) * (C) Destination Address * (D) IP flags * (E) IP options * * (3) Validation ignores the following arguments : * * (A) Data * (B) Data length * * (b) Get buffer for ICMP Request Message : * * (1) Calculate ICMP Request Message buffer size * (2) Copy data into ICMP Request Message * (3) Initialize ICMP Request Message buffer controls * * (c) Prepare ICMP Request Message : * * (1) Type See Note #1cA * (2) Code See Note #1cA * (3) Identification (ID) * (4) Sequence Number * (5) Data * (6) Timestamps * * (A) See 'net_icmp.h ICMP MESSAGE TYPES & CODES Notes #2 & #3' for supported ICMP * message types & codes. * * (B) Timestamp Request Message * * (1) "The Originate Timestamp is the time the sender last touched the message * before sending it" (RFC #792, Section 'Timestamp or Timestamp Reply Message : * Description'). * * (d) Transmit ICMP Request Message * * (e) Free ICMP Request Message buffer * * (f) Update transmit statistics * * (g) Return ICMP Request Message Identification & Sequence Number * OR * NULL id & sequence number structure, on failure * * *$PAGE* * Argument(s) : type ICMP Request Message type (see Note #1cA) : * * NET_ICMP_MSG_TYPE_ECHO_REQ * NET_ICMP_MSG_TYPE_TS_REQ * NET_ICMP_MSG_TYPE_ADDR_MASK_REQ * * code ICMP Request Message code (see Note #1cA). * * id ICMP Request Message id (see 'net_os.c NetOS_ICMP_TxMsgReq() Note #3b'). * * TOS Specific TOS to transmit IP packet * (see 'net_ip.h IP HEADER TYPE OF SERVICE (TOS) DEFINES'). * * TTL Specific TTL to transmit IP packet (see 'net_ip.h IP HEADER DEFINES'). * * addr_dest Destination IP address. * * flags Flags to select 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 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.h Note #1f'). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE ICMP Request Message successfully transmitted. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * ---- RETURNED BY NetICMP_TxPktDiscard() : ---- * NET_ERR_TX Transmit error; packet discarded. * * Return(s) : ICMP Request Message's Identification (ID) & Sequence Numbers, if NO errors. * * NULL Identification (ID) & Sequence Numbers, otherwise. * * Caller(s) : NetOS_ICMP_TxMsgReq(). * * This function is an INTERNAL network protocol suite function & SHOULD NOT be called by * application function(s). * * Note(s) : (2) NetICMP_TxMsgReq() blocked until network initialization completes. * * (3) NetICMP_TxMsgReq() is the internal ICMP handler for ICMP Request Messages. Its * global declaration is required since NetOS_ICMP_TxMsgReq() calls the handler function * from the OS port file (see also 'net_os.c NetOS_ICMP_TxMsgReq() Note #1'). * * (4) Default case already invalidated in NetICMP_TxMsgReqValidate(). However, the default * case is included as an extra precaution in case 'type' is incorrectly modified. * * (5) Assumes network buffer's protocol header size is large enough to accomodate ICMP header * size (see 'net_buf.h NETWORK BUFFER INDEX & SIZE DEFINES Note #1'). * * (6) Some buffer controls were previously initialized in NetBuf_Get() when the buffer * was allocated earlier in this function. These buffer controls do NOT need to be * re-initialized but are shown for completeness. * * (7) (a) ICMP message Check-Sum MUST be calculated AFTER the entire ICMP message 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) ICMP message Check-Sum field MUST be cleared to '0' BEFORE the ICMP message * Check-Sum is calculated (see RFC #792, Sections 'Echo or Echo Reply Message : * Checksum', 'Timestamp or Timestamp Reply Message : Checksum'; & RFC #950, * Appendix I 'Address Mask ICMP', Section 'ICMP Fields : Checksum'). * * (c) The ICMP message Check-Sum field is returned in network-order & MUST NOT be re- * converted back to host-order (see 'net_util.c NetUtil_16BitOnesCplChkSumHdrCalc() * Note #3b' & 'net_util.c NetUtil_16BitOnesCplChkSumDataCalc() Note #4b'). * * (8) Network buffer already freed by lower layer; only increment error counter. ********************************************************************************************************* */ /*$PAGE*/ NET_ICMP_REQ_ID_SEQ NetICMP_TxMsgReq (CPU_INT08U type, CPU_INT08U code, CPU_INT16U id, NET_IP_TOS TOS, NET_IP_TTL TTL, NET_IP_ADDR addr_dest, CPU_INT16U flags, void *popts, void *p_data, CPU_INT16U data_len, NET_ERR *perr) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif NET_ICMP_REQ_ID_SEQ id_seq; CPU_INT16U msg_size_hdr; CPU_INT16U msg_size_data; CPU_INT16U msg_size_tot; CPU_INT16U msg_seq_nbr; CPU_INT16U msg_ix; CPU_INT16U msg_ix_data; CPU_INT16U msg_chk_sum; NET_TS ts; NET_BUF *pmsg_req; NET_BUF_HDR *pmsg_req_hdr; NET_ICMP_HDR_ECHO *picmp_hdr_echo; NET_ICMP_HDR_TS *picmp_hdr_ts; NET_ICMP_HDR_ADDR_MASK *picmp_hdr_addr; NET_ERR err; /* Prepare err rtn val. */ id_seq.ID = 0; id_seq.SeqNbr = 0; #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit tx (see Note #2). */ *perr = NET_ERR_INIT_INCOMPLETE; return (id_seq); } #endif /* ------------- VALIDATE ICMP TX REQ MSG ------------- */ NetICMP_TxMsgReqValidate(type, code, &err); if (err != NET_ICMP_ERR_NONE) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); return (id_seq); } /*$PAGE*/ /* --------------- GET ICMP REQ MSG BUF --------------- */ /* Calc req msg buf size. */ switch (type) { case NET_ICMP_MSG_TYPE_ECHO_REQ: msg_size_hdr = NET_ICMP_HDR_SIZE_ECHO; if (p_data != (void *)0) { msg_size_data = data_len; } else { msg_size_data = 0; } break; case NET_ICMP_MSG_TYPE_TS_REQ: #if 1 /* ???? Rtn err OR ignore data? */ if (p_data != (void *)0) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); return (id_seq); } if (data_len > 0) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); return (id_seq); } #endif msg_size_hdr = NET_ICMP_HDR_SIZE_TS; msg_size_data = 0; break; case NET_ICMP_MSG_TYPE_ADDR_MASK_REQ: #if 1 /* ???? Rtn err OR ignore data? */ if (p_data != (void *)0) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); return (id_seq); } if (data_len > 0) { NetICMP_TxPktDiscard((NET_BUF *)0, perr); return (id_seq); } #endif msg_size_hdr = NET_ICMP_HDR_SIZE_ADDR_MASK; msg_size_data = 0; break; default: /* See Note #4. */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); return (id_seq); /* Prevent 'break NOT reachable' compiler warning. */ } msg_size_tot = msg_size_hdr + msg_size_data; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (NET_BUF_DATA_TX_IX < msg_size_hdr) { /* See Note #5. */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); NET_CTR_ERR_INC(NetICMP_ErrTxInvalidBufIxCtr); return (id_seq); } #endif msg_ix = NET_BUF_DATA_TX_IX - msg_size_hdr; pmsg_req = NetBuf_Get((NET_BUF_SIZE) msg_size_tot, /* Get req msg buf. */ (NET_BUF_SIZE) msg_ix, (CPU_INT16U ) NET_BUF_FLAG_NONE, (NET_ERR *)&err); if (err != NET_BUF_ERR_NONE) { NetICMP_TxPktDiscard(pmsg_req, perr); return (id_seq); } /*$PAGE*/ /* Init req msg buf ctrls. */ pmsg_req_hdr = &pmsg_req->Hdr; pmsg_req_hdr->ICMP_MsgIx = (CPU_INT16U )msg_ix; pmsg_req_hdr->ICMP_MsgLen = (CPU_INT16U )msg_size_tot; pmsg_req_hdr->ICMP_HdrLen = (CPU_INT16U )msg_size_hdr; pmsg_req_hdr->TotLen = (NET_BUF_SIZE)pmsg_req_hdr->ICMP_MsgLen; pmsg_req_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_ICMP; msg_ix_data = msg_ix + msg_size_hdr; if (msg_size_data > 0) { /* Copy data into ICMP req tx buf. */ NetBuf_DataWr((NET_BUF *) pmsg_req, (NET_BUF_SIZE) msg_ix_data, (NET_BUF_SIZE) msg_size_data, (CPU_INT08U *) p_data, (NET_ERR *)&err); if (err != NET_BUF_ERR_NONE) { NetICMP_TxPktDiscard(pmsg_req, perr); return (id_seq); } pmsg_req_hdr->DataIx = (CPU_INT16U )msg_ix_data; pmsg_req_hdr->DataLen = (NET_BUF_SIZE)msg_size_data; #if 0 /* Init'd in NetBuf_Get() [see Note #6]. */ } else { pmsg_req_hdr->DataIx = NET_BUF_IX_NONE; pmsg_req_hdr->DataLen = 0; #endif } /*$PAGE*/ /* --------------- PREPARE ICMP REQ MSG --------------- */ NET_ICMP_TX_GET_SEQ_NBR(msg_seq_nbr); switch (type) { case NET_ICMP_MSG_TYPE_ECHO_REQ: picmp_hdr_echo = (NET_ICMP_HDR_ECHO *)&pmsg_req->Data[pmsg_req_hdr->ICMP_MsgIx]; picmp_hdr_echo->Type = NET_ICMP_MSG_TYPE_ECHO_REQ; picmp_hdr_echo->Code = NET_ICMP_MSG_CODE_ECHO_REQ; NET_UTIL_VAL_COPY_SET_NET_16(&picmp_hdr_echo->ID, &id); NET_UTIL_VAL_COPY_SET_NET_16(&picmp_hdr_echo->SeqNbr, &msg_seq_nbr); /* Calc ICMP msg chk sum (see Note #7). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_echo->ChkSum, 0x0000); /* Clr chk sum (see Note #7b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumDataCalc((void *) pmsg_req, (void *) 0, (CPU_INT16U) 0, (NET_ERR *)&err); NET_UTIL_VAL_COPY_16(&picmp_hdr_echo->ChkSum, &msg_chk_sum); /* Copy chk sum in net order (see Note #7c).*/ break; case NET_ICMP_MSG_TYPE_TS_REQ: picmp_hdr_ts = (NET_ICMP_HDR_TS *)&pmsg_req->Data[pmsg_req_hdr->ICMP_MsgIx]; picmp_hdr_ts->Type = NET_ICMP_MSG_TYPE_TS_REQ; picmp_hdr_ts->Code = NET_ICMP_MSG_CODE_TS_REQ; ts = NetUtil_TS_Get(); /* See Note #1cB1. */ NET_UTIL_VAL_COPY_SET_NET_16(&picmp_hdr_ts->ID, &id); NET_UTIL_VAL_COPY_SET_NET_16(&picmp_hdr_ts->SeqNbr, &msg_seq_nbr); NET_UTIL_VAL_COPY_SET_NET_32(&picmp_hdr_ts->TS_Originate, &ts); NET_UTIL_VAL_SET_NET_32(&picmp_hdr_ts->TS_Rx, NET_TS_NONE); NET_UTIL_VAL_SET_NET_32(&picmp_hdr_ts->TS_Tx, NET_TS_NONE); /* Calc ICMP msg chk sum (see Note #7). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_ts->ChkSum, 0x0000); /* Clr chk sum (see Note #7b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumHdrCalc((void *) picmp_hdr_ts, (CPU_INT16U) pmsg_req_hdr->ICMP_MsgLen, (NET_ERR *)&err); NET_UTIL_VAL_COPY_16(&picmp_hdr_ts->ChkSum, &msg_chk_sum); /* Copy chk sum in net order (see Note #7c).*/ break; case NET_ICMP_MSG_TYPE_ADDR_MASK_REQ: picmp_hdr_addr = (NET_ICMP_HDR_ADDR_MASK *)&pmsg_req->Data[pmsg_req_hdr->ICMP_MsgIx]; picmp_hdr_addr->Type = NET_ICMP_MSG_TYPE_ADDR_MASK_REQ; picmp_hdr_addr->Code = NET_ICMP_MSG_CODE_ADDR_MASK_REQ; NET_UTIL_VAL_COPY_SET_NET_16(&picmp_hdr_addr->ID, &id); NET_UTIL_VAL_COPY_SET_NET_16(&picmp_hdr_addr->SeqNbr, &msg_seq_nbr); NET_UTIL_VAL_SET_NET_32(&picmp_hdr_addr->AddrMask, NET_IP_ADDR_NONE); /* Calc ICMP msg chk sum (see Note #7). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_addr->ChkSum, 0x0000); /* Clr chk sum (see Note #7b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumHdrCalc((void *) picmp_hdr_addr, (CPU_INT16U) pmsg_req_hdr->ICMP_MsgLen, (NET_ERR *)&err); NET_UTIL_VAL_COPY_16(&picmp_hdr_addr->ChkSum, &msg_chk_sum); /* Copy chk sum in net order (see Note #7c).*/ break; default: /* See Note #4. */ NetICMP_TxPktDiscard(pmsg_req, perr); return (id_seq); /* Prevent 'break NOT reachable' compiler warning. */ } if (err != NET_UTIL_ERR_NONE) { /* Chk err from NetUtil_16BitOnesCplChkSum()'s. */ NetICMP_TxPktDiscard(pmsg_req, perr); return (id_seq); } /*$PAGE*/ /* ----------------- TX ICMP REQ MSG ------------------ */ NetIP_Tx((NET_BUF *)pmsg_req, (NET_IP_ADDR)NetIP_AddrThisHost, (NET_IP_ADDR)addr_dest, (NET_IP_TOS )TOS, (NET_IP_TTL )TTL, (CPU_INT16U )flags, (void *)popts, (NET_ERR *)perr); /* ------- FREE ICMP REQ MSG / UPDATE TX STATS -------- */ switch (*perr) { case NET_IP_ERR_NONE: NetICMP_TxPktFree(pmsg_req); NET_CTR_STAT_INC(NetICMP_StatTxMsgCtr); NET_CTR_STAT_INC(NetICMP_StatTxMsgReqCtr); break; case NET_ERR_TX: NET_CTR_ERR_INC(NetICMP_ErrTxPktDiscardedCtr); /* See Note #8. */ return (id_seq); /* Prevent 'break NOT reachable' compiler warning. */ case NET_ERR_INIT_INCOMPLETE: default: NetICMP_TxPktDiscard(pmsg_req, perr); return (id_seq); /* Prevent 'break NOT reachable' compiler warning. */ } *perr = NET_ICMP_ERR_NONE; /* ----------- RTN ICMP REQ MSG ID/SEQ NBR ------------ */ id_seq.ID = id; id_seq.SeqNbr = msg_seq_nbr; return (id_seq); } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerRx() * * Description : Handle & reply to incoming IP packets for ICMP error &/or status conditions. * * (1) (a) When network low-resources status is set, transmit ICMP Source Quench Error Messages. * * (b) When network low-resources status clears, clear the ICMP Transmit Source Quench List. * * * Argument(s) : pbuf Pointer to network buffer that received an IP packet. * ---- Argument validated in NetIP_RxPktValidate() * by NetIP_Rx(). * * Return(s) : none. * * Caller(s) : NetIP_RxPktValidate(). * * This function is an INTERNAL network protocol suite function & MUST NOT be called by * application function(s). * * Note(s) : none. ********************************************************************************************************* */ void NetICMP_HandlerRx (NET_BUF *pbuf) { #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) NET_DBG_STATUS rsrc_lo; rsrc_lo = NetDbg_MonTaskStatGetHandlerLo(); /* Get lo rsrc's status. */ if (rsrc_lo != NET_DBG_STATUS_OK) { /* If net rsrc's lo, ... */ NetICMP_HandlerTxSrcQuench(pbuf); /* ... tx ICMP src quench err to IP pkt src host. */ } else { /* Else if ICMP tx src quench list avail, ... */ if (NetICMP_TxSrcQuenchListHead != (NET_ICMP_TX_SRC_QUENCH *)0) { NetICMP_HandlerTxSrcQuenchClrList(); /* ... clr tx src quench list. */ } } #else (void)&pbuf; /* Prevent compiler warning. */ #endif } /*$PAGE*/ /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * NetICMP_RxPktValidateBuf() * * Description : Validate received buffer header as ICMP protocol. * * Argument(s) : pbuf_hdr Pointer to network buffer header that received ICMP packet. * -------- Argument validated in NetICMP_Rx(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE Received buffer's ICMP header validated. * NET_ERR_INVALID_PROTOCOL Buffer's protocol type is NOT ICMP. * NET_BUF_ERR_INVALID_IX Invalid buffer index. * * Return(s) : none. * * Caller(s) : NetICMP_Rx(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static void NetICMP_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 ICMP BUF HDR -------------- */ if (pbuf_hdr->ProtocolHdrType != NET_PROTOCOL_TYPE_ICMP) { NET_CTR_ERR_INC(Net_ErrInvalidProtocolCtr); *perr = NET_ERR_INVALID_PROTOCOL; return; } if (pbuf_hdr->ICMP_MsgIx == NET_BUF_IX_NONE) { NET_CTR_ERR_INC(NetICMP_ErrRxInvalidBufIxCtr); *perr = NET_BUF_ERR_INVALID_IX; return; } *perr = NET_ICMP_ERR_NONE; } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_RxPktValidate() * * Description : (1) Validate received ICMP packet : * * (a) Validate the received packet's destination (see Note #3). * * (b) (1) Validate the received packet's following ICMP message fields : * * (A) Type * (B) Code * (C) Message Length * (D) Pointer See RFC #792, Section 'Parameter Problem Message' * (E) Check-Sum See Note #7a * * (2) Validation ignores the following ICMP header fields : * * (A) Unused See RFC # 792, Section 'Message Formats' * (B) Data See RFC #1122, Sections 3.2.2 & 3.2.2.6 * (C) Identification (ID) See RFC # 792, Sections 'Echo or Echo Reply Message' * & 'Timestamp or Timestamp Reply Message' * (D) Sequence Number See RFC # 792, Sections 'Echo or Echo Reply Message' * & 'Timestamp or Timestamp Reply Message' * * (c) Convert the following ICMP message fields from network-order to host-order : * * (1) Check-Sum See Note #7c * * (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. * * (d) Update network buffer's length controls. * * (e) Demultiplex ICMP message type. * * * Argument(s) : pbuf Pointer to network buffer that received ICMP packet. * ---- Argument checked in NetICMP_Rx(). * * pbuf_hdr Pointer to network buffer header. * -------- Argument validated in NetICMP_Rx(). * * picmp_hdr Pointer to received packet's ICMP header. * --------- Argument validated in NetICMP_Rx()/NetICMP_RxPktValidateBuf(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_MSG_TYPE_ERR Received packet validated as ICMP Error Message. * NET_ICMP_ERR_MSG_TYPE_REQ Received packet validated as ICMP Request Message. * NET_ICMP_ERR_MSG_TYPE_REPLY Received packet validated as ICMP Reply Message. * * NET_ICMP_ERR_RX_BROADCAST Packet received via broadcast. * * NET_ICMP_ERR_INVALID_TYPE Invalid/unknown ICMP message type. * NET_ICMP_ERR_INVALID_CODE Invalid/unknown ICMP message code. * NET_ICMP_ERR_INVALID_PTR Invalid ICMP message pointer outside ICMP message. * NET_ICMP_ERR_INVALID_LEN Invalid ICMP message length. * NET_ICMP_ERR_INVALID_LEN_DATA Invalid ICMP message data length. * NET_ICMP_ERR_INVALID_CHK_SUM Invalid ICMP check-sum. * * Return(s) : none. * * Caller(s) : NetICMP_Rx(). * * Note(s) : (2) See 'net_icmp.h ICMP HEADER' for ICMP header format. * * (3) (a) RFC #1122, Sections 3.2.2.6 & 3.2.2.8 state that "an ICMP ... Request destined to an * IP broadcast ... address MAY be silently discarded". * * However, NO RFC specifies how OTHER ICMP messages should handle messages received by * broadcast. ???? Therefore, it is assumed that ALL ICMP messages destined to an IP * broadcast address SHOULD be silently discarded. * * (b) Since a packet destined to a valid IP broadcast address MUST also have been received as * a link-layer broadcast (see RFC #1122, Section 3.3.6 & 'net_ip.c NetIP_RxPktValidate() * Note #9d3B'), the determination of an IP broadcast destination address need only verify * that the received packet was received as a link-layer broadcast packet. * * (4) (a) RFC #1122, Section 3.2.2 requires that ICMP messages with the following invalid ICMP * header fields be "silently discarded" : * * (1) Type RFC #1122, Section 3.2.2 * * (b) Assumes that ICMP messages with the following invalid ICMP header fields should also * be "silently discarded" : * * (1) Code * (2) Message Length * (3) Pointer * (4) Check-Sum *$PAGE* * (5) See 'net_icmp.h ICMP MESSAGE TYPES & CODES Notes #2 & #3' for currently unsupported * ICMP message types/codes. * * (6) Since ICMP message headers do NOT contain a message length field, the ICMP Message Length * is assumed to be the remaining IP Datagram Length. * * (7) (a) ICMP message Check-Sum field MUST be validated AFTER (or BEFORE) 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 ICMP message Check-Sum CANNOT be validated AFTER SOME but NOT * ALL multi-octet words have been converted from network-order to host-order. * * However, ALL received packets' multi-octet words are converted in local or network * buffer variables ONLY (see Note #1cA). Therefore, ICMP message Check-Sum may be * validated at any point. * * (b) RFC #792, Section 'Echo or Echo Reply Message : Checksum' specifies that "if the * total length is odd, the received data is padded with one octet of zeros for * computing the checksum". * * However, NO RFC specifies how OTHER ICMP message types should handle odd-length * check-sums. Therefore, it is assumed that ICMP Echo Request & Echo Reply Messages * should handle odd-length check-sums according to RFC #792's 'Echo or Echo Reply * Message : Checksum' specification, while ALL other ICMP message types should handle * odd-length check-sums according to RFC #1071, Section 4.1. * * See also 'net_util.c NetUtil_16BitSumDataCalc() Note #8'. * * (c) After the ICMP message 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. * * (8) Default case already invalidated earlier in this function. However, the default case * is included as an extra precaution in case 'Type' is incorrectly modified. * * (9) (a) (1) Except for ICMP Echo & Echo Reply Messages (see Note #9b), most ICMP messages do * NOT permit user &/or application data (see RFC #792 & RFC #1122, Sections 3.2.2). * * (2) Most ICMP messages that do NOT contain user &/or application data will NOT be * received in separate packet buffers since most ICMP messages are NOT large enough * to be fragmented since the minimum network buffer size MUST be configured such * that most ICMP messages fit within a single packet buffer (see 'net_buf.h * NETWORK BUFFER INDEX & SIZE DEFINES Note #1d'). * * However, RFC #1122, Section 3.2.2 states that "every ICMP error message includes * the Internet header and at least the first 8 data octets of the datagram that * triggered the error; more than 8 octets MAY be sent". Thus, it is possible that * some received ICMP error messages MAY contain more than 8 octets of the Internet * header & may therefore be received in one or more fragmented packet buffers. * * Furthermore, these additional error message octets SHOULD NOT contain user &/or * application data. * * (3) ICMP data index value to clear was previously initialized in NetBuf_Get() when * the buffer was allocated. This index value does NOT need to be re-cleared but * is shown for completeness. * * (b) (1) ICMP Echo & Echo Reply Messages permit the transmission & receipt of user &/or * application data (see RFC #792, Section 'Echo or Echo Reply Message' & RFC #1122, * Section 3.2.2.6). * * Since the minimum network buffer size MUST be configured such that the entire * ICMP Echo Message header MUST be received in a single packet (see 'net_buf.h * NETWORK BUFFER INDEX & SIZE DEFINES Note #1d'), after the ICMP Echo Message * 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. * * (A) Note that the 'Data' index is updated regardless of a null-size data length. * * (2) 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 ICMP Message Length is duplicated in ALL fragmented packet buffers * (may NOT be necessary; remove if unnecessary). ********************************************************************************************************* */ /*$PAGE*/ static void NetICMP_RxPktValidate (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, NET_ICMP_HDR *picmp_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 rx_broadcast; CPU_BOOLEAN icmp_chk_sum_valid; CPU_INT16U icmp_msg_len_hdr; CPU_INT16U icmp_msg_len_min; CPU_INT16U icmp_msg_len_max; CPU_INT16U icmp_msg_len; NET_ICMP_HDR_PARAM_PROB *picmp_param_prob; NET_BUF *pbuf_next; NET_BUF_HDR *pbuf_next_hdr; /* -------------- VALIDATE ICMP RX DEST --------------- */ rx_broadcast = DEF_BIT_IS_SET(pbuf_hdr->Flags, NET_BUF_FLAG_BROADCAST_RX); if (rx_broadcast != DEF_NO) { /* If ICMP rx'd as broadcast, rtn err (see Note #3). */ NET_CTR_ERR_INC(NetICMP_ErrRxBroadcastCtr); *perr = NET_ICMP_ERR_RX_BROADCAST; return; } /* ------------- VALIDATE ICMP TYPE/CODE -------------- */ switch (picmp_hdr->Type) { /* See Notes #4a1 & #4b1. */ case NET_ICMP_MSG_TYPE_DEST_UNREACH: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_DEST_NET: case NET_ICMP_MSG_CODE_DEST_HOST: case NET_ICMP_MSG_CODE_DEST_PROTOCOL: case NET_ICMP_MSG_CODE_DEST_PORT: case NET_ICMP_MSG_CODE_DEST_FRAG_NEEDED: case NET_ICMP_MSG_CODE_DEST_ROUTE_FAIL: case NET_ICMP_MSG_CODE_DEST_NET_UNKNOWN: case NET_ICMP_MSG_CODE_DEST_HOST_UNKNOWN: case NET_ICMP_MSG_CODE_DEST_HOST_ISOLATED: case NET_ICMP_MSG_CODE_DEST_NET_TOS: case NET_ICMP_MSG_CODE_DEST_HOST_TOS: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_DEST_UNREACH; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_DEST_UNREACH; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_DEST_UNREACH; break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_SRC_QUENCH: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_SRC_QUENCH: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_SRC_QUENCH; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_SRC_QUENCH; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_SRC_QUENCH; break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; /*$PAGE*/ case NET_ICMP_MSG_TYPE_TIME_EXCEED: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_TIME_EXCEED_TTL: case NET_ICMP_MSG_CODE_TIME_EXCEED_FRAG_REASM: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_TIME_EXCEED; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_TIME_EXCEED; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_TIME_EXCEED; break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_PARAM_PROB: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_PARAM_PROB_IP_HDR: case NET_ICMP_MSG_CODE_PARAM_PROB_OPT_MISSING: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_PARAM_PROB; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_PARAM_PROB; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_PARAM_PROB; picmp_param_prob = (NET_ICMP_HDR_PARAM_PROB *)picmp_hdr; if (picmp_param_prob->Ptr < NET_ICMP_MSG_PTR_MIN_PARAM_PROB) { /* If ptr val < min ptr val, .. */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrPtrCtr); *perr = NET_ICMP_ERR_INVALID_PTR; /* ... rtn err (see Note #4b3). */ return; } break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_ECHO_REQ: case NET_ICMP_MSG_TYPE_ECHO_REPLY: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_ECHO: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_ECHO; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_ECHO; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_ECHO; break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_TS_REQ: case NET_ICMP_MSG_TYPE_TS_REPLY: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_TS: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_TS; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_TS; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_TS; break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; /*$PAGE*/ case NET_ICMP_MSG_TYPE_ADDR_MASK_REPLY: switch (picmp_hdr->Code) { case NET_ICMP_MSG_CODE_ADDR_MASK: icmp_msg_len_hdr = NET_ICMP_HDR_SIZE_ADDR_MASK; icmp_msg_len_min = NET_ICMP_MSG_LEN_MIN_ADDR_MASK; icmp_msg_len_max = NET_ICMP_MSG_LEN_MAX_ADDR_MASK; break; default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; #if 0 /* ---------------- UNSUPPORTED TYPES ----------------- */ /* See Note #5. */ case NET_ICMP_MSG_TYPE_REDIRECT: case NET_ICMP_MSG_TYPE_ROUTE_REQ: case NET_ICMP_MSG_TYPE_ROUTE_AD: case NET_ICMP_MSG_TYPE_ADDR_MASK_REQ: /* 'break' intentionally omitted; do NOT move from the */ /* ... following case : 'default'. */ #endif default: NET_CTR_ERR_INC(NetICMP_ErrRxHdrTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } /*$PAGE*/ /* -------------- VALIDATE ICMP MSG LEN --------------- */ icmp_msg_len = pbuf_hdr->IP_DatagramLen; /* See Note #6. */ pbuf_hdr->ICMP_MsgLen = icmp_msg_len; if (pbuf_hdr->ICMP_MsgLen < icmp_msg_len_min) { /* If msg len < min msg len, rtn err. */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrMsgLenCtr); *perr = NET_ICMP_ERR_INVALID_LEN; return; } if (icmp_msg_len_max != NET_ICMP_MSG_LEN_MAX_NONE) { if (pbuf_hdr->ICMP_MsgLen > icmp_msg_len_max) { /* If msg len > max msg len, rtn err. */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrMsgLenCtr); *perr = NET_ICMP_ERR_INVALID_LEN; return; } } if (picmp_hdr->Type == NET_ICMP_MSG_TYPE_PARAM_PROB) { /* For ICMP Param Prob msg, ... */ if (picmp_param_prob->Ptr >= pbuf_hdr->ICMP_MsgLen) { /* ... if ptr val >= msg len, ... */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrPtrCtr); *perr = NET_ICMP_ERR_INVALID_PTR; /* ... rtn err (see Note #4b3). */ return; } } /* -------------- VALIDATE ICMP CHK SUM --------------- */ /* See Note #7. */ switch (picmp_hdr->Type) { /* See Note #7b. */ case NET_ICMP_MSG_TYPE_DEST_UNREACH: case NET_ICMP_MSG_TYPE_SRC_QUENCH: case NET_ICMP_MSG_TYPE_TIME_EXCEED: case NET_ICMP_MSG_TYPE_PARAM_PROB: case NET_ICMP_MSG_TYPE_TS_REQ: case NET_ICMP_MSG_TYPE_TS_REPLY: case NET_ICMP_MSG_TYPE_ADDR_MASK_REPLY: icmp_chk_sum_valid = NetUtil_16BitOnesCplChkSumHdrVerify((void *)picmp_hdr, (CPU_INT16U)pbuf_hdr->ICMP_MsgLen, (NET_ERR *)perr); break; case NET_ICMP_MSG_TYPE_ECHO_REQ: case NET_ICMP_MSG_TYPE_ECHO_REPLY: icmp_chk_sum_valid = NetUtil_16BitOnesCplChkSumDataVerify((void *)pbuf, (void *)0, (CPU_INT16U)0, (NET_ERR *)perr); break; default: /* See Note #8. */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } if (icmp_chk_sum_valid != DEF_OK) { NET_CTR_ERR_INC(NetICMP_ErrRxHdrChkSumCtr); *perr = NET_ICMP_ERR_INVALID_CHK_SUM; return; } #if 0 /* Conv to host-order NOT necessary (see Note #7c). */ (void)NET_UTIL_VAL_GET_NET_16(&picmp_hdr->ChkSum); #endif /*$PAGE*/ /* ----------------- UPDATE BUF CTRLS ----------------- */ pbuf_hdr->ICMP_HdrLen = icmp_msg_len_hdr; switch (picmp_hdr->Type) { case NET_ICMP_MSG_TYPE_DEST_UNREACH: case NET_ICMP_MSG_TYPE_SRC_QUENCH: case NET_ICMP_MSG_TYPE_TIME_EXCEED: case NET_ICMP_MSG_TYPE_PARAM_PROB: case NET_ICMP_MSG_TYPE_TS_REQ: case NET_ICMP_MSG_TYPE_TS_REPLY: case NET_ICMP_MSG_TYPE_ADDR_MASK_REPLY: pbuf_hdr->DataLen = 0; /* Clr data len/ix (see Note #9a1). */ #if 0 /* Clr'd in NetBuf_Get() [see Note #9a3]. */ pbuf_hdr->DataIx = NET_BUF_IX_NONE; #endif pbuf_next = (NET_BUF *)pbuf_hdr->NextBufPtr; while (pbuf_next != (NET_BUF *)0) { /* Clr ALL pkt bufs' data len/ix (see Note #9a2). */ pbuf_next_hdr = &pbuf_next->Hdr; pbuf_next_hdr->DataLen = 0; #if 0 /* Clr'd in NetBuf_Get() [see Note #9a3]. */ pbuf_next_hdr->DataIx = NET_BUF_IX_NONE; #endif pbuf_next_hdr->ICMP_HdrLen = 0; /* NULL ICMP hdr len in each pkt buf. */ pbuf_next_hdr->ICMP_MsgLen = icmp_msg_len; /* Dup ICMP msg len in each pkt buf (see Note #9c). */ pbuf_next = (NET_BUF *)pbuf_next_hdr->NextBufPtr; } break; case NET_ICMP_MSG_TYPE_ECHO_REQ: case NET_ICMP_MSG_TYPE_ECHO_REPLY: /* Calc ICMP Echo Msg data len/ix (see Note #9b). */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (pbuf_hdr->ICMP_HdrLen > pbuf_hdr->DataLen) { NET_CTR_ERR_INC(NetICMP_ErrRxHdrDataLenCtr); *perr = NET_ICMP_ERR_INVALID_LEN_DATA; return; } #endif pbuf_hdr->DataLen -= (NET_BUF_SIZE) pbuf_hdr->ICMP_HdrLen; pbuf_hdr->DataIx = (CPU_INT16U )(pbuf_hdr->ICMP_MsgIx + NET_ICMP_MSG_LEN_MIN_ECHO); pbuf_next = (NET_BUF *)pbuf_hdr->NextBufPtr; while (pbuf_next != (NET_BUF *)0) { /* Calc ALL pkt bufs' data len/ix (see Note #9b2). */ pbuf_next_hdr = &pbuf_next->Hdr; pbuf_next_hdr->DataIx = pbuf_next_hdr->ICMP_MsgIx; pbuf_next_hdr->ICMP_HdrLen = 0; /* NULL ICMP hdr len in each pkt buf. */ pbuf_next_hdr->ICMP_MsgLen = icmp_msg_len; /* Dup ICMP msg len in each pkt buf (see Note #9c). */ pbuf_next = (NET_BUF *)pbuf_next_hdr->NextBufPtr; } break; default: /* See Note #8. */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } /* --------------- DEMUX ICMP MSG TYPE ---------------- */ switch (picmp_hdr->Type) { case NET_ICMP_MSG_TYPE_DEST_UNREACH: case NET_ICMP_MSG_TYPE_SRC_QUENCH: case NET_ICMP_MSG_TYPE_TIME_EXCEED: case NET_ICMP_MSG_TYPE_PARAM_PROB: *perr = NET_ICMP_ERR_MSG_TYPE_ERR; break; case NET_ICMP_MSG_TYPE_ECHO_REQ: case NET_ICMP_MSG_TYPE_TS_REQ: *perr = NET_ICMP_ERR_MSG_TYPE_REQ; break; case NET_ICMP_MSG_TYPE_ECHO_REPLY: case NET_ICMP_MSG_TYPE_TS_REPLY: case NET_ICMP_MSG_TYPE_ADDR_MASK_REPLY: *perr = NET_ICMP_ERR_MSG_TYPE_REPLY; break; default: /* See Note #8. */ NET_CTR_ERR_INC(NetICMP_ErrRxHdrTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_RxPktFree() * * Description : Free network buffer(s). * * Argument(s) : pbuf Pointer to network buffer. * * Return(s) : none. * * Caller(s) : NetICMP_Rx(). * * Note(s) : none. ********************************************************************************************************* */ static void NetICMP_RxPktFree (NET_BUF *pbuf) { NetBuf_FreeBufList((NET_BUF *)pbuf, (NET_CTR *)0); } /* ********************************************************************************************************* * NetICMP_RxPktDiscard() * * Description : On any ICMP Receive errors, discard ICMP 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) : NetICMP_Rx(). * * Note(s) : none. ********************************************************************************************************* */ static void NetICMP_RxPktDiscard (NET_BUF *pbuf, NET_ERR *perr) { NET_CTR *pctr; #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) pctr = (NET_CTR *)&NetICMP_ErrRxPktDiscardedCtr; #else pctr = (NET_CTR *) 0; #endif NetBuf_FreeBufList((NET_BUF *)pbuf, (NET_CTR *)pctr); *perr = NET_ERR_RX; } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_TxMsgErrValidate() * * Description : (1) Validate received packet & transmit error parameters for ICMP Error Message transmit : * * (a) RFC #1122, Section 3.2.2 specifies that "an ICMP error message MUST NOT be sent as * the result of receiving" : * * (1) "An ICMP Error Message", ... * * (2) "A datagram destined to an IP broadcast or IP multicast address", ... * * (A) Any packet received as an IP broadcast or IP multicast destination address MUST * also have been received as a link-layer broadcast (see RFC #1122, Section 3.3.6 * & 'net_ip.c NetIP_RxPktValidate() Note #9d3'). * * Therefore, it is NOT necessary to re-validate the IP destination address as a * non-broadcast address since it has ALREADY been validated as a non-broadcast * at the link-layer (see Note #1a1). * * (B) See also 'net_ip.h Note #1d'. * * (3) "A datagram sent as a link-layer broadcast", ... * * (4) "A non-initial fragment", ... * * (5) "A datagram whose source address does not define a single host -- e.g., a zero address, * a loopback address, a broadcast address, a multicast address, or a Class E address" * * (A) ALL IP source addresses already validated (see 'net_ip.c NetIP_RxPktValidate() * Note #9c') except 'This Host' & 'Specified Host' addresses. * * (B) See also 'net_ip.h Note #1d'. * * (b) Validate ICMP Error Message transmit parameters : * * (1) Type * (2) Code * (3) Pointer See Note #6 * * * Argument(s) : pbuf Pointer to network buffer that received a packet with error(s). * ---- Argument checked in NetICMP_TxMsgErr(). * * pbuf_hdr Pointer to network buffer header. * -------- Argument validated in NetICMP_TxMsgErr(). * * pip_hdr Pointer to received packet's IP header. * ------- Argument validated in NetICMP_TxMsgErr(). * * type ICMP Error Message type (see Note #5) : * * NET_ICMP_MSG_TYPE_DEST_UNREACH * NET_ICMP_MSG_TYPE_SRC_QUENCH * NET_ICMP_MSG_TYPE_TIME_EXCEED * NET_ICMP_MSG_TYPE_PARAM_PROB * * code ICMP Error Message code (see Note #5). * * ptr Pointer to received packet's ICMP error (optional). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE Received packet successfully validated * for ICMP transmit error message. * NET_ICMP_ERR_TX_INVALID_BROADCAST Packet received as a broadcast packet. * NET_ICMP_ERR_TX_INVALID_ADDR_SRC Packet received with a non-single host * IP source address. * NET_ICMP_ERR_TX_INVALID_FRAG Packet received as a non-initial fragment. * NET_ICMP_ERR_TX_INVALID_ERR_MSG Packet received as an ICMP Error Message. * NET_ICMP_ERR_INVALID_TYPE Invalid/unknown ICMP message type. * NET_ICMP_ERR_INVALID_CODE Invalid/unknown ICMP message code. * NET_ICMP_ERR_INVALID_PTR Invalid message pointer outside error message. * NET_BUF_ERR_INVALID_IX Invalid buffer index. * * Return(s) : none. * * Caller(s) : NetICMP_TxMsgErr(). *$PAGE* * Note(s) : (2) The following IP header fields MUST be converted from network-order to host-order BEFORE * any transmit ICMP Error Messages are validated : * * (a) Total Length See 'net_ip.c NetIP_RxPktValidate() Note #3b' * (b) Source Address See 'net_ip.c NetIP_RxPktValidate() Note #3c' * * (3) See 'net_ip.h IP ADDRESS DEFINES Notes #2, #3, & #4' for supported IP addresses. * * (4) Default case already invalidated in NetIP_RxPktValidate(). However, the default case * is included as an extra precaution in case 'IP_AddrSrc' is incorrectly modified. * * (5) See 'net_icmp.h ICMP MESSAGE TYPES & CODES Notes #2 & #3' for supported ICMP message * types & codes. * * (6) (a) ICMP Parameter Problem Messages' pointer fields validated by comparing the pointer * field value to minimum & maximum pointer field values. * * (b) Since an ICMP Parameter Problem Message's minimum pointer field value is NOT less * than zero (see 'net_icmp.h ICMP POINTER DEFINES'), a minimum pointer field value * check is NOT required unless native data type 'CPU_INT16U' is incorrectly configured * as a signed integer in 'cpu.h'. * * (c) Since an ICMP Parameter Problem Message may be received for an IP or higher-layer * protocol, the maximum pointer field value is specific to each received ICMP packets' * IP header length & demultiplexed protocol header length : * * Pointer Field Value < Maximum Pointer Field Value = IP Header Length * [ + Other Protocol Header Length ] * * (d) See 'net_icmp.h ICMP POINTER DEFINES Note #2' for supported ICMP Parameter Problem * Message protocols. ********************************************************************************************************* */ /*$PAGE*/ static void NetICMP_TxMsgErrValidate (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, NET_IP_HDR *pip_hdr, CPU_INT08U type, CPU_INT08U code, CPU_INT08U ptr, 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) CPU_INT16U ptr_max; CPU_INT16U ptr_max_protocol; #endif CPU_BOOLEAN rx_broadcast; CPU_BOOLEAN ip_flag_frags_more; CPU_INT16U ip_flags; CPU_INT16U ip_frag_offset; NET_ICMP_HDR *picmp_hdr; /* ------------- CHK LINK-LAYER BROADCAST ------------- */ rx_broadcast = DEF_BIT_IS_SET(pbuf_hdr->Flags, NET_BUF_FLAG_BROADCAST_RX); if (rx_broadcast != DEF_NO) { /* If pkt rx'd via broadcast, ... */ *perr = NET_ICMP_ERR_TX_INVALID_BROADCAST; /* ... rtn err (see Note #1a3). */ return; } /* ----------------- CHK IP DEST ADDR ----------------- */ /* See Note #1a2. */ /* Dest addr already validated (see Note #1a2A). */ /* ----------------- CHK IP SRC ADDR ------------------ */ /* See Note #1a5. */ if (pbuf_hdr->IP_AddrSrc == NET_IP_ADDR_THIS_HOST) { /* Chk invalid 'This Host' (see Note #1a3A). */ *perr = NET_ICMP_ERR_TX_INVALID_ADDR_SRC; return; } if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_A_MASK) == NET_IP_ADDR_CLASS_A) { /* Chk invalid Class-A specified host (see Note #1a5A). */ if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_A_MASK_HOST) == (NET_IP_ADDR_THIS_HOST & NET_IP_ADDR_CLASS_A_MASK_HOST)) { *perr = NET_ICMP_ERR_TX_INVALID_ADDR_SRC; return; } } else if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_B_MASK) == NET_IP_ADDR_CLASS_B) { /* Chk invalid Class-B specified host (see Note #1a5A). */ if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_B_MASK_HOST) == (NET_IP_ADDR_THIS_HOST & NET_IP_ADDR_CLASS_B_MASK_HOST)) { *perr = NET_ICMP_ERR_TX_INVALID_ADDR_SRC; return; } } else if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_C_MASK) == NET_IP_ADDR_CLASS_C) { /* Chk invalid Class-C specified host (see Note #1a5A). */ if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_C_MASK_HOST) == (NET_IP_ADDR_THIS_HOST & NET_IP_ADDR_CLASS_C_MASK_HOST)) { *perr = NET_ICMP_ERR_TX_INVALID_ADDR_SRC; return; } } else { /* Discard invalid addr class (see Notes #3 & #4). */ *perr = NET_ICMP_ERR_TX_INVALID_ADDR_SRC; return; } /* ------------------- CHK IP FRAG -------------------- */ ip_flags = pbuf_hdr->IP_Flags_FragOffset & NET_IP_HDR_FLAG_MASK; ip_flag_frags_more = DEF_BIT_IS_SET(ip_flags, NET_IP_HDR_FLAG_FRAG_MORE); if (ip_flag_frags_more != DEF_NO) { /* If 'More Frags' flag set ... */ ip_frag_offset = pbuf_hdr->IP_Flags_FragOffset & NET_IP_HDR_FRAG_OFFSET_MASK; if (ip_frag_offset != NET_IP_HDR_FRAG_OFFSET_NONE) { /* ... & frag offset != 0, ... */ *perr = NET_ICMP_ERR_TX_INVALID_FRAG; /* ... rtn err for non-initial frag (see Note #1a4). */ return; } } /*$PAGE*/ /* ----------------- CHK ICMP ERR MSG ----------------- */ if (pip_hdr->Protocol == NET_IP_HDR_PROTOCOL_ICMP) { /* If rx'd IP datagram is ICMP, ... */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (pbuf_hdr->ICMP_MsgIx == NET_BUF_IX_NONE) { NET_CTR_ERR_INC(NetICMP_ErrRxInvalidBufIxCtr); *perr = NET_BUF_ERR_INVALID_IX; return; } #endif picmp_hdr = (NET_ICMP_HDR *)&pbuf->Data[pbuf_hdr->ICMP_MsgIx]; switch (picmp_hdr->Type) { /* ... chk ICMP msg type & ... */ case NET_ICMP_MSG_TYPE_DEST_UNREACH: case NET_ICMP_MSG_TYPE_SRC_QUENCH: case NET_ICMP_MSG_TYPE_TIME_EXCEED: case NET_ICMP_MSG_TYPE_PARAM_PROB: *perr = NET_ICMP_ERR_TX_INVALID_ERR_MSG; /* ... rtn err for ICMP err msgs (see Note #1a1). */ return; /* Prevent 'break NOT reachable' compiler warning. */ case NET_ICMP_MSG_TYPE_ECHO_REQ: case NET_ICMP_MSG_TYPE_ECHO_REPLY: case NET_ICMP_MSG_TYPE_TS_REQ: case NET_ICMP_MSG_TYPE_TS_REPLY: case NET_ICMP_MSG_TYPE_ADDR_MASK_REPLY: #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) ptr_max_protocol = pbuf_hdr->ICMP_MsgLen; /* See Note #6c. */ #endif break; #if 0 /* ---------------- UNSUPPORTED TYPES ----------------- */ /* See Note #5. */ case NET_ICMP_MSG_TYPE_REDIRECT: case NET_ICMP_MSG_TYPE_ROUTE_REQ: case NET_ICMP_MSG_TYPE_ROUTE_AD: case NET_ICMP_MSG_TYPE_ADDR_MASK_REQ: /* 'break' intentionally omitted; do NOT move from the */ /* ... following case : 'default'. */ #endif default: *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } } else { /* #### See Note #6d. */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) ptr_max_protocol = 0; #endif } /*$PAGE*/ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------- VALIDATE ICMP ERR MSG TYPE/CODE/PTR -------- */ switch (type) { case NET_ICMP_MSG_TYPE_DEST_UNREACH: switch (code) { case NET_ICMP_MSG_CODE_DEST_PROTOCOL: case NET_ICMP_MSG_CODE_DEST_PORT: break; case NET_ICMP_MSG_CODE_DEST_NET: case NET_ICMP_MSG_CODE_DEST_HOST: case NET_ICMP_MSG_CODE_DEST_FRAG_NEEDED: case NET_ICMP_MSG_CODE_DEST_ROUTE_FAIL: case NET_ICMP_MSG_CODE_DEST_NET_UNKNOWN: case NET_ICMP_MSG_CODE_DEST_HOST_UNKNOWN: case NET_ICMP_MSG_CODE_DEST_HOST_ISOLATED: case NET_ICMP_MSG_CODE_DEST_NET_TOS: case NET_ICMP_MSG_CODE_DEST_HOST_TOS: default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_SRC_QUENCH: switch (code) { case NET_ICMP_MSG_CODE_SRC_QUENCH: break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_TIME_EXCEED: switch (code) { case NET_ICMP_MSG_CODE_TIME_EXCEED_TTL: case NET_ICMP_MSG_CODE_TIME_EXCEED_FRAG_REASM: break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_PARAM_PROB: switch (code) { case NET_ICMP_MSG_CODE_PARAM_PROB_IP_HDR: case NET_ICMP_MSG_CODE_PARAM_PROB_OPT_MISSING: /* Validate ICMP Param Prob Msg ptr (see Note #6). */ #if 0 /* See Note #6b. */ if (ptr < NET_ICMP_PTR_IX_BASE) { NET_CTR_ERR_INC(NetICMP_ErrTxHdrPtrCtr); *perr = NET_ICMP_ERR_INVALID_PTR; } #endif ptr_max = pbuf_hdr->IP_HdrLen + ptr_max_protocol; if (ptr >= ptr_max) { NET_CTR_ERR_INC(NetICMP_ErrTxHdrPtrCtr); *perr = NET_ICMP_ERR_INVALID_PTR; } break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_ECHO_REQ: case NET_ICMP_MSG_TYPE_ECHO_REPLY: case NET_ICMP_MSG_TYPE_TS_REQ: case NET_ICMP_MSG_TYPE_TS_REPLY: case NET_ICMP_MSG_TYPE_ADDR_MASK_REPLY: *perr = NET_ICMP_ERR_TX_INVALID_ERR_MSG; return; /* Prevent 'break NOT reachable' compiler warning. */ /*$PAGE*/ #if 0 /* ---------------- UNSUPPORTED TYPES ----------------- */ /* See Note #5. */ case NET_ICMP_MSG_TYPE_REDIRECT: case NET_ICMP_MSG_TYPE_ROUTE_REQ: case NET_ICMP_MSG_TYPE_ROUTE_AD: case NET_ICMP_MSG_TYPE_ADDR_MASK_REQ: /* 'break' intentionally omitted; do NOT move from the */ /* ... following case : 'default'. */ #endif default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } #else /* Prevent compiler warnings. */ (void)&type; (void)&code; (void)&ptr; #endif *perr = NET_ICMP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_TxMsgReqValidate() * * Description : Validate parameters for ICMP Request Message transmit. * * Argument(s) : type ICMP Request Message type (see Note #1) : * * NET_ICMP_MSG_TYPE_ECHO_REQ * NET_ICMP_MSG_TYPE_TS_REQ * NET_ICMP_MSG_TYPE_ADDR_MASK_REQ * * code ICMP Request Message code (see Note #1). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE Transmit parameters successfully validated * for ICMP transmit request message. * NET_ICMP_ERR_INVALID_TYPE Invalid/unknown ICMP message type. * NET_ICMP_ERR_INVALID_CODE Invalid/unknown ICMP message code. * * Return(s) : none. * * Caller(s) : NetICMP_TxMsgReq(). * * Note(s) : (1) See 'net_icmp.h ICMP MESSAGE TYPES & CODES Notes #2 & #3' for supported ICMP message * types & codes. ********************************************************************************************************* */ /*$PAGE*/ static void NetICMP_TxMsgReqValidate (CPU_INT08U type, CPU_INT08U 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 /* --------- VALIDATE ICMP REQ MSG TYPE/CODE ---------- */ switch (type) { case NET_ICMP_MSG_TYPE_ECHO_REQ: switch (code) { case NET_ICMP_MSG_CODE_ECHO_REQ: break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_TS_REQ: switch (code) { case NET_ICMP_MSG_CODE_TS_REQ: break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; case NET_ICMP_MSG_TYPE_ADDR_MASK_REQ: switch (code) { case NET_ICMP_MSG_CODE_ADDR_MASK_REQ: break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrCodeCtr); *perr = NET_ICMP_ERR_INVALID_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } break; default: NET_CTR_ERR_INC(NetICMP_ErrTxHdrTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return; /* Prevent 'break NOT reachable' compiler warning. */ } *perr = NET_ICMP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_TxMsgReply() * * Description : (1) Transmit ICMP Reply Message in response to received ICMP Request Message : * * (a) Process ICMP Reply Message : * * (1) The following ICMP Reply Messages require receive processing : * * (A) Timestamp Reply Message * * (1) "The Receive Timestamp is the time the echoer first touched it on receipt" * (RFC #792, Section 'Timestamp or Timestamp Reply Message : Description'). * * (b) Get buffer for ICMP Reply Message : * * (1) Copy ICMP Request Message into ICMP Reply Message * (2) Initialize ICMP Reply Message buffer controls * * (c) Prepare ICMP Reply Message's IP header : * * (1) RFC #1349, Section 5.1 specifies that "an ICMP reply message is sent with the same * value in the TOS field as was used in the corresponding ICMP request message". * * (2) RFC #1122, Sections 3.2.2.6 & 3.2.2.8 specify that "if a Record Route and/or Time * Stamp option is received in [an ICMP Request, these options] SHOULD be updated ... * and included in the IP header of the ... Reply message". Also "if a Source Route * option is received ... the return route MUST be reversed and used as a Source Route * option for the ... Reply message". * * #### These IP header option requirements for ICMP Reply Messages are NOT yet implemented. * * (d) Prepare ICMP Reply Message : * * (1) Echo Reply Message * * (A) "To form an echo reply message, the source and destination addresses are simply * reversed, the type code changed to [reply], and the checksum recomputed" * (RFC #792, Section 'Echo or Echo Reply Message : Addresses'). * * (2) Timestamp Reply Message * * (A) "The Transmit Timestamp is the time the echoer last touched the message on sending * it" (RFC #792, Section 'Timestamp or Timestamp Reply Message : Description'). * * (B) "To form a timestamp reply message, the source and destination addresses are * simply reversed, the type code changed to [reply], and the checksum recomputed" * (RFC #792, Section 'Timestamp or Timestamp Reply Message : Addresses'). * * (3) Some ICMP Reply Message fields are copied directly from the ICMP Request Message. * * (A) ICMP Reply Message Identification & Sequence Number fields were NOT validated * or converted from network-order to host-order (see 'NetICMP_RxPktValidate() * Notes #1b2C & #1b2D') & therefore do NOT need to be converted from host-order * to network-order. * * (e) Transmit ICMP Reply Message * * (f) Free ICMP Reply Message buffer * * (g) Update transmit statistics * *$PAGE* * Argument(s) : pbuf Pointer to network buffer that received ICMP packet. * ---- Argument checked in NetICMP_Rx(). * * pbuf_hdr Pointer to network buffer header. * -------- Argument validated in NetICMP_Rx(). * * picmp_hdr Pointer to received packet's ICMP header. * --------- Argument validated in NetICMP_Rx()/NetICMP_RxPktValidateBuf(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE ICMP Reply Message successfully transmitted. * * --- RETURNED BY NetICMP_TxPktDiscard() : --- * NET_ERR_TX Transmit error; packet discarded. * * --------- RETURNED BY NetIP_Tx() : --------- * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * Return(s) : none. * * Caller(s) : NetICMP_Rx(). * * Note(s) : (2) Default case already invalidated in NetICMP_RxPktValidate(). However, the default case * is included as an extra precaution in case 'Type' is incorrectly modified. * * (3) (a) "Data received in an ICMP Echo Request MUST be entirely included in the resulting * Echo Reply. However, if sending the Echo Reply requires intentional fragmentation * that is not implemented, the datagram MUST be truncated to maximum transmission * size ... and sent" (RFC #1122, Section 3.2.2.6). * * See also 'net_ip.h Note #1e'. * * (b) In case the maximum network buffer size is smaller than the ICMP message data length, * the ICMP Echo Request Message data should be similarly truncated in order to transmit * the ICMP Echo Reply Message. * * (4) Some buffer controls were previously initialized in NetBuf_Get() when the buffer * was allocated earlier in this function. These buffer controls do NOT need to be * re-initialized but are shown for completeness. * * (5) (a) ICMP message Check-Sum MUST be calculated AFTER the entire ICMP message 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) ICMP message Check-Sum field MUST be cleared to '0' BEFORE the ICMP message * Check-Sum is calculated (see RFC #792, Sections 'Echo or Echo Reply Message : * Checksum' & 'Timestamp or Timestamp Reply Message : Checksum'). * * (c) The ICMP message Check-Sum field is returned in network-order & MUST NOT be re- * converted back to host-order (see 'net_util.c NetUtil_16BitOnesCplChkSumHdrCalc() * Note #3b' & 'net_util.c NetUtil_16BitOnesCplChkSumDataCalc() Note #4b'). * * (6) Network buffer already freed by lower layer; only increment error counter. ********************************************************************************************************* */ /*$PAGE*/ static void NetICMP_TxMsgReply (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, NET_ICMP_HDR *picmp_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 #if 0 /* DISABLED while NOT yet implemented. */ NET_IP_OPT_CFG_ROUTE_TS msg_opt_route_ts; #endif NET_ICMP_HDR_ECHO *picmp_hdr_echo; NET_ICMP_HDR_TS *picmp_hdr_ts; NET_BUF *pmsg_req; NET_BUF *pmsg_reply; NET_BUF_HDR *pmsg_req_hdr; NET_BUF_HDR *pmsg_reply_hdr; NET_IP_OPT_CFG_ROUTE_TS *pmsg_opt_cfg_route_ts; NET_IP_HDR *pip_hdr; NET_BUF_SIZE buf_size_max; CPU_INT16U msg_size_hdr; CPU_INT16U msg_len; CPU_INT16U msg_len_min; CPU_INT16U msg_len_rem; CPU_INT16U msg_ix; CPU_INT16U msg_reply_ix; CPU_INT16U msg_reply_len; CPU_INT16U msg_chk_sum; CPU_INT16U flags; CPU_INT08U *pmsg_req_data; NET_TS ts; NET_IP_TOS TOS; NET_ERR err; /* ------------- PROCESS ICMP REPLY MSGs -------------- */ switch (picmp_hdr->Type) { case NET_ICMP_MSG_TYPE_ECHO_REQ: msg_size_hdr = NET_ICMP_HDR_SIZE_ECHO; msg_len_min = NET_ICMP_MSG_LEN_MIN_ECHO; break; case NET_ICMP_MSG_TYPE_TS_REQ: picmp_hdr_ts = (NET_ICMP_HDR_TS *)picmp_hdr; ts = NetUtil_TS_Get(); /* See Note #1a1A1. */ NET_UTIL_VAL_COPY_SET_NET_32(&picmp_hdr_ts->TS_Rx, &ts); msg_size_hdr = NET_ICMP_HDR_SIZE_TS; msg_len_min = NET_ICMP_MSG_LEN_MIN_TS; break; default: /* See Note #2. */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } /*$PAGE*/ /* -------------- GET ICMP REPLY MSG BUF -------------- */ msg_len = pbuf_hdr->ICMP_MsgLen; /* Adjust req msg len for reply msg len. */ if (msg_len > NET_IP_MTU) { /* If msg len > MTU, ... */ if (picmp_hdr->Type != NET_ICMP_MSG_TYPE_ECHO_REQ) { /* ... for Echo Req Msg ONLY, ... */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); return; } msg_len = NET_IP_MTU; /* ... truncate msg len (see Note #3a). */ } msg_ix = NET_BUF_DATA_TX_IX; buf_size_max = NetBuf_GetMaxSize((NET_BUF *)0, (NET_BUF_SIZE)msg_ix); if ((NET_BUF_SIZE)msg_len > buf_size_max) { /* If msg len > max buf size, ... */ msg_len = (CPU_INT16U)buf_size_max; /* ... truncate msg len (see Note #3b). */ } if (msg_len < msg_len_min) { /* If msg len < min msg len, rtn err. */ NetICMP_TxPktDiscard((NET_BUF *)0, perr); NET_CTR_ERR_INC(NetICMP_ErrTxInvalidLenCtr); return; } pmsg_reply = NetBuf_Get((NET_BUF_SIZE) msg_len, /* Get reply msg buf. */ (NET_BUF_SIZE) msg_ix, (CPU_INT16U ) NET_BUF_FLAG_NONE, (NET_ERR *)&err); if (err != NET_BUF_ERR_NONE) { NetICMP_TxPktDiscard(pmsg_reply, perr); return; } pmsg_req = pbuf; msg_reply_ix = msg_ix; msg_len_rem = msg_len; while ((pmsg_req != (NET_BUF *)0) && (msg_len_rem > 0)) { /* For ALL ICMP req msg pkt bufs, ... */ /* ... copy rx'd ICMP req msg into ICMP reply tx buf. */ pmsg_req_hdr = &pmsg_req->Hdr; pmsg_req_data = &pmsg_req->Data[pmsg_req_hdr->ICMP_MsgIx]; msg_reply_len = pmsg_req_hdr->IP_DataLen; /* Each pkt buf's IP data is ICMP req msg data. */ if (msg_reply_len > msg_len_rem) { /* If req msg pkt buf data len > rem msg len, ... */ msg_reply_len = msg_len_rem; /* ... truncate req msg pkt buf data len. */ } NetBuf_DataWr((NET_BUF *) pmsg_reply, (NET_BUF_SIZE) msg_reply_ix, (NET_BUF_SIZE) msg_reply_len, (CPU_INT08U *) pmsg_req_data, (NET_ERR *)&err); if (err != NET_BUF_ERR_NONE) { NetICMP_TxPktDiscard(pmsg_reply, perr); return; } msg_reply_ix += msg_reply_len; msg_len_rem -= msg_reply_len; pmsg_req = (NET_BUF *)pmsg_req_hdr->NextBufPtr; } #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (msg_len_rem > 0) { /* If entire ICMP req msg NOT copied, rtn err. */ NetICMP_TxPktDiscard(pmsg_reply, perr); NET_CTR_ERR_INC(NetICMP_ErrTxInvalidLenCtr); return; } #endif /* Init reply msg buf ctrls. */ pmsg_reply_hdr = &pmsg_reply->Hdr; pmsg_reply_hdr->ICMP_MsgIx = (CPU_INT16U )msg_ix; pmsg_reply_hdr->ICMP_MsgLen = (CPU_INT16U )msg_len; pmsg_reply_hdr->ICMP_HdrLen = (CPU_INT16U )msg_size_hdr; pmsg_reply_hdr->TotLen = (NET_BUF_SIZE)pmsg_reply_hdr->ICMP_MsgLen; pmsg_reply_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_ICMP; /*$PAGE*/ /* ------------ PREPARE ICMP REPLY IP HDR ------------- */ pip_hdr = (NET_IP_HDR *)&pbuf->Data[pbuf_hdr->IP_HdrIx]; TOS = pip_hdr->TOS; /* See Note #1c1. */ flags = NET_IP_FLAG_NONE; /* See Note #1c2. */ pmsg_opt_cfg_route_ts = (NET_IP_OPT_CFG_ROUTE_TS *)0; /* -------------- PREPARE ICMP REPLY MSG -------------- */ switch (picmp_hdr->Type) { case NET_ICMP_MSG_TYPE_ECHO_REQ: /* See Note #1d1. */ picmp_hdr_echo = (NET_ICMP_HDR_ECHO *)&pmsg_reply->Data[pmsg_reply_hdr->ICMP_MsgIx]; picmp_hdr_echo->Type = NET_ICMP_MSG_TYPE_ECHO_REPLY; #if 0 /* Copied from ICMP req msg (see Note #1d3). */ picmp_hdr_echo->Code = NET_ICMP_MSG_CODE_ECHO; /* See Note #1d3A. */ (void)&picmp_hdr_echo->ID; (void)&picmp_hdr_echo->SeqNbr; #endif /* Calc ICMP msg data len. */ if (pbuf_hdr->ICMP_MsgLen > msg_len_min) { pmsg_reply_hdr->DataIx = (CPU_INT16U )(pmsg_reply_hdr->ICMP_MsgIx + msg_len_min); pmsg_reply_hdr->DataLen = (NET_BUF_SIZE)(pmsg_reply_hdr->ICMP_MsgLen - msg_len_min); #if 0 /* Init'd in NetBuf_Get() [see Note #4]. */ } else { pmsg_reply_hdr->DataIx = NET_BUF_IX_NONE; pmsg_reply_hdr->DataLen = 0; #endif } /* Calc ICMP msg chk sum (see Note #5). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_echo->ChkSum, 0x0000); /* Clr chk sum (see Note #5b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumDataCalc((void *) pmsg_reply, (void *) 0, (CPU_INT16U) 0, (NET_ERR *)&err); NET_UTIL_VAL_COPY_16(&picmp_hdr_echo->ChkSum, &msg_chk_sum); /* Copy chk sum in net order (see Note #5c).*/ break; case NET_ICMP_MSG_TYPE_TS_REQ: /* See Note #1d2. */ picmp_hdr_ts = (NET_ICMP_HDR_TS *)&pmsg_reply->Data[pmsg_reply_hdr->ICMP_MsgIx]; ts = NetUtil_TS_Get(); /* See Note #1d2A. */ NET_UTIL_VAL_COPY_SET_NET_32(&picmp_hdr_ts->TS_Tx, &ts); picmp_hdr_ts->Type = NET_ICMP_MSG_TYPE_TS_REPLY; #if 0 /* Copied from ICMP req msg (see Note #1d3). */ picmp_hdr_ts->Code = NET_ICMP_MSG_CODE_TS; /* See Note #1d3A. */ (void)&picmp_hdr_ts->ID; (void)&picmp_hdr_ts->SeqNbr; #endif /* NULL ICMP msg data len. */ #if 0 /* Init'd in NetBuf_Get() [see Note #4]. */ pmsg_reply_hdr->DataIx = NET_BUF_IX_NONE; pmsg_reply_hdr->DataLen = 0; #endif /* Calc ICMP msg chk sum (see Note #5). */ NET_UTIL_VAL_SET_NET_16(&picmp_hdr_ts->ChkSum, 0x0000); /* Clr chk sum (see Note #5b). */ msg_chk_sum = NetUtil_16BitOnesCplChkSumHdrCalc((void *) picmp_hdr_ts, (CPU_INT16U) pmsg_reply_hdr->ICMP_MsgLen, (NET_ERR *)&err); NET_UTIL_VAL_COPY_16(&picmp_hdr_ts->ChkSum, &msg_chk_sum); /* Copy chk sum in net order (see Note #5c).*/ break; default: /* See Note #2. */ NetICMP_TxPktDiscard(pmsg_reply, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } if (err != NET_UTIL_ERR_NONE) { /* Chk err from NetUtil_16BitOnesCplChkSum()'s. */ NetICMP_TxPktDiscard(pmsg_reply, perr); return; } /*$PAGE*/ /* ---------------- TX ICMP REPLY MSG ----------------- */ NetIP_Tx((NET_BUF *)pmsg_reply, (NET_IP_ADDR)pbuf_hdr->IP_AddrDest, (NET_IP_ADDR)pbuf_hdr->IP_AddrSrc, (NET_IP_TOS )TOS, (NET_IP_TTL )NET_IP_TTL_DFLT, (CPU_INT16U )flags, (void *)pmsg_opt_cfg_route_ts, (NET_ERR *)perr); /* ------ FREE ICMP REPLY MSG / UPDATE TX STATS ------- */ switch (*perr) { case NET_IP_ERR_NONE: NetICMP_TxPktFree(pmsg_reply); NET_CTR_STAT_INC(NetICMP_StatTxMsgCtr); NET_CTR_STAT_INC(NetICMP_StatTxMsgReplyCtr); break; case NET_ERR_TX: NET_CTR_ERR_INC(NetICMP_ErrTxPktDiscardedCtr); /* See Note #6. */ return; /* Prevent 'break NOT reachable' compiler warning. */ case NET_ERR_INIT_INCOMPLETE: default: NetICMP_TxPktDiscard(pmsg_reply, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } *perr = NET_ICMP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_TxPktFree() * * Description : Free network buffer. * * Argument(s) : pbuf Pointer to network buffer. * * Return(s) : none. * * Caller(s) : NetICMP_TxMsgErr(), * NetICMP_TxMsgReq(), * NetICMP_TxMsgReply(). * * Note(s) : (1) (a) Although ICMP Transmit initially requests the network buffer for transmit, * the ICMP layer does NOT maintain a reference to the buffer. * * (b) Also, since 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 ICMP layer MUST not * free the transmit buffer. ********************************************************************************************************* */ static void NetICMP_TxPktFree (NET_BUF *pbuf) { (void)&pbuf; /* Prevent compiler warning (see Note #1). */ } /* ********************************************************************************************************* * NetICMP_TxPktDiscard() * * Description : On any Transmit packet errors, discard packet & buffer. * * 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; packet discarded. * * Return(s) : none. * * Caller(s) : NetICMP_TxMsgErr(), * NetICMP_TxMsgReq(), * NetICMP_TxMsgReply(). * * Note(s) : none. ********************************************************************************************************* */ static void NetICMP_TxPktDiscard (NET_BUF *pbuf, NET_ERR *perr) { NET_CTR *pctr; #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) pctr = (NET_CTR *)&NetICMP_ErrTxPktDiscardedCtr; #else pctr = (NET_CTR *) 0; #endif NetBuf_FreeBuf((NET_BUF *)pbuf, (NET_CTR *)pctr); *perr = NET_ERR_TX; } /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuench() * * Description : When network low-resources status is set, transmit periodic ICMP Source Quench Error * Messages to all individual IP source host addresses sending IP packets to this host * (see 'NetICMP_HandlerRx() Note #1a'). * * (1) Validate IP Source Host Address : * * (a) ICMP Source Quench Error Messages should be transmitted to individual host addresses * ONLY. * * (b) Therefore, ICMP Source Quench Error Messages SHOULD NOT be transmitted to the following * IP source host addresses : * * (1) This Host RFC #1122, Section 3.2.1.3.(a) * (2) Specified Host RFC #1122, Section 3.2.1.3.(b) * * (c) See also 'net_ip.c NetIP_RxPktValidate() Note #9c' for invalid IP source host addresses. * * (2) Search ICMP Transmit Source Quench List for entry with corresponding IP source host address * (see Notes #4a & #4c). * * (3) Transmit ICMP Source Quench Error Message to all individual IP source host addresses sending * IP packets to this host. * * * Argument(s) : pbuf Pointer to network buffer that received an IP packet. * ---- Argument validated in NetICMP_HandlerRx() * by NetIP_Rx(). * * Return(s) : none. * * Caller(s) : NetICMP_HandlerRx(). *$PAGE* * Note(s) : (4) (a) ICMP Transmit Source Quench List totals the number of ICMP Source Quench Error Messages * transmitted to specific IP source host addresses. * * (b) ICMP transmit source quench entries are linked to form an ICMP Transmit Source Quench * List. In the diagram below, the horizontal row represents the list of ICMP transmit * source quench entries. * * (1) 'NetICMP_TxSrcQuenchListHead' points to the head of the list; * 'NetICMP_TxSrcQuenchListTail' points to the tail of the list. * * (2) ICMP transmit source quench entries' 'PrevPtr' & 'NextPtr' doubly-link each * entry to form the ICMP Transmit Source Quench List. * * (c) For any ICMP Transmit Source Quench List lookup, all ICMP transmit source quench * entries are searched in order to find the entry with the appropriate IP address-- * i.e. the entry with the corresponding source host address (see Note #4a). * * (d) New ICMP transmit source quench entries are added at the head of the ICMP Transmit * Source Quench List. This allows faster lookup for recently added entries. * * (e) As ICMP transmit source quench entries are added into the list, older entries migrate * to the tail of the list. If the list is full & a new entry is needed, then the oldest * entry at the tail of the list is removed for allocation. * * (f) The ICMP Transmit Source Quench List is cleared only when the network low-resources * status clears (see 'NetICMP_HandlerRx() Note #1b'). * * * | | * |<------- List of ICMP Transmit Source Quench Entries ------->| * | (see Note #4b) | * * New ICMP entries Oldest entry in ICMP * inserted at head Transmit Source Quench List * (see Note #4d) (see Note #4e) * * | NextPtr | * | (see Note #4b2) | * v | v * | * Head of ICMP ------- ------- v ------- ------- ------- (see Note #4b1) * Transmit Source ---->| |------>| |------>| |------>| |------>| | * Quench List | | | | | | | | | | Tail of ICMP * | |<------| |<------| |<------| |<------| |<---- Transmit Source * (see Note #4b1) ------- ------- ^ ------- ------- ------- Quench List * | * | * PrevPtr * (see Note #4b2) * * * (5) The following IP header fields MUST be decoded &/or converted from network-order to host- * order BEFORE any ICMP Source Quench List search & error message transmit (see 'net_ip.c * NetIP_RxPktValidate() Note #3') : * * (a) Source Address * * (6) (a) See 'net_ip.h IP ADDRESS DEFINES Notes #2, #3, & #4' for supported IP addresses. * * (b) Default case already invalidated in NetIP_RxPktValidate(). However, the default case * is included as an extra precaution in case 'IP_AddrSrc' is incorrectly modified. * * (7) During ICMP transmit source quench entry initialization, some entry values were previously * initialized in NetICMP_HandlerTxSrcQuenchGet() when the entry was allocated from the pool. * These entry values do NOT need to be re-initialized but are shown for completeness. ********************************************************************************************************* */ /*$PAGE*/ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuench (NET_BUF *pbuf) { NET_BUF_HDR *pbuf_hdr; NET_ICMP_TX_SRC_QUENCH *ptx_src_quench; NET_ICMP_TX_SRC_QUENCH *pentry_next; CPU_BOOLEAN found; CPU_BOOLEAN tx_src_quench; NET_ERR err; pbuf_hdr = &pbuf->Hdr; /* ----------- VALIDATE IP SRC ADDR ----------- */ /* See Notes #1 & #5a. */ if (pbuf_hdr->IP_AddrSrc == NET_IP_ADDR_THIS_HOST) { /* Chk 'This Host' (see Note #1b1). */ return; } if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_A_MASK) == NET_IP_ADDR_CLASS_A) { /* Chk Class-A specified host (see Note #1b2). */ if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_A_MASK_HOST) == (NET_IP_ADDR_THIS_HOST & NET_IP_ADDR_CLASS_A_MASK_HOST)) { return; } } else if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_B_MASK) == NET_IP_ADDR_CLASS_B) { /* Chk Class-B specified host (see Note #1b2). */ if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_B_MASK_HOST) == (NET_IP_ADDR_THIS_HOST & NET_IP_ADDR_CLASS_B_MASK_HOST)) { return; } } else if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_C_MASK) == NET_IP_ADDR_CLASS_C) { /* Chk Class-C specified host (see Note #1b2). */ if ((pbuf_hdr->IP_AddrSrc & NET_IP_ADDR_CLASS_C_MASK_HOST) == (NET_IP_ADDR_THIS_HOST & NET_IP_ADDR_CLASS_C_MASK_HOST)) { return; } } else { /* Discard invalid addr class (see Note #6). */ return; } /* ------- SRCH ICMP TX SRC QUENCH LIST ------- */ ptx_src_quench = NetICMP_TxSrcQuenchListHead; /* Start @ ICMP Tx Src Quench List head. */ found = DEF_NO; tx_src_quench = DEF_NO; while ((ptx_src_quench != (NET_ICMP_TX_SRC_QUENCH *)0) && /* Srch ICMP Tx Src Quench List ... */ (found == DEF_NO)) { /* ... until entry found. */ pentry_next = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench->NextPtr; found = ((NET_IP_ADDR)pbuf_hdr->IP_AddrSrc == (NET_IP_ADDR)ptx_src_quench->Addr) ? DEF_YES : DEF_NO; if (found != DEF_YES) { /* If NOT found, adv to next entry. */ ptx_src_quench = pentry_next; } else { ptx_src_quench->TxCtr++; if (ptx_src_quench->TxCtr >= NetICMP_TxSrcQuenchTxTh_nbr) { /* If tx ctr > th, */ tx_src_quench = DEF_YES; /* .. tx ICMP Src Quench Err Msg. */ } } } if (found != DEF_YES) { /* If ICMP tx src quench entry NOT found, ... */ ptx_src_quench = NetICMP_HandlerTxSrcQuenchGet(&err); /* ... get new entry, ... */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (ptx_src_quench == (NET_ICMP_TX_SRC_QUENCH *)0) { return; } #endif /* ... init new entry, ... */ ptx_src_quench->Addr = (NET_IP_ADDR)pbuf_hdr->IP_AddrSrc; #if 0 /* Init'd in NetICMP_HandlerTxSrcQuenchGet() .. */ /* ... (see Note #7). */ ptx_src_quench->TxCtr = 0; /* Init'd in NetICMP_HandlerTxSrcQuenchInsert(). */ ptx_src_quench->PrevPtr = (void *)0; ptx_src_quench->NextPtr = (void *)0; #endif NetICMP_HandlerTxSrcQuenchInsert(ptx_src_quench); /* ... insert new entry into list, & ... */ tx_src_quench = DEF_YES; /* ... tx ICMP Src Quench Err Msg. */ } /*$PAGE*/ /* ------------ TX ICMP SRC QUENCH ERR MSG ------------ */ if (tx_src_quench != DEF_NO) { NetICMP_TxMsgErr(pbuf, NET_ICMP_MSG_TYPE_SRC_QUENCH, NET_ICMP_MSG_CODE_SRC_QUENCH, NET_ICMP_MSG_PTR_NONE, &err); if (err == NET_ICMP_ERR_NONE) { /* If ICMP Src Quench Err Msg successfully tx'd, ... */ ptx_src_quench->TxCtr = 0; /* ... clr tx ctr. */ } else if (found != DEF_YES) { /* Else if new entry, set tx ctr to th val for retry. */ ptx_src_quench->TxCtr = NetICMP_TxSrcQuenchTxTh_nbr; } } } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchClrList() * * Description : Clear ICMP Transmit Source Quench List when network low-resources status clears. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : NetICMP_HandlerRx(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchClrList (void) { NET_ICMP_TX_SRC_QUENCH *ptx_src_quench; NET_ICMP_TX_SRC_QUENCH *pentry_next; ptx_src_quench = NetICMP_TxSrcQuenchListHead; while (ptx_src_quench != (NET_ICMP_TX_SRC_QUENCH *)0) { pentry_next = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench->NextPtr; NetICMP_HandlerTxSrcQuenchFree(ptx_src_quench); ptx_src_quench = pentry_next; } NetICMP_TxSrcQuenchListHead = (NET_ICMP_TX_SRC_QUENCH *)0; NetICMP_TxSrcQuenchListTail = (NET_ICMP_TX_SRC_QUENCH *)0; } #endif /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchClr() * * Description : Clear ICMP transmit source quench entry controls. * * Argument(s) : ptx_src_quench Pointer to an ICMP transmit source quench entry. * -------------- Argument validated in NetICMP_Init(), * NetICMP_HandlerTxSrcQuenchGet(), * NetICMP_HandlerTxSrcQuenchFree(). * * Return(s) : none. * * Caller(s) : NetICMP_Init(), * NetICMP_HandlerTxSrcQuenchGet(), * NetICMP_HandlerTxSrcQuenchFree(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchClr (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench) { ptx_src_quench->PrevPtr = (void *)0; ptx_src_quench->NextPtr = (void *)0; ptx_src_quench->Addr = (NET_IP_ADDR)NET_IP_ADDR_NONE; ptx_src_quench->TxCtr = 0; ptx_src_quench->Flags = NET_ICMP_FLAG_NONE; } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchGet() * * Description : (1) Allocate & initialize an ICMP transmit source quench entry : * * (a) Get an ICMP transmit source quench entry * (b) Validate ICMP transmit source quench entry * (c) Initialize ICMP transmit source quench entry * (d) Update ICMP transmit source quench pool statistics * (e) Return pointer to ICMP transmit source quench entry * OR * Null pointer & error code, on failure * * (2) The ICMP transmit source quench pool is implemented as a stack : * * (a) 'NetICMP_TxSrcQuenchPoolPtr' points to the head of the pool. * * (b) Entries' 'NextPtr's link each entry to form the pool stack. * * (c) Entries are inserted & removed at the head of the pool stack. * * * ICMP transmit source * quench entries * inserted & removed * at the head * (see Note #2c) * * | NextPtr * | (see Note #2b) * v | * | * ICMP Transmit ------- ------- v ------- ------- ------- * Source Quench Pool ---->| |------>| |------>| |------>| |------>| | * Pointer | | | | | | | | | | * | | | | | | | | | | * (see Note #2a) ------- ------- ------- ------- ------- * * | | * |<---- Pool of Free ICMP Transmit Source Quench Entries ----->| * | (see Note #2) | * * * Argument(s) : perr Pointer to variable that will receive the return error code from this function : * * NET_ICMP_ERR_NONE ICMP transmit source quench entry * successfully allocated & initialized. * NET_ICMP_ERR_NONE_AVAIL NO available entries to allocate. * NET_ICMP_ERR_INVALID_TYPE ICMP transmit source quench entry is NOT * a valid entry type. * * Return(s) : Pointer to ICMP transmit source quench entry, if NO errors. * * Pointer to NULL, otherwise. * * Caller(s) : NetICMP_HandlerTxSrcQuench(). * * Note(s) : (3) (a) ICMP transmit source quench pool is accessed by 'NetICMP_TxSrcQuenchPoolPtr' during * execution of * * (1) NetICMP_Init() * (2) NetICMP_HandlerTxSrcQuenchGet() * (3) NetICMP_HandlerTxSrcQuenchFree() * * (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 ICMP transmit source quench pool since no asynchronous access * from other network tasks is possible. * * (4) 'No entry available' case NOT possible during correct operation of the ICMP Transmit * Source Quench List. However, the 'else' case is included as an extra precaution in the * case that the ICMP Transmit Source Quench List is incorrectly modified &/or corrupted. ********************************************************************************************************* */ /*$PAGE*/ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static NET_ICMP_TX_SRC_QUENCH *NetICMP_HandlerTxSrcQuenchGet (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_ICMP_TX_SRC_QUENCH *ptx_src_quench; NET_ERR stat_err; /* ---------- GET ICMP TX SRC QUENCH ---------- */ if (NetICMP_TxSrcQuenchPoolPtr != (NET_ICMP_TX_SRC_QUENCH *)0) { /* If ICMP tx src quench pool NOT empty, */ /* ... get tx src quench entry from pool. */ ptx_src_quench = (NET_ICMP_TX_SRC_QUENCH *)NetICMP_TxSrcQuenchPoolPtr; NetICMP_TxSrcQuenchPoolPtr = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench->NextPtr; /* If ICMP Tx Src Quench List NOT empty, .. */ } else if (NetICMP_TxSrcQuenchListTail != (NET_ICMP_TX_SRC_QUENCH *)0) { /* ... get tx src quench entry from list tail. */ ptx_src_quench = (NET_ICMP_TX_SRC_QUENCH *)NetICMP_TxSrcQuenchListTail; NetICMP_HandlerTxSrcQuenchRemove(ptx_src_quench); ptx_src_quench = (NET_ICMP_TX_SRC_QUENCH *)NetICMP_TxSrcQuenchPoolPtr; NetICMP_TxSrcQuenchPoolPtr = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench->NextPtr; } else { /* Else none avail, rtn err (see Note #4). */ NET_CTR_ERR_INC(NetICMP_ErrNoneAvailCtr); *perr = NET_ICMP_ERR_NONE_AVAIL; return ((NET_ICMP_TX_SRC_QUENCH *)0); } #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------- VALIDATE ICMP TX SRC QUENCH -------- */ if (ptx_src_quench->Type != NET_ICMP_TYPE_TX_SRC_QUENCH) { NetICMP_HandlerTxSrcQuenchDiscard(ptx_src_quench); NET_CTR_ERR_INC(NetICMP_ErrInvalidTypeCtr); *perr = NET_ICMP_ERR_INVALID_TYPE; return ((NET_ICMP_TX_SRC_QUENCH *)0); } #endif /* --------- INIT ICMP TX SRC QUENCH ---------- */ NetICMP_HandlerTxSrcQuenchClr(ptx_src_quench); DEF_BIT_SET(ptx_src_quench->Flags, NET_ICMP_FLAG_USED); /* Set entry as used. */ /* --- UPDATE ICMP TX SRC QUENCH POOL STATS --- */ NetStat_PoolEntryUsedInc(&NetICMP_TxSrcQuenchPoolStat, &stat_err); *perr = NET_ICMP_ERR_NONE; return (ptx_src_quench); /* ---------- RTN ICMP TX SRC QUENCH ---------- */ } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchFree() * * Description : (1) Free an ICMP transmit source quench entry : * * (a) Clear ICMP transmit source quench entry controls * (b) Free ICMP transmit source quench entry back to pool * (c) Update ICMP transmit source quench pool statistics * * * Argument(s) : ptx_src_quench Pointer to an ICMP transmit source quench entry. * -------------- Argument validated in NetICMP_HandlerTxSrcQuenchClrList(), * NetICMP_HandlerTxSrcQuenchRemove(). * * Return(s) : none. * * Caller(s) : NetICMP_HandlerTxSrcQuenchClrList(), * NetICMP_HandlerTxSrcQuenchRemove(). * * Note(s) : (2) #### To prevent freeing an ICMP transmit source quench entry already freed via * previous ICMP transmit source quench free, NetICMP_HandlerTxSrcQuenchFree() * checks the ICMP transmit source quench entry's 'USED' flag BEFORE freeing the * ICMP transmit source quench entry. * * This prevention is only best-effort since any invalid duplicate ICMP transmit * source quench frees MAY be asynchronous to potentially valid ICMP transmit * source quench gets. Thus the invalid ICMP transmit source quench free(s) * MAY corrupt the ICMP transmit source quench entry'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 * ICMP resources from possible corruption since no asynchronous access from other * network tasks is possible. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchFree (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench) { #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_ERR err; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE TYPE ------------------ */ if (ptx_src_quench->Type != NET_ICMP_TYPE_TX_SRC_QUENCH) { NetICMP_HandlerTxSrcQuenchDiscard(ptx_src_quench); NET_CTR_ERR_INC(NetICMP_ErrInvalidTypeCtr); return; } /* --------- VALIDATE ICMP TX SRC QUENCH USED --------- */ used = DEF_BIT_IS_SET(ptx_src_quench->Flags, NET_ICMP_FLAG_USED); if (used != DEF_YES) { /* If ICMP tx src quench NOT used, ... */ NET_CTR_ERR_INC(NetICMP_ErrNotUsedCtr); return; /* ... rtn but do NOT free (see Note #2). */ } #endif /* -------------- CLR ICMP TX SRC QUENCH -------------- */ DEF_BIT_CLR(ptx_src_quench->Flags, NET_ICMP_FLAG_USED); /* Set ICMP tx src quench entry as NOT used. */ #if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED) NetICMP_HandlerTxSrcQuenchClr(ptx_src_quench); #endif /* ------------- FREE ICMP TX SRC QUENCH -------------- */ ptx_src_quench->NextPtr = (void *)NetICMP_TxSrcQuenchPoolPtr; NetICMP_TxSrcQuenchPoolPtr = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench; /* ------- UPDATE ICMP TX SRC QUENCH POOL STATS ------- */ NetStat_PoolEntryUsedDec(&NetICMP_TxSrcQuenchPoolStat, &err); } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchRemove() * * Description : (1) Remove an ICMP transmit source quench entry from the ICMP Transmit Source Quench List : * * (a) Remove ICMP transmit source quench entry from list * (b) Free ICMP transmit source quench entry back to pool * * * Argument(s) : ptx_src_quench Pointer to an ICMP transmit source quench entry. * -------------- Argument validated in NetICMP_HandlerTxSrcQuenchGet(). * * Return(s) : none. * * Caller(s) : NetICMP_HandlerTxSrcQuenchGet(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchRemove (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench) { /* ------- REMOVE ICMP TX SRC QUENCH FROM LIST -------- */ NetICMP_HandlerTxSrcQuenchUnlink(ptx_src_quench); /* ------------- FREE ICMP TX SRC QUENCH -------------- */ NetICMP_HandlerTxSrcQuenchFree(ptx_src_quench); } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchInsert() * * Description : Insert an ICMP transmit source quench entry into the ICMP Transmit Source Quench List at * the head of the list. * * Argument(s) : ptx_src_quench Pointer to an ICMP transmit source quench entry. * -------------- Argument checked in NetICMP_HandlerTxSrcQuench(). * * Return(s) : none. * * Caller(s) : NetICMP_HandlerTxSrcQuench(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchInsert (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench) { ptx_src_quench->PrevPtr = (void *)0; ptx_src_quench->NextPtr = (void *)NetICMP_TxSrcQuenchListHead; if (NetICMP_TxSrcQuenchListHead != (NET_ICMP_TX_SRC_QUENCH *)0) { /* If list NOT empty, insert before head. */ NetICMP_TxSrcQuenchListHead->PrevPtr = (void *)ptx_src_quench; } else { /* Else add first entry to list. */ NetICMP_TxSrcQuenchListTail = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench; } NetICMP_TxSrcQuenchListHead = ptx_src_quench; /* Insert entry @ list head. */ } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchUnlink() * * Description : Unlink an ICMP transmit source quench entry from the ICMP Transmit Source Quench List. * * Argument(s) : ptx_src_quench Pointer to an ICMP transmit source quench entry. * -------------- Argument validated in NetICMP_HandlerTxSrcQuenchRemove(). * * Return(s) : none. * * Caller(s) : NetICMP_HandlerTxSrcQuenchRemove(). * * Note(s) : (1) (a) Since NetICMP_HandlerTxSrcQuenchUnlink() called ONLY to remove & free entries from * list tail, it is NOT necessary to implement unlink to remove entry from any position * in the list. However, unlink from any position in the list implemented for correctness * & completeness. * * (b) For a similar reason, it is NOT necessary to clear the entry's previous & next pointers. * However, pointers cleared to NULL shown for correctness & completeness. ********************************************************************************************************* */ #if (NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) static void NetICMP_HandlerTxSrcQuenchUnlink (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench) { NET_ICMP_TX_SRC_QUENCH *pentry_prev; NET_ICMP_TX_SRC_QUENCH *pentry_next; /* --- UNLINK ICMP TX SRC QUENCH FROM LIST ---- */ pentry_prev = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench->PrevPtr; pentry_next = (NET_ICMP_TX_SRC_QUENCH *)ptx_src_quench->NextPtr; /* Point prev entry to next entry. */ if (pentry_prev != (NET_ICMP_TX_SRC_QUENCH *)0) { pentry_prev->NextPtr = (void *)pentry_next; } else { NetICMP_TxSrcQuenchListHead = (NET_ICMP_TX_SRC_QUENCH *)pentry_next; } /* Point next entry to prev entry. */ if (pentry_next != (NET_ICMP_TX_SRC_QUENCH *)0) { pentry_next->PrevPtr = (void *)pentry_prev; } else { NetICMP_TxSrcQuenchListTail = (NET_ICMP_TX_SRC_QUENCH *)pentry_prev; } #if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED) /* Clr ICMP src quench ptrs (see Note #1b). */ ptx_src_quench->PrevPtr = (void *)0; ptx_src_quench->NextPtr = (void *)0; #endif } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetICMP_HandlerTxSrcQuenchDiscard() * * Description : (1) Discard an invalid/corrupted ICMP transmit source quench entry : * * (a) Discard ICMP transmit source quench entry from available pool See Note #2 * (b) Update ICMP transmit source quench pool statistics * * (2) Assumes ICMP transmit source quench entry is invalid/corrupt & MUST be removed. * ICMP transmit source quench entry removed simply by NOT returning the entry back * to the ICMP transmit source quench pool. * * * Argument(s) : pcache Pointer to an invalid/corrupted ICMP transmit source quench entry. * * Return(s) : none. * * Caller(s) : NetICMP_HandlerTxSrcQuenchGet(), * NetICMP_HandlerTxSrcQuenchFree(). * * Note(s) : none. ********************************************************************************************************* */ #if ((NET_ICMP_CFG_TX_SRC_QUENCH_EN == DEF_ENABLED) && \ (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)) static void NetICMP_HandlerTxSrcQuenchDiscard (NET_ICMP_TX_SRC_QUENCH *ptx_src_quench) { #if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif NET_ERR stat_err; /* ------------ DISCARD ICMP TX SRC QUENCH ------------ */ if (ptx_src_quench == (NET_ICMP_TX_SRC_QUENCH *)0) { NET_CTR_ERR_INC(NetICMP_ErrNullPtrCtr); return; } /* --------------- UPDATE DISCARD STATS --------------- */ NetStat_PoolEntryLostInc(&NetICMP_TxSrcQuenchPoolStat, &stat_err); } #endif