/* ********************************************************************************************************* * 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 ARP LAYER * (ADDRESS RESOLUTION PROTOCOL) * * Filename : net_arp.c * Version : V1.89 * Programmer(s) : ITJ ********************************************************************************************************* * Note(s) : (1) Address Resolution Protocol ONLY required for network interfaces that require * network-address-to-hardware-address bindings (see RFC #826 'Abstract'). * * (2) Supports Address Resolution Protocol as described in RFC #826 with the following * restrictions/constraints : * * (a) ONLY supports the following hardware types : * (1) 48-bit Ethernet * * (b) ONLY supports the following protocol types : * (1) 32-bit IP ********************************************************************************************************* */ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #define NET_ARP_MODULE #include /* ********************************************************************************************************* * MODULE * * Note(s) : (1) See 'net_arp.h MODULE'. ********************************************************************************************************* */ #ifdef NET_ARP_MODULE_PRESENT /*$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 NetARP_RxPktValidateBuf (NET_BUF_HDR *pbuf_hdr, NET_ERR *perr); #endif static void NetARP_RxPktValidate (NET_BUF_HDR *pbuf_hdr, NET_ARP_HDR *parp_hdr, NET_ERR *perr); static void NetARP_RxPktCacheUpdate (NET_ARP_HDR *parp_hdr, NET_ERR *perr); static void NetARP_RxPktReply (NET_ARP_HDR *parp_hdr, NET_ERR *perr); static void NetARP_RxPktIsTargetThisHost(NET_ARP_HDR *parp_hdr, NET_ERR *perr); static void NetARP_RxPktFree (NET_BUF *pbuf); static void NetARP_RxPktDiscard (NET_BUF *pbuf, NET_ERR *perr); /* --------------- TX FNCTS --------------- */ static void NetARP_Tx (CPU_INT08U *paddr_hw_sender, CPU_INT08U *paddr_hw_target, CPU_INT08U *paddr_protocol_sender, CPU_INT08U *paddr_protocol_target, CPU_INT16U op_code, NET_ERR *perr); static void NetARP_TxReq (NET_ARP_CACHE *pcache); static void NetARP_TxReply (NET_ARP_HDR *parp_hdr); static void NetARP_TxPktPrepareHdr (NET_BUF *pbuf, CPU_INT16U msg_ix, CPU_INT08U *paddr_hw_sender, CPU_INT08U *paddr_hw_target, CPU_INT08U *paddr_protocol_sender, CPU_INT08U *paddr_protocol_target, CPU_INT16U op_code, NET_ERR *perr); static void NetARP_TxPktFree (NET_BUF *pbuf); static void NetARP_TxPktDiscard (NET_BUF *pbuf, NET_ERR *perr); /*$PAGE*/ /* ----------- ARP CACHE FNCTS ------------ */ static void NetARP_CacheTxPktHandler (NET_BUF *pbuf_q, CPU_INT08U *paddr_hw); static NET_ARP_CACHE *NetARP_CacheSrch (CPU_INT08U *paddr_protocol); static void NetARP_CacheAddPend (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, CPU_INT08U *paddr_protocol, NET_ERR *perr); static void NetARP_CacheAddResolved (CPU_INT08U *paddr_hw, CPU_INT08U *paddr_protocol, NET_ERR *perr); static void NetARP_CacheRemove (NET_ARP_CACHE *pcache, CPU_BOOLEAN tmr_free); static void NetARP_CacheInsert (NET_ARP_CACHE *pcache); static void NetARP_CacheUnlink (NET_ARP_CACHE *pcache); static void NetARP_CacheUnlinkBuf (NET_BUF *pbuf); static void NetARP_CacheReqTimeout (void *pcache_timeout); static void NetARP_CacheTimeout (void *pcache_timeout); static NET_ARP_CACHE *NetARP_CacheCfg (CPU_INT08U *paddr_hw, CPU_INT08U *paddr_protocol, CPU_FNCT_PTR timeout_fnct, NET_TMR_TICK timeout_tick, NET_ERR *perr); static NET_ARP_CACHE *NetARP_CacheGet (NET_ERR *perr); static void NetARP_CacheFree (NET_ARP_CACHE *pcache, CPU_BOOLEAN tmr_free); static void NetARP_CacheClr (NET_ARP_CACHE *pcache); #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static CPU_BOOLEAN NetARP_CacheIsUsed (NET_ARP_CACHE *pcache); static void NetARP_CacheDiscard (NET_ARP_CACHE *pcache); #endif /* ********************************************************************************************************* * LOCAL CONFIGURATION ERRORS ********************************************************************************************************* */ /*$PAGE*/ /* ********************************************************************************************************* * NetARP_Init() * * Description : (1) Initialize Address Resolution Protocol : * * (a) Initialize ARP cache pool * (b) Initialize ARP cache table * (c) Initialize ARP cache list pointers * (d) Initialize ARP host address pointers * (e) Initialize ARP statistics & error counters * * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : NetIF_Init(). * * This function is a network protocol suite to network interface (IF) function & SHOULD be * called only by appropriate network interface initialization function(s). * * Note(s) : (2) ARP cache pool MUST be initialized PRIOR to initializing the pool with pointers to * ARP caches. ********************************************************************************************************* */ void NetARP_Init (void) { NET_ARP_CACHE *pcache; NET_ARP_CACHE_QTY i; NET_ERR stat_err; /* ------------ INIT ARP CACHE POOL/STATS ------------- */ NetARP_CachePoolPtr = (NET_ARP_CACHE *)0; /* Init-clr ARP cache pool (see Note #2). */ NetStat_PoolInit((NET_STAT_POOL *)&NetARP_CachePoolStat, (NET_STAT_POOL_QTY) NET_ARP_CFG_NBR_CACHE, (NET_ERR *)&stat_err); #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) NetARP_CacheSrchCtr_lo = 0; NetARP_CacheSrchCtr_hi = 0; NetARP_CacheFoundCtr_lo = 0; NetARP_CacheFoundCtr_hi = 0; NetARP_CacheFoundPct = 0; #endif /* ---------------- INIT ARP CACHE TBL ---------------- */ pcache = &NetARP_CacheTbl[0]; for (i = 0; i < NET_ARP_CFG_NBR_CACHE; i++) { /* Init each ARP cache type/addr len--NEVER modify. */ pcache->Type = NET_ARP_TYPE_CACHE; pcache->HW_Type = NET_ARP_CFG_HW_TYPE; pcache->HW_AddrLen = NET_ARP_CFG_HW_ADDR_LEN; pcache->ProtocolType = NET_ARP_CFG_PROTOCOL_TYPE; pcache->ProtocolAddrLen = NET_ARP_CFG_PROTOCOL_ADDR_LEN; pcache->State = NET_ARP_CACHE_STATE_FREE; /* Init each ARP cache as free/NOT used. */ pcache->Flags = NET_ARP_FLAG_NONE; #if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED) NetARP_CacheClr(pcache); #endif /* Free each ARP cache to cache pool (see Note #2). */ pcache->NextPtr = (void *)NetARP_CachePoolPtr; NetARP_CachePoolPtr = (NET_ARP_CACHE *)pcache; pcache++; } /* ------------- INIT ARP CACHE LIST PTRS ------------- */ NetARP_CacheListHead = (NET_ARP_CACHE *)0; NetARP_CacheListTail = (NET_ARP_CACHE *)0; /* ------------- INIT ARP HOST ADDR PTRS ------------- */ NetARP_HostAddrPtrHW = NetARP_GetHostAddrPtrHW(); NetARP_HostAddrPtrProtocol = NetARP_GetHostAddrPtrProtocol(); /*$PAGE*/ /* ------------- INIT ARP STAT & ERR CTRS ------------- */ #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) NetARP_StatRxPktCtr = 0; NetARP_StatRxMsgProcessedCtr = 0; NetARP_StatRxMsgReqProcessedCtr = 0; NetARP_StatRxMsgReplyProcessedCtr = 0; NetARP_StatTxMsgCtr = 0; NetARP_StatTxMsgReqCtr = 0; NetARP_StatTxMsgReplyCtr = 0; #endif #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) NetARP_ErrNoneAvailCtr = 0; NetARP_ErrRxHdrHW_TypeCtr = 0; NetARP_ErrRxHdrHW_AddrLenCtr = 0; NetARP_ErrRxHdrHW_AddrCtr = 0; NetARP_ErrRxHdrProtocolTypeCtr = 0; NetARP_ErrRxHdrProtocolAddrLenCtr = 0; NetARP_ErrRxHdrProtocolAddrCtr = 0; NetARP_ErrRxHdrOpCodeCtr = 0; NetARP_ErrRxHdrOpAddrCtr = 0; NetARP_ErrRxHdrMsgLenCtr = 0; NetARP_ErrRxPktTargetReplyCtr = 0; NetARP_ErrRxPktTargetNotThisHostCtr = 0; NetARP_ErrRxPktDiscardedCtr = 0; NetARP_ErrTxPktDiscardedCtr = 0; #if ((NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) || \ (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED)) NetARP_ErrNullPtrCtr = 0; #endif #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) NetARP_ErrInvalidAddrLenHW_Ctr = 0; NetARP_ErrInvalidAddrLenProtocolCtr = 0; #endif #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) NetARP_ErrNotUsedCtr = 0; NetARP_ErrInvalidTypeCtr = 0; NetARP_ErrRxInvalidBufIxCtr = 0; NetARP_ErrTxHdrOpCodeCtr = 0; #endif #endif } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CfgCacheTimeout() * * Description : Configure ARP cache timeout from ARP Cache List. * * Argument(s) : timeout_sec Desired value for ARP cache timeout (in seconds). * * Return(s) : DEF_OK, ARP cache timeout 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) : (1) RFC #1122, Section 2.3.2.1 states that "an implementation of the Address Resolution * Protocol (ARP) ... MUST provide a mechanism to flush out-of-date cache entries. If * this mechanism involves a timeout, it SHOULD be possible to configure the timeout * value". * * (2) Timeout in seconds converted to 'NET_TMR_TICK' ticks in order to pre-compute initial * timeout value in 'NET_TMR_TICK' ticks. ********************************************************************************************************* */ CPU_BOOLEAN NetARP_CfgCacheTimeout (CPU_INT16U timeout_sec) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif NET_TMR_TICK tick; #if (NET_ARP_CACHE_TIMEOUT_MIN_SEC > DEF_INT_16U_MIN_VAL) if (timeout_sec < NET_ARP_CACHE_TIMEOUT_MIN_SEC) { timeout_sec = NET_ARP_CACHE_TIMEOUT_MIN_SEC; } #endif #if (NET_ARP_CACHE_TIMEOUT_MAX_SEC < DEF_INT_16U_MAX_VAL) if (timeout_sec > NET_ARP_CACHE_TIMEOUT_MAX_SEC) { timeout_sec = NET_ARP_CACHE_TIMEOUT_MAX_SEC; } #endif tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC; CPU_CRITICAL_ENTER(); NetARP_CacheTimeout_sec = timeout_sec; NetARP_CacheTimeout_tick = tick; CPU_CRITICAL_EXIT(); return (DEF_OK); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CfgCacheAccessedTh() * * Description : Configure ARP cache accessed-promotion threshold. * * Argument(s) : nbr_access Desired number of ARP cache accesses before ARP cache is promoted. * * Return(s) : DEF_OK, ARP cache promotion 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. ********************************************************************************************************* */ CPU_BOOLEAN NetARP_CfgCacheAccessedTh (CPU_INT16U nbr_access) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif #if (NET_ARP_CACHE_ACCESSED_TH_MIN > DEF_INT_16U_MIN_VAL) if (nbr_access < NET_ARP_CACHE_ACCESSED_TH_MIN) { nbr_access = NET_ARP_CACHE_ACCESSED_TH_MIN; } #endif #if (NET_ARP_CACHE_ACCESSED_TH_MAX < DEF_INT_16U_MAX_VAL) if (nbr_access > NET_ARP_CACHE_ACCESSED_TH_MAX) { nbr_access = NET_ARP_CACHE_ACCESSED_TH_MAX; } #endif CPU_CRITICAL_ENTER(); NetARP_CacheAccessedTh_nbr = nbr_access; CPU_CRITICAL_EXIT(); return (DEF_OK); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CfgReqTimeout() * * Description : Configure timeout between ARP Request retries. * * Argument(s) : timeout_sec Desired value for ARP Request pending ARP Reply timeout (in seconds). * * Return(s) : DEF_OK, ARP Request timeout 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) : (1) Timeout in seconds converted to 'NET_TMR_TICK' ticks in order to pre-compute initial * timeout value in 'NET_TMR_TICK' ticks. ********************************************************************************************************* */ CPU_BOOLEAN NetARP_CfgReqTimeout (CPU_INT08U timeout_sec) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif NET_TMR_TICK tick; if (timeout_sec < NET_ARP_REQ_RETRY_TIMEOUT_MIN_SEC) { timeout_sec = NET_ARP_REQ_RETRY_TIMEOUT_MIN_SEC; } if (timeout_sec > NET_ARP_REQ_RETRY_TIMEOUT_MAX_SEC) { timeout_sec = NET_ARP_REQ_RETRY_TIMEOUT_MAX_SEC; } tick = (NET_TMR_TICK)timeout_sec * NET_TMR_TIME_TICK_PER_SEC; CPU_CRITICAL_ENTER(); NetARP_ReqTimeout_sec = timeout_sec; NetARP_ReqTimeout_tick = tick; CPU_CRITICAL_EXIT(); return (DEF_OK); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CfgReqMaxRetries() * * Description : Configure ARP Request maximum number of requests. * * Argument(s) : max_nbr_retries Desired maximum number of ARP Request attempts. * * Return(s) : DEF_OK, ARP Request maximum number of attempts 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) : (1) An ARP cache monitors the number of ARP Requests transmitted before receiving an ARP * Reply. In other words, an ARP cache monitors the number of ARP Request attempts. * * However, the maximum number of ARP Requests that each ARP cache is allowed to transmit * is configured in terms of retries. Thus, the total number of attempts is equal to the * configured number of retries plus one (1). ********************************************************************************************************* */ CPU_BOOLEAN NetARP_CfgReqMaxRetries (CPU_INT08U max_nbr_retries) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif #if (NET_ARP_REQ_RETRY_MIN > DEF_INT_08U_MIN_VAL) if (max_nbr_retries < NET_ARP_REQ_RETRY_MIN) { max_nbr_retries = NET_ARP_REQ_RETRY_MIN; } #endif #if (NET_ARP_REQ_RETRY_MAX < DEF_INT_08U_MAX_VAL) if (max_nbr_retries > NET_ARP_REQ_RETRY_MAX) { max_nbr_retries = NET_ARP_REQ_RETRY_MAX; } #endif CPU_CRITICAL_ENTER(); NetARP_ReqMaxAttempts_nbr = max_nbr_retries + 1; /* Set max attempts as max retries + 1 (see Note #1). */ CPU_CRITICAL_EXIT(); return (DEF_OK); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_ProbeAddrOnNet() * * Description : (1) Transmit an ARP Request to probe the local network for a specific protocol address : * * (a) Remove ARP cache with desired protocol address from ARP Cache List, if available * (b) Configure ARP cache : * (1) Get default-configured ARP cache * (2) ARP cache state * (c) Transmit ARP Request to probe local network for desired protocol address * * * (2) NetARP_ProbeAddrOnNet() SHOULD be used in conjunction with NetARP_CacheGetAddrHW() * to determine if a specific protocol address is available on the local network : * * (a) After successfully transmitting an ARP Request to probe the local network & ... * (b) After some time delay(s) [on the order of ARP Request timeouts & retries]; ... * (c) Check ARP Cache for the hardware address of a host on the local network that * corresponds to the desired protocol address. * * See also 'NetARP_CacheGetAddrHW() Note #1'. * * * Argument(s) : paddr_protocol Pointer to protocol address to probe local network (see Note #3). * * addr_protocol_len Length of protocol address (in octets) [see Note #4]. * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE ARP Request successfully transmitted to * probe local network for the desired * protocol address (see Note #2). * NET_ARP_ERR_NULL_PTR Argument 'paddr_protocol' passed a NULL * pointer. * NET_ARP_ERR_INVALID_PROTOCOL_LEN Invalid ARP protocol address length. * * --- RETURNED BY NetARP_CacheCfg() : ---- * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * NET_TMR_ERR_NULL_OBJ Argument 'obj' passed a NULL pointer. * NET_TMR_ERR_NULL_FNCT Argument 'fnct' passed a NULL pointer. * NET_TMR_ERR_NONE_AVAIL NO available timers to allocate. * NET_TMR_ERR_INVALID_TYPE Network timer is NOT a valid timer type. * * Return(s) : none. * * Caller(s) : Application. * * This function is a network protocol suite application interface (API) function & MAY be * called by application function(s). * * Note(s) : (3) 'paddr_protocol' MUST point to a valid protocol address that is in network-order. * * See also 'NetARP_CacheHandler() Note #2e3'. * * (4) The length of the protocol address MUST be equal to NET_ARP_CFG_PROTOCOL_ADDR_LEN * & is included for correctness & completeness. ********************************************************************************************************* */ /*$PAGE*/ void NetARP_ProbeAddrOnNet (CPU_INT08U *paddr_protocol, NET_ARP_ADDR_LEN addr_protocol_len, NET_ERR *perr) { #if ((NET_ERR_CFG_ARG_CHK_EXT_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_ARP_CACHE *pcache; #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* ------------ VALIDATE PROTOCOL ADDR BUF ------------ */ if (paddr_protocol == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } if (addr_protocol_len != NET_ARP_CFG_PROTOCOL_ADDR_LEN) { /* Chk protocol addr len (see Note #4). */ NET_CTR_ERR_INC(NetARP_ErrInvalidAddrLenProtocolCtr); *perr = NET_ARP_ERR_INVALID_PROTOCOL_LEN; return; } #else (void)&addr_protocol_len; /* Prevent compiler warning. */ #endif /* --------- REMOVE PROTOCOL ADDR'S ARP CACHE --------- */ pcache = NetARP_CacheSrch(paddr_protocol); if (pcache != (NET_ARP_CACHE *)0) { /* If protocol addr's ARP cache avail, ... */ NetARP_CacheRemove(pcache, DEF_YES); /* ... remove from ARP Cache List (see Note #1a). */ } /* ------------------ CFG ARP CACHE ------------------- */ pcache = NetARP_CacheCfg((CPU_INT08U *)0, (CPU_INT08U *)paddr_protocol, (CPU_FNCT_PTR)NetARP_CacheReqTimeout, (NET_TMR_TICK)NetARP_ReqTimeout_tick, (NET_ERR *)perr); if (*perr != NET_ARP_ERR_NONE) { return; } pcache->State = NET_ARP_CACHE_STATE_PEND; /* ------- INSERT ARP CACHE INTO ARP CACHE LIST ------- */ NetARP_CacheInsert(pcache); /* -------------------- TX ARP REQ -------------------- */ NetARP_TxReq(pcache); /* Tx ARP req to probe local net for protocol addr. */ *perr = NET_ARP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_Rx() * * Description : (1) Process received ARP packets & update ARP Cache List : * * (a) Validate ARP packet * (b) Update ARP cache * (c) Prepare & transmit an ARP Reply for a received ARP Request * (d) Free ARP packet * (e) Update receive statistics * * * Argument(s) : pbuf Pointer to network buffer that received ARP packet. * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE ARP packet successfully received & processed. * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * ---- RETURNED BY NetARP_RxPktDiscard() : ---- * NET_ERR_RX Receive error; packet discarded. * * Return(s) : none. * * Caller(s) : NetIF_RxPktFrameDemux(). * * This function is a network protocol suite to network interface (IF) function & SHOULD be * called only by appropriate network interface function(s). * * Note(s) : (2) NetARP_Rx() blocked until network initialization completes. ********************************************************************************************************* */ void NetARP_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_ARP_HDR *parp_hdr; #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (Net_InitDone != DEF_YES) { /* If init NOT complete, exit rx (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) { NetARP_RxPktDiscard(pbuf, perr); NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); return; } #endif NET_CTR_STAT_INC(NetARP_StatRxPktCtr); /* ----------------- VALIDATE ARP PKT ----------------- */ pbuf_hdr = &pbuf->Hdr; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) NetARP_RxPktValidateBuf(pbuf_hdr, perr); /* Validate rx'd buf. */ switch (*perr) { case NET_ARP_ERR_NONE: break; case NET_ERR_INVALID_PROTOCOL: case NET_BUF_ERR_INVALID_IX: default: NetARP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } #endif parp_hdr = (NET_ARP_HDR *)&pbuf->Data[pbuf_hdr->ARP_MsgIx]; NetARP_RxPktValidate(pbuf_hdr, parp_hdr, perr); /* Validate rx'd pkt. */ /*$PAGE*/ /* ----------------- UPDATE ARP CACHE ----------------- */ switch (*perr) { /* Chk err from NetARP_RxPktValidate(). */ case NET_ARP_ERR_NONE: NetARP_RxPktCacheUpdate(parp_hdr, perr); break; case NET_ARP_ERR_INVALID_HW_TYPE: case NET_ARP_ERR_INVALID_HW_LEN: case NET_ARP_ERR_INVALID_HW_ADDR: case NET_ARP_ERR_INVALID_PROTOCOL_TYPE: case NET_ARP_ERR_INVALID_PROTOCOL_LEN: case NET_ARP_ERR_INVALID_PROTOCOL_ADDR: case NET_ARP_ERR_INVALID_OP_CODE: case NET_ARP_ERR_INVALID_OP_ADDR: case NET_ARP_ERR_INVALID_LEN_MSG: default: NetARP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } /* ------------------- TX ARP REPLY ------------------- */ switch (*perr) { /* Chk err from NetARP_RxPktCacheUpdate(). */ case NET_ARP_ERR_CACHE_RESOLVED: NetARP_RxPktReply(parp_hdr, perr); break; case NET_ARP_ERR_CACHE_NONE_AVAIL: case NET_ARP_ERR_CACHE_INVALID_TYPE: case NET_ARP_ERR_INVALID_OP_CODE: case NET_ARP_ERR_RX_TARGET_REPLY: case NET_ARP_ERR_RX_TARGET_NOT_THIS_HOST: case NET_TMR_ERR_NULL_OBJ: case NET_TMR_ERR_NULL_FNCT: case NET_TMR_ERR_NONE_AVAIL: case NET_TMR_ERR_INVALID_TYPE: default: NetARP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } /* ---------- FREE ARP PKT / UPDATE RX STATS ---------- */ switch (*perr) { /* Chk err from NetARP_RxPktReply(). */ case NET_ARP_ERR_RX_REQ_TX_REPLY: #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) pctr = &NetARP_StatRxMsgReqProcessedCtr; #endif break; case NET_ARP_ERR_RX_REPLY_TX_PKTS: #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) pctr = &NetARP_StatRxMsgReplyProcessedCtr; #endif break; case NET_ARP_ERR_INVALID_OP_CODE: case NET_ARP_ERR_RX_TARGET_NOT_THIS_HOST: default: NetARP_RxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } NetARP_RxPktFree(pbuf); NET_CTR_STAT_INC(NetARP_StatRxMsgProcessedCtr); NET_CTR_STAT_INC(*pctr); *perr = NET_ARP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheHandler() * * Description : (1) Resolve destination hardware address for transmit data packet : * * (a) Search ARP Cache List for ARP cache with corresponding protocol address * (b) If ARP cache found, handle packet based on ARP cache state : * * (1) PENDING -> Enqueue transmit packet buffer to ARP cache * (2) RESOLVED -> Copy ARP cache's hardware address to data packet; * Return to Network Interface to transmit data packet * * (c) If ARP cache NOT found, allocate new ARP cache in 'PENDING' state (see Note #1b1) * * See 'net_arp.h ARP CACHE STATES' for ARP cache state diagram. * * (2) This ARP cache handler function assumes the following : * * (a) ALL ARP caches in the ARP Cache List are valid [validated by NetARP_CacheGet()] * (b) ANY ARP cache in the 'PENDING' state MAY have already enqueued at LEAST one * transmit packet buffer when ARP cache allocated [see NetARP_CacheGet()] * (c) ALL ARP caches in the 'RESOLVED' state have valid hardware addresses * (d) ALL transmit buffers enqueued on any ARP cache are valid * (e) Buffer's ARP address pointers pre-configured by Network Interface to point to : * * (1) 'ARP_AddrProtocolPtr' Pointer to the protocol address used to * resolve the hardware address * (2) 'ARP_AddrHW_Ptr' Pointer to memory buffer to return the * resolved hardware address * (3) ARP addresses which MUST be in network-order * * * Argument(s) : pbuf Pointer to network buffer to transmit. * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_CACHE_RESOLVED ARP cache resolved & hardware address * successfully copied. * NET_ARP_ERR_CACHE_PEND ARP cache in 'PENDING' state; transmit * buffer enqueued to ARP cache. * NET_ARP_ERR_NULL_PTR Argument 'pbuf' passed a NULL pointer; * OR * 'pbuf's 'ARP_AddrProtocolPtr'/'ARP_AddrHWPtr' * are set as NULL pointers. * * ---- RETURNED BY NetARP_CacheAddPend() : ---- * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * NET_TMR_ERR_NULL_OBJ Argument 'obj' passed a NULL pointer. * NET_TMR_ERR_NULL_FNCT Argument 'fnct' passed a NULL pointer. * NET_TMR_ERR_NONE_AVAIL NO available timers to allocate. * NET_TMR_ERR_INVALID_TYPE Network timer is NOT a valid timer type. * * Return(s) : none. * * Caller(s) : NetIF_Tx(). * * This function is a network protocol suite to network interface (IF) function & SHOULD be * called only by appropriate network interface function(s). * * Note(s) : (3) (a) ARP Cache List is accessed by * * (1) NetARP_CacheHandler() * (2) NetARP_CacheAddPend() via NetARP_CacheInsert() * (3) NetARP_CacheAddResolved() via NetARP_CacheInsert() * (4) NetARP_CacheRemove() via NetARP_CacheUnlink() * (5) NetARP_RxPktCacheUpdate() * (6) ARP cache's 'TMR->Obj' pointer via NetARP_CacheReqTimeout() & * NetARP_CacheTimeout() * * (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 ARP Cache List since no asynchronous access from other network * tasks is possible. * * (4) (a) RFC #1122, Section 2.3.2.2 states that "the link layer SHOULD" ... : * * (1) "Save (rather than discard) ... packets destined to the same unresolved * IP address and" ... * (2) "Transmit the saved packet[s] when the address has been resolved." * * (b) Since ARP Layer is the last layer to handle & queue the transmit network * buffer, it is NOT necessary to increment the network buffer's reference * counter to include the pending ARP cache buffer queue as a new reference * to the network buffer. * * (5) Some buffer controls were previously initialized in NetBuf_Get() when the packet * was received at the network interface layer. These buffer controls do NOT need * to be re-initialized but are shown for completeness. ********************************************************************************************************* */ /*$PAGE*/ void NetARP_CacheHandler (NET_BUF *pbuf, 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 CPU_INT08U *paddr_hw; CPU_INT08U *paddr_protocol; NET_BUF_HDR *pbuf_hdr; NET_BUF_HDR *ptail_buf_hdr; NET_BUF *ptail_buf; NET_ARP_CACHE *pcache; /* ------------------- VALIDATE PTRS ------------------ */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (pbuf == (NET_BUF *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } #endif pbuf_hdr = &pbuf->Hdr; paddr_hw = pbuf_hdr->ARP_AddrHW_Ptr; paddr_protocol = pbuf_hdr->ARP_AddrProtocolPtr; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) if (paddr_hw == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } if (paddr_protocol == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } #endif /* ------------------ SRCH ARP CACHE ------------------ */ pcache = NetARP_CacheSrch(paddr_protocol); if (pcache != (NET_ARP_CACHE *)0) { /* If ARP cache found, chk state. */ switch (pcache->State) { case NET_ARP_CACHE_STATE_PEND: /* If ARP cache pend, append buf onto Q (see Note #4a1).*/ ptail_buf = pcache->BufQ_Tail; if (ptail_buf != (NET_BUF *)0) { /* If Q NOT empty, append buf @ Q tail. */ ptail_buf_hdr = &ptail_buf->Hdr; ptail_buf_hdr->NextSecListPtr = (void *)pbuf; pbuf_hdr->PrevSecListPtr = (void *)ptail_buf; pcache->BufQ_Tail = (NET_BUF *)pbuf; } else { /* Else add buf as first q'd buf. */ pcache->BufQ_Head = (NET_BUF *)pbuf; pcache->BufQ_Tail = (NET_BUF *)pbuf; #if 0 /* Init'd in NetBuf_Get() [see Note #5]. */ pbuf_hdr->PrevSecListPtr = (void *)0; pbuf_hdr->NextSecListPtr = (void *)0; #endif } /* Set ARP cache as unlink fnct/obj. */ pbuf_hdr->UnlinkFnctPtr = (CPU_FNCT_PTR)NetARP_CacheUnlinkBuf; pbuf_hdr->UnlinkObjPtr = (void *)pcache; *perr = NET_ARP_ERR_CACHE_PEND; break; case NET_ARP_CACHE_STATE_RESOLVED: /* If ARP cache resolved, copy hw addr. */ Mem_Copy((void *) paddr_hw, (void *)&pcache->HW_Addr[0], (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); *perr = NET_ARP_ERR_CACHE_RESOLVED; break; case NET_ARP_CACHE_STATE_NONE: case NET_ARP_CACHE_STATE_FREE: default: NetARP_CacheRemove(pcache, DEF_YES); NetARP_CacheAddPend(pbuf, pbuf_hdr, paddr_protocol, perr); break; } } else { /* Else add new ARP cache into ARP Cache List. */ NetARP_CacheAddPend(pbuf, pbuf_hdr, paddr_protocol, perr); } } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheCalcStat() * * Description : (1) Calculate ARP statistics : * * (a) ARP cache found percentage * * * Argument(s) : none. * * Return(s) : ARP cache found percentage, if NO errors, * * NULL cache found percentage, otherwise. * * Caller(s) : Application. * * This function is a network protocol suite application interface (API) function & MAY be * called by application function(s). * * Note(s) : (2) NetARP_CacheCalcStat() blocked until network initialization completes; return NULL * ARP cache found percentage. * * (3) These ARP statistics calculation(s) are potentially expensive operations. Recommended * only from low-priority, background tasks. ********************************************************************************************************* */ CPU_INT08U NetARP_CacheCalcStat (void) { #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif NET_CTR pct_numer_hi; NET_CTR pct_numer_lo; NET_CTR pct_denom_hi; NET_CTR pct_denom_lo; #endif CPU_INT08U pct; #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (Net_InitDone != DEF_YES) { /* If init NOT complete, ... */ return (0); /* ... rtn NULL pct (see Note #2). */ } #endif /* ------------- CALC ARP CACHE FOUND PCT ------------- */ #if (NET_CTR_CFG_STAT_EN == DEF_ENABLED) CPU_CRITICAL_ENTER(); pct_numer_hi = NetARP_CacheFoundCtr_hi; pct_numer_lo = NetARP_CacheFoundCtr_lo; pct_denom_hi = NetARP_CacheSrchCtr_hi; pct_denom_lo = NetARP_CacheSrchCtr_lo; CPU_CRITICAL_EXIT(); pct = NetCtr_CalcPctLarge(pct_numer_hi, pct_numer_lo, pct_denom_hi, pct_denom_lo); CPU_CRITICAL_ENTER(); NetARP_CacheFoundPct = pct; CPU_CRITICAL_EXIT(); #else pct = 0; #endif return (pct); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheGetAddrHW() * * Description : (1) Get hardware address that corresponds to a specific ARP cache's protocol address : * * (a) Search ARP Cache List for ARP cache with desired protocol address * (b) If corresponding ARP cache found, get/return hardware address * * * Argument(s) : paddr_hw Pointer to a memory buffer that will receive the hardware address : * (see Notes #2a & 3a) : * * Hardware address that corresponds to the desired protocol address, * if NO errors. * * Hardware address cleared to all zeros (see Note #2a3), otherwise. * * addr_hw_len_buf Length of hardware address memory buffer (in octets) [see Note #2a1]. * * paddr_protocol Pointer to the specific protocol address to search for corresponding * hardware address (see Note #3b). * * addr_protocol_len Length of protocol address (in octets) [see Note #2b]. * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE Hardware address successfully returned. * NET_ARP_ERR_CACHE_NOT_FOUND ARP cache with corresponding hardware/protocol * address NOT found. * NET_ARP_ERR_CACHE_PEND ARP cache in 'PENDING' state; hardware address * NOT yet resolved (see Note #4). * * NET_ARP_ERR_NULL_PTR Argument(s) 'paddr_hw'/'paddr_protocol' passed * a NULL pointer. * NET_ARP_ERR_INVALID_HW_LEN Invalid ARP hardware address length. * NET_ARP_ERR_INVALID_PROTOCOL_LEN Invalid ARP protocol address length. * * Return(s) : Length of returned hardware address (see Note #2a2), if available. * * 0, otherwise. * * Caller(s) : Application. * * This function is a network protocol suite application interface (API) function & MAY be * called by application function(s). * * Note(s) : (2) (a) (1) The size of the memory buffer that will receive the returned hardware address * MUST be greater than or equal to NET_ARP_CFG_HW_ADDR_LEN. * * (2) The length of any returned hardware address is equal to NET_ARP_CFG_HW_ADDR_LEN. * * (3) Address memory array cleared in case of any error(s). * * (A) Address memory array SHOULD be initialized to return a NULL address PRIOR * to all other validation or function handling in case of any error(s). * * (b) The length of the protocol address MUST be equal to NET_ARP_CFG_PROTOCOL_ADDR_LEN * & is included for correctness & completeness. * * (3) ARP addresses MUST be in network-order : * * (a) 'paddr_hw' hardware address returned in network-order * (b) 'paddr_protocol' MUST point to a protocol address that is in network-order * * See also 'NetARP_CacheHandler() Note #2e3'. * * (4) While an ARP cache is in 'PENDING' state the hardware address is NOT yet resolved, * but MAY be resolved in the near future by an awaited ARP Reply. ********************************************************************************************************* */ /*$PAGE*/ NET_ARP_ADDR_LEN NetARP_CacheGetAddrHW (CPU_INT08U *paddr_hw, NET_ARP_ADDR_LEN addr_hw_len_buf, CPU_INT08U *paddr_protocol, NET_ARP_ADDR_LEN addr_protocol_len, NET_ERR *perr) { #if ((NET_ERR_CFG_ARG_CHK_EXT_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_ARP_ADDR_LEN addr_hw_len; NET_ARP_CACHE *pcache; /* --------------- VALIDATE HW ADDR BUF --------------- */ #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (paddr_hw == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return (0); } #endif /* Clr hw addr (see Note #2a3). */ Mem_Clr((void *)paddr_hw, (CPU_SIZE_T) addr_hw_len_buf); addr_hw_len = NET_ARP_CFG_HW_ADDR_LEN; /* Cfg hw addr len (see Note #2a2). */ #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (addr_hw_len_buf < addr_hw_len) { /* Chk hw addr buf len (see Note #2a1). */ NET_CTR_ERR_INC(NetARP_ErrInvalidAddrLenHW_Ctr); *perr = NET_ARP_ERR_INVALID_HW_LEN; return (0); } #endif #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) /* ------------ VALIDATE PROTOCOL ADDR BUF ------------ */ if (paddr_protocol == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return (0); } if (addr_protocol_len != NET_ARP_CFG_PROTOCOL_ADDR_LEN) { /* Chk protocol addr len (see Note #2b). */ NET_CTR_ERR_INC(NetARP_ErrInvalidAddrLenProtocolCtr); *perr = NET_ARP_ERR_INVALID_PROTOCOL_LEN; return (0); } #else (void)&addr_protocol_len; /* Prevent compiler warning. */ #endif /* ------------------ SRCH ARP CACHE ------------------ */ pcache = NetARP_CacheSrch(paddr_protocol); if (pcache == (NET_ARP_CACHE *)0) { *perr = NET_ARP_ERR_CACHE_NOT_FOUND; return (0); } switch (pcache->State) { case NET_ARP_CACHE_STATE_PEND: /* If ARP cache pend, hw addr NOT yet avail ... */ *perr = NET_ARP_ERR_CACHE_PEND; /* ... (see Note #4). */ return (0); /* Prevent 'break NOT reachable' compiler warning. */ case NET_ARP_CACHE_STATE_RESOLVED: /* If ARP cache resolved, hw addr avail. */ break; case NET_ARP_CACHE_STATE_NONE: case NET_ARP_CACHE_STATE_FREE: default: NetARP_CacheRemove(pcache, DEF_YES); *perr = NET_ARP_ERR_CACHE_NOT_FOUND; return (0); /* Prevent 'break NOT reachable' compiler warning. */ } /* ------------------- GET HW ADDR -------------------- */ Mem_Copy((void *) paddr_hw, (void *)&pcache->HW_Addr[0], (CPU_SIZE_T) addr_hw_len); *perr = NET_ARP_ERR_NONE; return (addr_hw_len); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CachePoolStatGet() * * Description : Get ARP statistics pool. * * Argument(s) : none. * * Return(s) : ARP statistics pool, if NO errors. * * NULL statistics pool, otherwise. * * Caller(s) : Application. * * This function is a network protocol suite application interface (API) function & MAY be * called by application function(s). * * Note(s) : (1) NetARP_CachePoolStatGet() blocked until network initialization completes; return NULL * statistics pool. ********************************************************************************************************* */ NET_STAT_POOL NetARP_CachePoolStatGet (void) { #if (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL) CPU_SR cpu_sr; #endif #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) NET_ERR err; #endif NET_STAT_POOL stat_pool; #if (NET_ERR_CFG_ARG_CHK_EXT_EN == DEF_ENABLED) if (Net_InitDone != DEF_YES) { /* If init NOT complete, ... */ NetStat_PoolClr(&stat_pool, &err); return (stat_pool); /* ... rtn NULL stat pool (see Note #1). */ } #endif CPU_CRITICAL_ENTER(); stat_pool = NetARP_CachePoolStat; CPU_CRITICAL_EXIT(); return (stat_pool); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CachePoolStatResetMaxUsed() * * Description : Reset ARP statistics pool's maximum number of entries used. * * Argument(s) : none. * * Return(s) : none. * * Caller(s) : Application. * * This function is a network protocol suite application interface (API) function & MAY be * called by application function(s). * * Note(s) : none. ********************************************************************************************************* */ void NetARP_CachePoolStatResetMaxUsed (void) { NET_ERR err; NetStat_PoolResetUsedMax(&NetARP_CachePoolStat, &err); } /*$PAGE*/ /* ********************************************************************************************************* ********************************************************************************************************* * LOCAL FUNCTIONS ********************************************************************************************************* ********************************************************************************************************* */ /* ********************************************************************************************************* * NetARP_RxPktValidateBuf() * * Description : Validate received buffer header as ARP protocol. * * Argument(s) : pbuf_hdr Pointer to network buffer header that received ARP packet. * -------- Argument validated in NetARP_Rx(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE Received buffer's ARP header validated. * NET_ERR_INVALID_PROTOCOL Buffer's protocol type is NOT ARP. * NET_BUF_ERR_INVALID_IX Invalid buffer index. * * Return(s) : none. * * Caller(s) : NetARP_Rx(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static void NetARP_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 ARP BUF HDR --------------- */ if (pbuf_hdr->ProtocolHdrType != NET_PROTOCOL_TYPE_ARP) { NET_CTR_ERR_INC(Net_ErrInvalidProtocolCtr); *perr = NET_ERR_INVALID_PROTOCOL; return; } if (pbuf_hdr->ARP_MsgIx == NET_BUF_IX_NONE) { NET_CTR_ERR_INC(NetARP_ErrRxInvalidBufIxCtr); *perr = NET_BUF_ERR_INVALID_IX; return; } *perr = NET_ARP_ERR_NONE; } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetARP_RxPktValidate() * * Description : (1) Validate received ARP packet : * * (a) Convert the following ARP header fields from network-order to host-order : * * (1) Hardware Type * (2) Protocol Type * (3) Operation Code See Note #1aB * * (A) These fields are NOT converted directly in the received packet buffer's * data area but are converted in local or network buffer variables ONLY. * * (B) To avoid storing the ARP operation code in a network buffer variable & * passing an additional pointer to the network buffer header that received * ARP packet, ARP operation code is converted in the following functions : * * (1) NetARP_RxPktValidate() * (2) NetARP_RxPktCacheUpdate() * (3) NetARP_RxPktReply() * (4) NetARP_RxPktIsTargetThisHost() * * (C) Hardware & Protocol Addresses are NOT converted from network-order to * host-order & MUST be accessed as multi-octet arrays. * * (b) Validate the received packet's following ARP header fields : * * (1) Hardware Type * (2) Hardware Address Length * (3) Hardware Address : Sender's * (4) Protocol Type * (5) Protocol Address Length * (6) Protocol Address : Sender's * (7) Operation Code * * (c) Update network buffer's length controls. * * (d) Validate ARP message length : * * (1) The ARP message length is compared to the remaining packet length which should * be identical. * * (2) However, some network interface frame types append 'pad' octets (octets with a * dummy value to be ignored) if the data length for the frame does NOT meet the * frame's required minimum size. Thus, if the ARP message length is NOT greater * than the frame's minimum size, then pad octets were appended & the ARP message * length CANNOT be compared. * * * Argument(s) : pbuf_hdr Pointer to network buffer header that received ARP packet. * -------- Argument validated in NetARP_Rx(). * * parp_hdr Pointer to received packet's ARP header. * -------- Argument validated in NetARP_Rx()/NetARP_RxPktValidateBuf(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE Received packet validated. * NET_ARP_ERR_INVALID_HW_TYPE Invalid ARP hardware type. * NET_ARP_ERR_INVALID_HW_LEN Invalid ARP hardware address length. * NET_ARP_ERR_INVALID_HW_ADDR Invalid ARP hardware address. * NET_ARP_ERR_INVALID_PROTOCOL_TYPE Invalid ARP protocol type. * NET_ARP_ERR_INVALID_PROTOCOL_LEN Invalid ARP protocol address length. * NET_ARP_ERR_INVALID_PROTOCOL_ADDR Invalid ARP protocol address. * NET_ARP_ERR_INVALID_OP_CODE Invalid ARP operation code. * NET_ARP_ERR_INVALID_OP_ADDR Invalid address for ARP operation * (see Note #3). * NET_ARP_ERR_INVALID_LEN_MSG Invalid ARP message length * (see Note #1d). * * Return(s) : none. * * Caller(s) : NetARP_Rx(). * * Note(s) : (2) See RFC #826, Section 'Packet Format' for ARP packet header format. * * (3) (a) An ARP Request SHOULD be transmitted onto the network by broadcast (see RFC #826, * Section 'Packet Generation'). Therefore, any ARP Request NOT received as a broadcast * packet SHOULD be discarded. * * (b) An ARP Reply SHOULD be transmitted directly to the ARP-Requesting host (see RFC #826, * Section 'Packet Reception' algorithm) & SHOULD NOT be broadcast onto the network. * Therefore, any ARP Reply received as a broadcast packet SHOULD be discarded. ********************************************************************************************************* */ /*$PAGE*/ static void NetARP_RxPktValidate (NET_BUF_HDR *pbuf_hdr, NET_ARP_HDR *parp_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_INT16U hw_type; CPU_INT16U protocol_type; CPU_INT16U op_code; CPU_BOOLEAN rx_broadcast; CPU_BOOLEAN valid; /* ------------ VALIDATE ARP HW TYPE/ADDR ------------- */ NET_UTIL_VAL_COPY_GET_NET_16(&hw_type, &parp_hdr->HW_Type); if (hw_type != NET_ARP_CFG_HW_TYPE) { NET_CTR_ERR_INC(NetARP_ErrRxHdrHW_TypeCtr); *perr = NET_ARP_ERR_INVALID_HW_TYPE; return; } if (parp_hdr->HW_AddrLen != NET_ARP_CFG_HW_ADDR_LEN) { NET_CTR_ERR_INC(NetARP_ErrRxHdrHW_AddrLenCtr); *perr = NET_ARP_ERR_INVALID_HW_LEN; return; } valid = NetARP_IsValidAddrHW(&parp_hdr->HW_AddrSender[0]); if (valid != DEF_YES) { NET_CTR_ERR_INC(NetARP_ErrRxHdrHW_AddrCtr); *perr = NET_ARP_ERR_INVALID_HW_ADDR; return; } /* --------- VALIDATE ARP PROTOCOL TYPE/ADDR ---------- */ NET_UTIL_VAL_COPY_GET_NET_16(&protocol_type, &parp_hdr->ProtocolType); if (protocol_type != NET_ARP_CFG_PROTOCOL_TYPE) { NET_CTR_ERR_INC(NetARP_ErrRxHdrProtocolTypeCtr); *perr = NET_ARP_ERR_INVALID_PROTOCOL_TYPE; return; } if (parp_hdr->ProtocolAddrLen != NET_ARP_CFG_PROTOCOL_ADDR_LEN) { NET_CTR_ERR_INC(NetARP_ErrRxHdrProtocolAddrLenCtr); *perr = NET_ARP_ERR_INVALID_PROTOCOL_LEN; return; } valid = NetARP_IsValidAddrProtocol(&parp_hdr->ProtocolAddrSender[0]); if (valid != DEF_YES) { NET_CTR_ERR_INC(NetARP_ErrRxHdrProtocolAddrCtr); *perr = NET_ARP_ERR_INVALID_PROTOCOL_ADDR; return; } /* --------------- VALIDATE ARP OP CODE --------------- */ NET_UTIL_VAL_COPY_GET_NET_16(&op_code, &parp_hdr->OpCode); rx_broadcast = DEF_BIT_IS_SET(pbuf_hdr->Flags, NET_BUF_FLAG_BROADCAST_RX); switch (op_code) { case NET_ARP_HDR_OP_REQ: if (rx_broadcast != DEF_YES) { /* See Note #3a. */ NET_CTR_ERR_INC(NetARP_ErrRxHdrOpAddrCtr); *perr = NET_ARP_ERR_INVALID_OP_ADDR; return; } break; case NET_ARP_HDR_OP_REPLY: if (rx_broadcast != DEF_NO) { /* See Note #3b. */ NET_CTR_ERR_INC(NetARP_ErrRxHdrOpAddrCtr); *perr = NET_ARP_ERR_INVALID_OP_ADDR; return; } break; default: NET_CTR_ERR_INC(NetARP_ErrRxHdrOpCodeCtr); *perr = NET_ARP_ERR_INVALID_OP_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } /*$PAGE*/ /* ----- UPDATE BUF CTRLS / VALIDATE ARP MSG LEN ------ */ pbuf_hdr->ARP_MsgLen = NET_ARP_HDR_SIZE; if (pbuf_hdr->ARP_MsgLen >= pbuf_hdr->IF_DataLenMin) { /* If ARP msg len >= min net IF data size & .. */ if (pbuf_hdr->ARP_MsgLen != pbuf_hdr->DataLen) { /* .. ARP msg len != rem pkt len, .. */ NET_CTR_ERR_INC(NetARP_ErrRxHdrMsgLenCtr); *perr = NET_ARP_ERR_INVALID_LEN_MSG; /* .. rtn err (see Note #1d). */ return; } } pbuf_hdr->DataLen -= (NET_BUF_SIZE)pbuf_hdr->ARP_MsgLen; *perr = NET_ARP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_RxPktCacheUpdate() * * Description : (1) Update an ARP cache based on received ARP packet's sender addresses : * * (a) Verify ARP message's intended target address is this host * (b) Search ARP Cache List * (c) Update ARP cache * * * Argument(s) : parp_hdr Pointer to received packet's ARP header. * -------- Argument validated in NetARP_Rx(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_CACHE_RESOLVED ARP cache resolved & hardware address * successfully copied. * NET_ARP_ERR_RX_TARGET_REPLY ARP Reply received but NO corresponding ARP * cache currently pending for ARP Reply. * * --- RETURNED BY NetARP_CacheAddResolved() : ---- * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * NET_TMR_ERR_NULL_OBJ Argument 'obj' passed a NULL pointer. * NET_TMR_ERR_NULL_FNCT Argument 'fnct' passed a NULL pointer. * NET_TMR_ERR_NONE_AVAIL NO available timers to allocate. * NET_TMR_ERR_INVALID_TYPE Network timer is NOT a valid timer type. * * - RETURNED BY NetARP_RxPktIsTargetThisHost() : - * NET_ARP_ERR_RX_TARGET_NOT_THIS_HOST Received ARP message NOT intended for this host. * NET_ARP_ERR_INVALID_OP_CODE Invalid ARP operation code. * * Return(s) : none. * * Caller(s) : NetARP_Rx(). * * Note(s) : (2) (a) The ARP cache algorithm implies that ALL messages received at the ARP layer automatically * update the ARP Cache List EVEN if this host is NOT the intended target host of a received * ARP message -- but ONLY if an ARP cache for the sender's addresses is already cached (see * RFC #826, Section 'Packet Reception'). However, if NO ARP cache exists for the sender's * addresses, then even the ARP cache algorithm implies that a misdirected or incorrectly * received ARP message is discarded. * * (b) A configurable ARP address filtering feature is provided to selectively filter & discard * ALL misdirected or incorrectly received ARP messages (see 'net_cfg.h ADDRESS RESOLUTION * PROTOCOL LAYER CONFIGURATION') : * * (1) When ENABLED, the ARP address filter discards : * * (A) ALL misdirected, broadcasted, or incorrectly received ARP messages. * * (B) Any ARP Reply received for this host for which NO corresponding ARP cache currently * exists. (Note : Such an ARP Reply may be a legitimate, yet late, ARP Reply to a * pending ARP Request that has timed-out & been removed from the ARP Cache List.) * * (2) When DISABLED, the ARP address filter discards : * * (A) Any misdirected or incorrectly received ARP messages if the sender's address(s) * are NOT already cached. * * (3) (a) RFC # 826, Section 'Related issue' states that "perhaps receiving of a packet from a host * should reset a timeout in the address resolution entry". * * (b) RFC #1122, Section 2.3.2.1 affirms "that this timeout should be restarted when the cache * entry is 'refreshed'". ********************************************************************************************************* */ static void NetARP_RxPktCacheUpdate (NET_ARP_HDR *parp_hdr, NET_ERR *perr) { #if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif #if (NET_ARP_CFG_ADDR_FLTR_EN == DEF_ENABLED) CPU_INT16U op_code; #else CPU_BOOLEAN cache_add; #endif CPU_INT08U *paddr_sender_hw; CPU_INT08U *paddr_sender_protocol; NET_ARP_CACHE *pcache; NET_BUF *pbuf_head; /*$PAGE*/ /* ----------------- CHK TARGET ADDR ------------------ */ NetARP_RxPktIsTargetThisHost(parp_hdr, perr); #if (NET_ARP_CFG_ADDR_FLTR_EN == DEF_ENABLED) if (*perr != NET_ARP_ERR_RX_TARGET_THIS_HOST) { /* Filter misdirected rx'd ARP msgs (see Note #2b1A). */ NET_CTR_ERR_INC(NetARP_ErrRxPktTargetNotThisHostCtr); return; } #else cache_add = (*perr == NET_ARP_ERR_RX_TARGET_THIS_HOST) ? DEF_YES : DEF_NO; #endif /* ------------------ SRCH ARP CACHE ------------------ */ paddr_sender_hw = parp_hdr->HW_AddrSender; paddr_sender_protocol = parp_hdr->ProtocolAddrSender; pcache = NetARP_CacheSrch(paddr_sender_protocol); /* ----------------- UPDATE ARP CACHE ----------------- */ if (pcache != (NET_ARP_CACHE *)0) { /* If ARP cache found, chk state. */ switch (pcache->State) { case NET_ARP_CACHE_STATE_PEND: /* If ARP cache pend, add sender's hw addr, ... */ Mem_Copy((void *)&pcache->HW_Addr[0], (void *) paddr_sender_hw, (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); /* Reset ARP cache tmr (see Note #3). */ NetTmr_Set((NET_TMR *)pcache->TmrPtr, (CPU_FNCT_PTR)NetARP_CacheTimeout, (NET_TMR_TICK)NetARP_CacheTimeout_tick, (NET_ERR *)perr); pbuf_head = pcache->BufQ_Head; pcache->BufQ_Head = (NET_BUF *)0; pcache->BufQ_Tail = (NET_BUF *)0; NetARP_CacheTxPktHandler(pbuf_head, /* ... & handle/tx cache's buf Q. */ paddr_sender_hw); pcache->State = NET_ARP_CACHE_STATE_RESOLVED; *perr = NET_ARP_ERR_CACHE_RESOLVED; break; case NET_ARP_CACHE_STATE_RESOLVED: /* If ARP cache resolved, update sender's hw addr. */ Mem_Copy((void *)&pcache->HW_Addr[0], (void *) paddr_sender_hw, (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); /* Reset ARP cache tmr (see Note #3). */ NetTmr_Set((NET_TMR *)pcache->TmrPtr, (CPU_FNCT_PTR)NetARP_CacheTimeout, (NET_TMR_TICK)NetARP_CacheTimeout_tick, (NET_ERR *)perr); *perr = NET_ARP_ERR_CACHE_RESOLVED; break; case NET_ARP_CACHE_STATE_NONE: case NET_ARP_CACHE_STATE_FREE: default: NetARP_CacheRemove(pcache, DEF_YES); NetARP_CacheAddResolved(paddr_sender_hw, paddr_sender_protocol, perr); break; } } else { /* Else add new ARP cache into ARP Cache List. */ #if (NET_ARP_CFG_ADDR_FLTR_EN == DEF_ENABLED) /* If ARP addr fltr en'd .. */ NET_UTIL_VAL_COPY_GET_NET_16(&op_code, &parp_hdr->OpCode); if (op_code != NET_ARP_HDR_OP_REQ) { /* .. but ARP pkt NOT an ARP Req, .. */ /* .. do NOT add new ARP cache (see Note #2b1B). */ NET_CTR_ERR_INC(NetARP_ErrRxPktTargetReplyCtr); *perr = NET_ARP_ERR_RX_TARGET_REPLY; return; } #else /* If ARP addr fltr dis'd .. */ if (cache_add != DEF_YES) { /* .. & ARP pkt NOT for this host, .. */ /* .. do NOT add new ARP cache (see Note #2b2A). */ NET_CTR_ERR_INC(NetARP_ErrRxPktTargetNotThisHostCtr); return; /* Err rtn'd by NetARP_RxPktIsTargetThisHost(). */ } #endif NetARP_CacheAddResolved(paddr_sender_hw, paddr_sender_protocol, perr); } } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_RxPktReply() * * Description : Reply to any ARP Request received. * * Argument(s) : parp_hdr Pointer to received packet's ARP header. * -------- Argument validated in NetARP_Rx(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_RX_REQ_TX_REPLY ARP Request transmitted. * NET_ARP_ERR_RX_REPLY_TX_PKTS ARP Reply received; pending ARP cache packets * already transmitted (see Note #2). * NET_ARP_ERR_INVALID_OP_CODE Invalid ARP operation code. * * - RETURNED BY NetARP_RxPktIsTargetThisHost() : - * NET_ARP_ERR_RX_TARGET_NOT_THIS_HOST Received ARP message NOT intended for this host. * * Return(s) : none. * * Caller(s) : NetARP_Rx(). * * Note(s) : (1) (a) ARP Request target hardware address already verified as the network interface's broadcast * address in NetARP_RxPktValidate() [see 'NetARP_RxPktValidate() Note #3a']. * * (b) (1) When ARP address filtering is DISABLED, an ARP Reply is transmitted for an ARP Request * ONLY if this host is the intended protocol address target of the ARP Request. * * (2) When ARP address filtering is ENABLED, an ARP Reply is automatically transmitted for an * ARP Request since this host's protocol address was already verified as the target protocol * address in NetARP_RxPktCacheUpdate() [see 'NetARP_RxPktCacheUpdate() Note #2b1']. * * (2) ARP Reply already transmitted the ARP cache's transmit buffer queue in NetARP_RxPktCacheUpdate(); * no further action required. * * (3) Default case already invalidated in NetARP_RxPktValidate(). However, the default case is included * as an extra precaution in case 'OpCode' is incorrectly modified. ********************************************************************************************************* */ static void NetARP_RxPktReply (NET_ARP_HDR *parp_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_INT16U op_code; NET_UTIL_VAL_COPY_GET_NET_16(&op_code, &parp_hdr->OpCode); switch (op_code) { case NET_ARP_HDR_OP_REQ: /* Use rx'd ARP Req to tx ARP Reply. */ #if (NET_ARP_CFG_ADDR_FLTR_EN != DEF_ENABLED) /* See Note #1b1. */ NetARP_RxPktIsTargetThisHost(parp_hdr, perr); if (*perr != NET_ARP_ERR_RX_TARGET_THIS_HOST) { NET_CTR_ERR_INC(NetARP_ErrRxPktTargetNotThisHostCtr); return; } #endif NetARP_TxReply(parp_hdr); *perr = NET_ARP_ERR_RX_REQ_TX_REPLY; break; case NET_ARP_HDR_OP_REPLY: /* See Note #2. */ *perr = NET_ARP_ERR_RX_REPLY_TX_PKTS; break; default: /* See Note #3. */ NET_CTR_ERR_INC(NetARP_ErrRxHdrOpCodeCtr); *perr = NET_ARP_ERR_INVALID_OP_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_RxPktIsTargetThisHost() * * Description : (1) Determine if this host is the intended target of the received ARP message : * * (a) Verify target hardware address * (b) Verify target protocol address * (c) Return target validation * * (2) (a) When ARP address filtering is ENABLED, the target hardware address for the received * ARP message is verified as either : * * (1) The network interface's broadcast address for a received ARP Request * OR * (2) This host's hardware address for a received ARP Reply * * (b) ARP Request target hardware address verified as the network interface's broadcast * address in NetARP_RxPktValidate() [see 'NetARP_RxPktValidate() Note #3a']. * * (c) When ARP address filtering is DISABLED, target hardware address verification required * only for the handling of an ARP Request in NetARP_RxPktReply() [see Note #2b & * 'NetARP_RxPktReply() Note #1b1']. * * See also 'NetARP_RxPktCacheUpdate() Note #2'. * * * Argument(s) : parp_hdr Pointer to received packet's ARP header. * -------- Argument validated in NetARP_Rx(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_RX_TARGET_THIS_HOST Received ARP message intended * for this host. * NET_ARP_ERR_RX_TARGET_NOT_THIS_HOST Received ARP message NOT intended * for this host. * NET_ARP_ERR_INVALID_OP_CODE Invalid ARP operation code. * * Return(s) : none. * * Caller(s) : NetARP_RxPktCacheUpdate(), * NetARP_RxPktReply(). * * Note(s) : (3) Default case already invalidated in NetARP_RxPktValidate(). However, the default case * is included as an extra precaution in case 'OpCode' is incorrectly modified. ********************************************************************************************************* */ /*$PAGE*/ static void NetARP_RxPktIsTargetThisHost (NET_ARP_HDR *parp_hdr, NET_ERR *perr) { #if (NET_ARP_CFG_ADDR_FLTR_EN == DEF_ENABLED) #if ((NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif CPU_INT16U op_code; CPU_INT08U *paddr_target_hw; #endif CPU_INT08U *paddr_target_protocol; CPU_BOOLEAN target_hw; CPU_BOOLEAN target_protocol; /* -------------- VERIFY TARGET HW ADDR --------------- */ #if (NET_ARP_CFG_ADDR_FLTR_EN == DEF_ENABLED) /* See Note #2a. */ NET_UTIL_VAL_COPY_GET_NET_16(&op_code, &parp_hdr->OpCode); switch (op_code) { case NET_ARP_HDR_OP_REQ: /* See Note #2b. */ target_hw = DEF_YES; break; case NET_ARP_HDR_OP_REPLY: paddr_target_hw = parp_hdr->HW_AddrTarget; target_hw = Mem_Cmp((void *)paddr_target_hw, (void *)NetARP_HostAddrPtrHW, (CPU_SIZE_T)NET_ARP_CFG_HW_ADDR_LEN); break; default: /* See Note #3. */ NET_CTR_ERR_INC(NetARP_ErrRxHdrOpCodeCtr); *perr = NET_ARP_ERR_INVALID_OP_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } #else /* See Note #2c. */ target_hw = DEF_YES; #endif /* ----------- VERIFY TARGET PROTOCOL ADDR ------------ */ paddr_target_protocol = parp_hdr->ProtocolAddrTarget; target_protocol = Mem_Cmp((void *)paddr_target_protocol, (void *)NetARP_HostAddrPtrProtocol, (CPU_SIZE_T)NET_ARP_CFG_PROTOCOL_ADDR_LEN); /* -------------- RTN TARGET VALIDATION --------------- */ *perr = ((target_hw == DEF_YES) && (target_protocol == DEF_YES)) ? NET_ARP_ERR_RX_TARGET_THIS_HOST : NET_ARP_ERR_RX_TARGET_NOT_THIS_HOST; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_RxPktFree() * * Description : Free network buffer. * * Argument(s) : pbuf Pointer to network buffer. * * Return(s) : none. * * Caller(s) : NetARP_Rx(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_RxPktFree (NET_BUF *pbuf) { NetBuf_FreeBuf((NET_BUF *)pbuf, (NET_CTR *)0); } /* ********************************************************************************************************* * NetARP_RxPktDiscard() * * Description : On any ARP Receive errors, discard ARP 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_RX Receive error; packet discarded. * * Return(s) : none. * * Caller(s) : NetARP_Rx(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_RxPktDiscard (NET_BUF *pbuf, NET_ERR *perr) { NET_CTR *pctr; #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) pctr = (NET_CTR *)&NetARP_ErrRxPktDiscardedCtr; #else pctr = (NET_CTR *) 0; #endif NetBuf_FreeBuf((NET_BUF *)pbuf, (NET_CTR *)pctr); *perr = NET_ERR_RX; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_Tx() * * Description : (1) Prepare & transmit an ARP Request or ARP Reply : * * (a) Get network buffer for ARP transmit packet * (b) Prepare & transmit packet * (c) Free transmit packet buffer(s) * (d) Update transmit statistics * * * Argument(s) : paddr_hw_sender Pointer to sender's hardware address (see Note #2). * * paddr_hw_target Pointer to target's hardware address (see Note #2). * * paddr_protocol_sender Pointer to sender's protocol address (see Note #2). * * paddr_protocol_target Pointer to target's protocol address (see Note #2). * * op_code ARP operation : Request or Reply. * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE ARP packet successfully transmitted. * NET_ARP_ERR_NULL_PTR Argument(s) passed a NULL pointer. * NET_ARP_ERR_INVALID_OP_CODE Invalid ARP operation code. * * ------- RETURNED BY NetBuf_Get() : ------- * NET_BUF_ERR_NONE_AVAIL NO available buffers to allocate. * NET_BUF_ERR_INVALID_TYPE Network buffer is NOT a valid buffer type. * NET_BUF_ERR_INVALID_SIZE Requested size is greater then the maximum * buffer size available. * * -- RETURNED BY NetARP_TxPktDiscard() : --- * NET_ERR_TX Transmit error; packet discarded. * * -------- RETURNED BY NetIF_Tx() : -------- * NET_ERR_INIT_INCOMPLETE Network initialization NOT complete. * * Return(s) : none. * * Caller(s) : NetARP_TxReq(), * NetARP_TxReply(). * * Note(s) : (2) ARP addresses MUST be in network-order. * * (3) Assumes network buffer's protocol header size is large enough to accomodate ARP header * size (see 'net_buf.h NETWORK BUFFER INDEX & SIZE DEFINES Note #1'). * * (4) Network buffer already freed by lower layer; only increment error counter. ********************************************************************************************************* */ /*$PAGE*/ static void NetARP_Tx (CPU_INT08U *paddr_hw_sender, CPU_INT08U *paddr_hw_target, CPU_INT08U *paddr_protocol_sender, CPU_INT08U *paddr_protocol_target, CPU_INT16U op_code, NET_ERR *perr) { #if (((NET_CTR_CFG_STAT_EN == DEF_ENABLED) || \ (NET_CTR_CFG_ERR_EN == DEF_ENABLED)) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif CPU_INT16U msg_ix; NET_BUF *pbuf; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE PTRS ------------------ */ if (paddr_hw_sender == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); NET_CTR_ERR_INC(NetARP_ErrTxPktDiscardedCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } if (paddr_protocol_sender == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); NET_CTR_ERR_INC(NetARP_ErrTxPktDiscardedCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } if (paddr_protocol_target == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); NET_CTR_ERR_INC(NetARP_ErrTxPktDiscardedCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } /* -------------------- VALIDATE OP ------------------- */ switch (op_code) { case NET_ARP_HDR_OP_REQ: /* For ARP Req, NULL hw addr ptr expected. */ break; case NET_ARP_HDR_OP_REPLY: if (paddr_hw_target == (CPU_INT08U *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); NET_CTR_ERR_INC(NetARP_ErrTxPktDiscardedCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } break; default: NET_CTR_ERR_INC(NetARP_ErrTxHdrOpCodeCtr); NET_CTR_ERR_INC(NetARP_ErrTxPktDiscardedCtr); *perr = NET_ARP_ERR_INVALID_OP_CODE; return; /* Prevent 'break NOT reachable' compiler warning. */ } #endif /*$PAGE*/ /* --------------------- GET BUF ---------------------- */ #if (NET_BUF_DATA_TX_IX < NET_ARP_HDR_SIZE) /* See Note #3. */ NET_CTR_ERR_INC(NetARP_ErrTxInvalidBufIxCtr); return; #endif msg_ix = NET_BUF_DATA_TX_IX - NET_ARP_HDR_SIZE; pbuf = NetBuf_Get((NET_BUF_SIZE)NET_ARP_MSG_LEN_DATA, (NET_BUF_SIZE)msg_ix, (CPU_INT16U )NET_BUF_FLAG_NONE, (NET_ERR *)perr); if (*perr != NET_BUF_ERR_NONE) { return; } /* ---------------- PREPARE/TX ARP PKT ---------------- */ NetARP_TxPktPrepareHdr(pbuf, msg_ix, paddr_hw_sender, paddr_hw_target, paddr_protocol_sender, paddr_protocol_target, op_code, perr); switch (*perr) { case NET_ARP_ERR_NONE: NetIF_Tx(pbuf, perr); break; case NET_ARP_ERR_NULL_PTR: default: NetARP_TxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } /* ---------- FREE TX PKT / UPDATE TX STATS ----------- */ switch (*perr) { /* Chk err from NetIF_Tx(). */ case NET_IF_ERR_NONE: NetARP_TxPktFree(pbuf); NET_CTR_STAT_INC(NetARP_StatTxMsgCtr); *perr = NET_ARP_ERR_NONE; break; case NET_ERR_TX: NET_CTR_ERR_INC(NetARP_ErrTxPktDiscardedCtr); /* See Note #4. */ return; /* Prevent 'break NOT reachable' compiler warning. */ case NET_ERR_INIT_INCOMPLETE: default: NetARP_TxPktDiscard(pbuf, perr); return; /* Prevent 'break NOT reachable' compiler warning. */ } } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_TxReq() * * Description : (1) Prepare & transmit an ARP Request to resolve a pending ARP cache : * * (a) Configure sender's hardware address as this host's hardware address * (b) Configure target's hardware address as NULL since unknown * (c) Configure sender's protocol address as this host's protocol address * (d) Configure target's protocol address as the protocol address listed in the ARP cache * (e) Configure ARP operation as ARP Request * * * Argument(s) : pcache Pointer to an ARP cache. * ------ Argument checked in NetARP_CacheAddPend(), * NetARP_CacheReqTimeout(). * * Return(s) : none. * * Caller(s) : NetARP_CacheAddPend(), * NetARP_CacheReqTimeout(). * * Note(s) : (2) Do NOT need to verify success of ARP Request since failure will cause timeouts & retries. ********************************************************************************************************* */ static void NetARP_TxReq (NET_ARP_CACHE *pcache) { #if ((NET_CTR_CFG_STAT_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif CPU_INT08U *paddr_hw_sender; CPU_INT08U *paddr_hw_target; CPU_INT08U *paddr_protocol_sender; CPU_INT08U *paddr_protocol_target; CPU_INT16U op_code; NET_ERR err_tx; /* Cfg ARP Req from ARP cache data (see Note #1). */ paddr_hw_sender = (CPU_INT08U *) NetARP_HostAddrPtrHW; paddr_hw_target = (CPU_INT08U *) 0; paddr_protocol_sender = (CPU_INT08U *) NetARP_HostAddrPtrProtocol; paddr_protocol_target = (CPU_INT08U *)&pcache->ProtocolAddr[0]; op_code = NET_ARP_HDR_OP_REQ; NetARP_Tx(paddr_hw_sender, paddr_hw_target, paddr_protocol_sender, paddr_protocol_target, op_code, &err_tx); if (err_tx == NET_ARP_ERR_NONE) { NET_CTR_STAT_INC(NetARP_StatTxMsgReqCtr); } pcache->ReqAttemptsCtr++; /* Inc req attempts ctr. */ } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_TxReply() * * Description : (1) Prepare & transmit an ARP Reply in response to an ARP Request : * * (a) Configure sender's hardware address as this host's hardware address * (b) Configure target's hardware address from the ARP Request's sender hardware address * (c) Configure sender's protocol address from the ARP Request's target protocol address * (d) Configure target's protocol address from the ARP Request's sender protocol address * (e) Configure ARP operation as ARP Reply * * * Argument(s) : parp_hdr Pointer to a packet's ARP header. * -------- Argument checked in NetARP_RxPktValidate(). * * Return(s) : none. * * Caller(s) : NetARP_RxPktReply(). * * Note(s) : (2) Do NOT need to verify success of ARP Reply since failure will cause timeouts & retries. ********************************************************************************************************* */ static void NetARP_TxReply (NET_ARP_HDR *parp_hdr) { #if ((NET_CTR_CFG_STAT_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif CPU_INT08U *paddr_hw_sender; CPU_INT08U *paddr_hw_target; CPU_INT08U *paddr_protocol_sender; CPU_INT08U *paddr_protocol_target; CPU_INT16U op_code; NET_ERR err_tx; /* Cfg ARP Reply from ARP Req (see Note #1). */ paddr_hw_sender = (CPU_INT08U *) NetARP_HostAddrPtrHW; paddr_hw_target = (CPU_INT08U *)&parp_hdr->HW_AddrSender[0]; paddr_protocol_sender = (CPU_INT08U *)&parp_hdr->ProtocolAddrTarget[0]; paddr_protocol_target = (CPU_INT08U *)&parp_hdr->ProtocolAddrSender[0]; op_code = NET_ARP_HDR_OP_REPLY; NetARP_Tx(paddr_hw_sender, paddr_hw_target, paddr_protocol_sender, paddr_protocol_target, op_code, &err_tx); if (err_tx == NET_ARP_ERR_NONE) { NET_CTR_STAT_INC(NetARP_StatTxMsgReplyCtr); } } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_TxPktPrepareHdr() * * Description : (1) Prepare ARP packet header : * * (a) Update network buffer's index & length controls. * * (b) Prepare the transmit packet's following ARP header fields : * * (1) Hardware Type * (2) Protocol Type * (3) Hardware Address Length * (4) Protocol Address Length * (5) Operation Code * (6) Sender's Hardware Address * (7) Sender's Protocol Address * (8) Target's Hardware Address * (9) Target's Protocol Address * * (c) Convert the following ARP header fields from host-order to network-order : * * (1) Hardware Type * (2) Protocol Type * (3) Operation Code * * (d) Configure ARP protocol address pointer (see Note #2). * * * Argument(s) : pbuf Pointer to network buffer to prepare ARP packet. * * msg_ix Buffer index to prepare ARP packet. * ------ Argument checked in NetARP_Tx(). * * paddr_hw_sender Pointer to sender's hardware address (see Note #2). * --------------- Argument checked in NetARP_Tx(). * * paddr_hw_target Pointer to target's hardware address (see Note #2). * --------------- Argument checked in NetARP_Tx(). * * paddr_protocol_sender Pointer to sender's protocol address (see Note #2). * --------------------- Argument checked in NetARP_Tx(). * * paddr_protocol_target Pointer to target's protocol address (see Note #2). * --------------------- Argument checked in NetARP_Tx(). * * op_code ARP operation : Request or Reply. * ------- Argument checked in NetARP_Tx(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE ARP packet successfully prepared. * NET_ARP_ERR_NULL_PTR Argument 'pbuf' passed a NULL pointer. * * Return(s) : none. * * Caller(s) : NetARP_Tx(). * * Note(s) : (2) ARP addresses MUST be in network-order. * * (3) Some buffer controls were previously initialized in NetBuf_Get() when the buffer was * allocated. These buffer controls do NOT need to be re-initialized but are shown for * completeness. ********************************************************************************************************* */ /*$PAGE*/ static void NetARP_TxPktPrepareHdr (NET_BUF *pbuf, CPU_INT16U msg_ix, CPU_INT08U *paddr_hw_sender, CPU_INT08U *paddr_hw_target, CPU_INT08U *paddr_protocol_sender, CPU_INT08U *paddr_protocol_target, CPU_INT16U op_code, NET_ERR *perr) { #if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \ (NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif NET_BUF_HDR *pbuf_hdr; NET_ARP_HDR *parp_hdr; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* --------------- VALIDATE PTR --------------- */ if (pbuf == (NET_BUF *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); *perr = NET_ARP_ERR_NULL_PTR; return; } #endif /* ------------- UPDATE BUF CTRLS ------------- */ pbuf_hdr = &pbuf->Hdr; pbuf_hdr->ARP_MsgIx = (CPU_INT16U )msg_ix; pbuf_hdr->ARP_MsgLen = (CPU_INT16U )NET_ARP_HDR_SIZE; pbuf_hdr->TotLen = (NET_BUF_SIZE)pbuf_hdr->ARP_MsgLen; pbuf_hdr->ProtocolHdrType = NET_PROTOCOL_TYPE_ARP; #if 0 /* Init'd in NetBuf_Get() [see Note #3]. */ pbuf_hdr->DataIx = NET_BUF_IX_NONE; pbuf_hdr->DataLen = 0; #endif /* ------------- PREPARE ARP HDR -------------- */ parp_hdr = (NET_ARP_HDR *)&pbuf->Data[pbuf_hdr->ARP_MsgIx]; /* ------ PREPARE ARP HW/PROTOCOL TYPES ------- */ NET_UTIL_VAL_SET_NET_16(&parp_hdr->HW_Type, NET_ARP_CFG_HW_TYPE); NET_UTIL_VAL_SET_NET_16(&parp_hdr->ProtocolType, NET_ARP_CFG_PROTOCOL_TYPE); /* ---- PREPARE ARP HW/PROTOCOL ADDR LENS ----- */ parp_hdr->HW_AddrLen = NET_ARP_CFG_HW_ADDR_LEN; parp_hdr->ProtocolAddrLen = NET_ARP_CFG_PROTOCOL_ADDR_LEN; /* ----------- PREPARE ARP OP CODE ------------ */ NET_UTIL_VAL_COPY_SET_NET_16(&parp_hdr->OpCode, &op_code); /* --- PREPARE ARP HW/PROTOCOL SENDER ADDRS --- */ Mem_Copy((void *)&parp_hdr->HW_AddrSender[0], (void *) paddr_hw_sender, (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); Mem_Copy((void *)&parp_hdr->ProtocolAddrSender[0], (void *) paddr_protocol_sender, (CPU_SIZE_T) NET_ARP_CFG_PROTOCOL_ADDR_LEN); /* --- PREPARE ARP HW/PROTOCOL TARGET ADDRS --- */ if (paddr_hw_target == (CPU_INT08U *)0) { /* If ARP target hw addr NULL for ARP Req, ... */ Mem_Clr( (void *)&parp_hdr->HW_AddrTarget[0], /* .. clr target hw addr octets. */ (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); DEF_BIT_SET(pbuf_hdr->Flags, NET_BUF_FLAG_BROADCAST_TX); /* ARP Req broadcast to ALL hosts on local net. */ } else { /* Else copy target hw addr for ARP Reply. */ Mem_Copy((void *)&parp_hdr->HW_AddrTarget[0], (void *) paddr_hw_target, (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); /* ARP Reply tx'd directly to target host. */ } Mem_Copy((void *)&parp_hdr->ProtocolAddrTarget[0], (void *) paddr_protocol_target, (CPU_SIZE_T) NET_ARP_CFG_PROTOCOL_ADDR_LEN); /* -------- CFG ARP PROTOCOL ADDR PTR --------- */ pbuf_hdr->ARP_AddrProtocolPtr = &parp_hdr->ProtocolAddrTarget[0]; *perr = NET_ARP_ERR_NONE; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_TxPktFree() * * Description : Free network buffer. * * Argument(s) : pbuf Pointer to network buffer. * * Return(s) : none. * * Caller(s) : NetARP_Tx(). * * Note(s) : (1) (a) Although ARP Transmit initially requests the network buffer for transmit, * the ARP 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 ARP layer MUST not * free the transmit buffer. ********************************************************************************************************* */ static void NetARP_TxPktFree (NET_BUF *pbuf) { (void)&pbuf; /* Prevent compiler warning (see Note #1). */ } /* ********************************************************************************************************* * NetARP_TxPktDiscard() * * Description : On any transmit handler 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) : NetARP_Tx(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_TxPktDiscard (NET_BUF *pbuf, NET_ERR *perr) { NET_CTR *pctr; #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) pctr = (NET_CTR *)&NetARP_ErrTxPktDiscardedCtr; #else pctr = (NET_CTR *) 0; #endif NetBuf_FreeBuf((NET_BUF *)pbuf, (NET_CTR *)pctr); *perr = NET_ERR_TX; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheTxPktHandler() * * Description : (1) Transmit packet buffers from ARP cache transmit buffer queue : * * (a) Resolve packet buffer(s)' hardware address(s) * (b) Update packet buffer(s)' unlink/reference values * (c) Transmit packet buffer(s) * * * Argument(s) : pbuf_q Pointer to network buffer(s) to transmit. * * paddr_hw Pointer to sender's hardware address (see Note #2). * -------- Argument checked in NetARP_RxPktCacheUpdate(). * * Return(s) : none. * * Caller(s) : NetARP_RxPktCacheUpdate(). * * Note(s) : (2) ARP addresses MUST be in network-order. * * (3) RFC #1122, Section 2.3.2.2 states that "the link layer SHOULD" ... : * * (a) "Save (rather than discard) ... packets destined to the same unresolved * IP address and" ... * (b) "Transmit the saved packet[s] when the address has been resolved." ********************************************************************************************************* */ static void NetARP_CacheTxPktHandler (NET_BUF *pbuf_q, CPU_INT08U *paddr_hw) { NET_BUF *pbuf_list; NET_BUF *pbuf_list_next; NET_BUF *pbuf; NET_BUF *pbuf_next; NET_BUF_HDR *pbuf_hdr; CPU_INT08U *pbuf_addr_hw; NET_ERR err; pbuf_list = pbuf_q; while (pbuf_list != (NET_BUF *)0) { /* Handle ALL buf lists in Q. */ pbuf_hdr = &pbuf_list->Hdr; pbuf_list_next = (NET_BUF *)pbuf_hdr->NextSecListPtr; pbuf = (NET_BUF *)pbuf_list; while (pbuf != (NET_BUF *)0) { /* Handle ALL bufs in buf list. */ pbuf_hdr = &pbuf->Hdr; pbuf_next = (NET_BUF *)pbuf_hdr->NextBufPtr; pbuf_addr_hw = pbuf_hdr->ARP_AddrHW_Ptr; Mem_Copy((void *)pbuf_addr_hw, /* Copy hw addr into pkt buf. */ (void *)paddr_hw, (CPU_SIZE_T)NET_ARP_CFG_HW_ADDR_LEN); /* Clr buf sec list & unlink ptrs. */ pbuf_hdr->PrevSecListPtr = (void *)0; pbuf_hdr->NextSecListPtr = (void *)0; pbuf_hdr->UnlinkFnctPtr = (CPU_FNCT_PTR)0; pbuf_hdr->UnlinkObjPtr = (void *)0; NetIF_TxPkt(pbuf, &err); /* Tx pkt to IF (see Note #3b). */ pbuf = pbuf_next; } pbuf_list = pbuf_list_next; } } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheSrch() * * Description : Search ARP Cache List for ARP cache with specific protocol address. * * (1) (a) ARP Cache List resolves protocol-address-to-hardware-address bindings based on the * following ARP cache fields : * * - Hardware Type Configured at compile time (see Note #1a1) * - Hardware Address Length Configured at compile time (see Note #1a1) * - Protocol Type Configured at compile time (see Note #1a1) * - Protocol Address Length Configured at compile time (see Note #1a1) * - Protocol Address Generated at run time * * (1) These fields are configured at compile time (see 'net_arp.h ARP CACHE Note #3'). * * (b) ARP caches are linked to form an ARP Cache List. In the diagram below, the * top horizontal row represents the list of ARP caches. * * (1) 'NetARP_CacheListHead' points to the head of the ARP Cache List; * 'NetARP_CacheListTail' points to the tail of the ARP Cache List. * * (2) ARP caches' 'PrevPtr' & 'NextPtr' doubly-link each ARP cache to form the * ARP Cache List. * * (c) ARP caches in the 'PENDING' state are pending hardware address resolution by an * ARP Reply. While in the 'PENDING' state, ALL transmit packet buffers are enqueued * for later transmission when the corresponding ARP Reply is received. * * (1) ARP caches' 'BufQ_Head' points to the head of the pending transmit packet queue; * ARP caches' 'BufQ_Tail' points to the tail of the pending transmit packet queue. * * (2) Buffer's 'PrevSecListPtr' & 'NextSecListPtr' link each buffer in a pending transmit * packet queue. * * (d) For any ARP cache lookup, all ARP caches are searched in order to find the ARP cache * with the appropriate hardware address--i.e. the ARP cache with the corresponding * protocol address (see Note #1a). * * (e) New ARP caches are added at the head of the ARP Cache List. This allows faster ARP * cache lookup for recently added ARP caches. * * (f) As ARP caches are added into the list, older ARP caches migrate to the tail of the * ARP Cache List. Once an ARP cache expires or is discarded, it is removed from the * ARP Cache List. Also if the ARP Cache List is full & a new ARP cache is needed, * then the oldest ARP cache at the tail of the list is removed for allocation. * *$PAGE* * * | | * |<------------ List of ARP Caches ------------->| * | (see Note #1b) | * * New ARP caches Oldest ARP cache * inserted at head in ARP Cache List * (see Note #1e) (see Note #1f) * * | NextPtr | * | (see Note #1b2) | * v | v * | * Head of ------- ------- v ------- ------- (see Note #1b1) * ARP Cache ---->| |------>| |------>| |------>| | * List | | | | | | | | Tail of * | |<------| |<------| |<------| |<---- ARP Cache * (see Note #1b1) ------- ------- ^ ------- ------- List * | | | | | * | | | | | * | ------ PrevPtr | ------ * BufQ_Head ---> | | (see Note #1b2) | | <--- BufQ_Tail * (see Note #1c1) v | v | (see Note #1c1) * --- ------- | ------- | * ^ | | | | | | * | | | | | | | * | | | | | | | * | | | | | | | * | ------- | ------- | * | | ^ | | ^ | * | NextSecListPtr ---> | | | | | <----- PrevSecListPtr * | (see Note #1c2) v | | v | | (see Note #1c2) * | ------- | ------- | * | | | | |<-- * Buffers pending on | | | | | * ARP cache resolution | | | ------- * (see Note #1c) | | | * ------- | * | | ^ | * | | | | * | v | | * | ------- | * | | |<-- * | | | * | | | * v | | * --- ------- * * * Argument(s) : paddr_protocol Pointer to protocol address (see Note #2). * -------------- Argument checked in NetARP_CacheHandler(). * * Return(s) : Pointer to ARP cache with specific protocol address, if found. * * Pointer to NULL, otherwise. * * Caller(s) : NetARP_CacheHandler(). * * Note(s) : (2) 'paddr_protocol' MUST point to a protocol address that is in network-order. * * See also 'NetARP_CacheHandler() Note #2e3'. ********************************************************************************************************* */ /*$PAGE*/ static NET_ARP_CACHE *NetARP_CacheSrch (CPU_INT08U *paddr_protocol) { #if ((NET_CTR_CFG_STAT_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif CPU_BOOLEAN found; NET_ARP_CACHE *pcache; NET_ARP_CACHE *pcache_next; CPU_INT08U *pcache_addr; NET_CTR_STAT_INC_LARGE(NetARP_CacheSrchCtr_hi, NetARP_CacheSrchCtr_lo); pcache = NetARP_CacheListHead; /* Start @ ARP Cache List head. */ found = DEF_NO; while ((pcache != (NET_ARP_CACHE *)0) && /* Srch ARP Cache List ... */ (found == DEF_NO)) { /* ... until cache found. */ pcache_next = (NET_ARP_CACHE *) pcache->NextPtr; pcache_addr = (CPU_INT08U *)&pcache->ProtocolAddr[0]; /* Cmp ARP cache protocol addr. */ found = Mem_Cmp((void *)paddr_protocol, (void *)pcache_addr, (CPU_SIZE_T)NET_ARP_CFG_PROTOCOL_ADDR_LEN); if (found != DEF_YES) { /* If NOT found, adv to next ARP cache. */ pcache = pcache_next; } else { /* Else rtn found ARP cache. */ pcache->AccessedCtr++; if (pcache->AccessedCtr > NetARP_CacheAccessedTh_nbr) { /* If ARP cache accessed > th, & ... */ pcache->AccessedCtr = 0; if (pcache != NetARP_CacheListHead) { /* .. ARP cache NOT @ list head, ... */ NetARP_CacheUnlink(pcache); NetARP_CacheInsert(pcache); /* .. promote ARP cache to list head. */ } } NET_CTR_STAT_INC_LARGE(NetARP_CacheFoundCtr_hi, NetARP_CacheFoundCtr_lo); } } return (pcache); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheAddPend() * * Description : (1) Add a 'PENDING' ARP cache into the ARP Cache List & transmit an ARP Request : * * (a) Configure ARP cache : * (1) Get default-configured ARP cache * (2) ARP cache state * (3) Enqueue transmit buffer to ARP cache queue * (b) Insert ARP cache into ARP Cache List * (c) Transmit ARP Request to resolve ARP cache * * * Argument(s) : pbuf Pointer to network buffer to transmit. * ---- Argument checked in NetARP_CacheHandler(). * * pbuf_hdr Pointer to network buffer header. * -------- Argument validated in NetARP_CacheHandler(). * * paddr_protocol Pointer to protocol address (see Note #2). * -------------- Argument checked in NetARP_CacheHandler(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_CACHE_PEND ARP cache added in 'PENDING' state. * * --- RETURNED BY NetARP_CacheCfg() : ---- * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * NET_TMR_ERR_NULL_OBJ Argument 'obj' passed a NULL pointer. * NET_TMR_ERR_NULL_FNCT Argument 'fnct' passed a NULL pointer. * NET_TMR_ERR_NONE_AVAIL NO available timers to allocate. * NET_TMR_ERR_INVALID_TYPE Network timer is NOT a valid timer type. * * Return(s) : none. * * Caller(s) : NetARP_CacheHandler(). * * Note(s) : (2) Assumes 'paddr_protocol' points to a valid protocol address that is in network-order. * * See also 'NetARP_CacheHandler() Note #2e3'. * * (3) (a) RFC #1122, Section 2.3.2.2 states that "the link layer SHOULD" ... : * * (1) "Save (rather than discard) ... packets destined to the same unresolved * IP address and" ... * (2) "Transmit the saved packet[s] when the address has been resolved." * * (b) Since ARP Layer is the last layer to handle & queue the transmit network * buffer, it is NOT necessary to increment the network buffer's reference * counter to include the pending ARP cache buffer queue as a new reference * to the network buffer. * * (4) Some buffer controls were previously initialized in NetBuf_Get() when the packet * was received at the network interface layer. These buffer controls do NOT need * to be re-initialized but are shown for completeness. ********************************************************************************************************* */ /*$PAGE*/ static void NetARP_CacheAddPend (NET_BUF *pbuf, NET_BUF_HDR *pbuf_hdr, CPU_INT08U *paddr_protocol, NET_ERR *perr) { NET_ARP_CACHE *pcache; /* ------------------ CFG ARP CACHE ------------------- */ pcache = NetARP_CacheCfg((CPU_INT08U *)0, (CPU_INT08U *)paddr_protocol, (CPU_FNCT_PTR)NetARP_CacheReqTimeout, (NET_TMR_TICK)NetARP_ReqTimeout_tick, (NET_ERR *)perr); if (*perr != NET_ARP_ERR_NONE) { return; } /* Cfg buf's unlink fnct/obj to ARP cache. */ pbuf_hdr->UnlinkFnctPtr = (CPU_FNCT_PTR)NetARP_CacheUnlinkBuf; pbuf_hdr->UnlinkObjPtr = (void *)pcache; #if 0 /* Init'd in NetBuf_Get() [see Note #4]. */ pbuf_hdr->PrevSecListPtr = (void *)0; pbuf_hdr->NextSecListPtr = (void *)0; #endif /* Q buf to ARP cache (see Note #3a1). */ pcache->BufQ_Head = (NET_BUF *)pbuf; pcache->BufQ_Tail = (NET_BUF *)pbuf; pcache->State = NET_ARP_CACHE_STATE_PEND; /* ------- INSERT ARP CACHE INTO ARP CACHE LIST ------- */ NetARP_CacheInsert(pcache); /* -------------------- TX ARP REQ -------------------- */ NetARP_TxReq(pcache); /* Tx ARP req to resolve ARP cache. */ *perr = NET_ARP_ERR_CACHE_PEND; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheAddResolved() * * Description : (1) Add a 'RESOLVED' ARP cache into the ARP Cache List : * * (a) Configure ARP cache : * (1) Get default-configured ARP cache * (2) ARP cache state * (b) Insert ARP cache into ARP Cache List * * * Argument(s) : paddr_hw Pointer to hardware address (see Note #2). * -------- Argument checked in NetARP_RxPktCacheUpdate(). * * paddr_protocol Pointer to protocol address (see Note #2). * -------------- Argument checked in NetARP_RxPktCacheUpdate(). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_CACHE_RESOLVED ARP cache added in 'RESOLVED' state. * * --- RETURNED BY NetARP_CacheCfg() : ---- * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * NET_TMR_ERR_NULL_OBJ Argument 'obj' passed a NULL pointer. * NET_TMR_ERR_NULL_FNCT Argument 'fnct' passed a NULL pointer. * NET_TMR_ERR_NONE_AVAIL NO available timers to allocate. * NET_TMR_ERR_INVALID_TYPE Network timer is NOT a valid timer type. * * Return(s) : none. * * Caller(s) : NetARP_RxPktCacheUpdate(). * * Note(s) : (2) Assumes 'paddr_hw' & 'paddr_protocol' point to valid hardware & protocol addresses * that are in network-order. * * See also 'NetARP_CacheHandler() Note #2e3'. ********************************************************************************************************* */ static void NetARP_CacheAddResolved (CPU_INT08U *paddr_hw, CPU_INT08U *paddr_protocol, NET_ERR *perr) { NET_ARP_CACHE *pcache; /* ------------------ CFG ARP CACHE ------------------- */ pcache = NetARP_CacheCfg((CPU_INT08U *)paddr_hw, (CPU_INT08U *)paddr_protocol, (CPU_FNCT_PTR)NetARP_CacheTimeout, (NET_TMR_TICK)NetARP_CacheTimeout_tick, (NET_ERR *)perr); if (*perr != NET_ARP_ERR_NONE) { return; } pcache->State = NET_ARP_CACHE_STATE_RESOLVED; /* ------- INSERT ARP CACHE INTO ARP CACHE LIST ------- */ NetARP_CacheInsert(pcache); *perr = NET_ARP_ERR_CACHE_RESOLVED; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheRemove() * * Description : (1) Remove an ARP cache from the ARP Cache List : * * (a) Remove ARP cache from ARP Cache List * (b) Free ARP cache back to ARP cache pool * * * Argument(s) : pcache Pointer to an ARP cache. * ------ Argument checked in NetARP_CacheHandler(), * NetARP_RxPktCacheUpdate(), * NetARP_CacheGet(), * NetARP_CacheReqTimeout(), * NetARP_CacheTimeout(). * * tmr_free Indicate whether to free network timer : * * DEF_YES Free network timer for ARP cache. * DEF_NO Do NOT free network timer for ARP cache * [Freed by NetTmr_TaskHandler()]. * * Return(s) : none. * * Caller(s) : NetARP_CacheHandler(), * NetARP_RxPktCacheUpdate(), * NetARP_CacheGet(), * NetARP_CacheReqTimeout(), * NetARP_CacheTimeout(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_CacheRemove (NET_ARP_CACHE *pcache, CPU_BOOLEAN tmr_free) { /* ------- REMOVE ARP CACHE FROM ARP CACHE LIST ------- */ NetARP_CacheUnlink(pcache); /* ------------------ FREE ARP CACHE ------------------ */ NetARP_CacheFree(pcache, tmr_free); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheInsert() * * Description : Insert an ARP cache into the ARP Cache List at the head of the list. * * Argument(s) : pcache Pointer to an ARP cache. * ------ Argument checked in NetARP_CacheSrch(), * NetARP_CacheAddPend(), * NetARP_CacheAddResolved(). * * Return(s) : none. * * Caller(s) : NetARP_CacheSrch(), * NetARP_CacheAddPend(), * NetARP_CacheAddResolved(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_CacheInsert (NET_ARP_CACHE *pcache) { pcache->PrevPtr = (void *)0; pcache->NextPtr = (void *)NetARP_CacheListHead; if (NetARP_CacheListHead != (NET_ARP_CACHE *)0) { /* If list NOT empty, insert before head. */ NetARP_CacheListHead->PrevPtr = (void *)pcache; } else { /* Else add first ARP cache to list. */ NetARP_CacheListTail = (NET_ARP_CACHE *)pcache; } NetARP_CacheListHead = pcache; /* Insert ARP cache @ list head. */ } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheUnlink() * * Description : Unlink an ARP cache from the ARP Cache List. * * Argument(s) : pcache Pointer to an ARP cache. * ------ Argument checked in NetARP_CacheSrch(); * NetARP_CacheRemove() * by NetARP_CacheHandler(), * NetARP_CacheGet(), * NetARP_CacheReqTimeout(), * NetARP_CacheTimeout(). * * Return(s) : none. * * Caller(s) : NetARP_CacheSrch(), * NetARP_CacheRemove(). * * Note(s) : (1) Since NetARP_CacheUnlink() called ONLY to remove & then re-link or free ARP caches, * it is NOT necessary to clear the entry's previous & next pointers. However, pointers * cleared to NULL shown for correctness & completeness. ********************************************************************************************************* */ static void NetARP_CacheUnlink (NET_ARP_CACHE *pcache) { NET_ARP_CACHE *pcache_prev; NET_ARP_CACHE *pcache_next; /* ------- UNLINK ARP CACHE FROM ARP CACHE LIST ------- */ pcache_prev = (NET_ARP_CACHE *)pcache->PrevPtr; pcache_next = (NET_ARP_CACHE *)pcache->NextPtr; /* Point prev ARP cache to next ARP cache. */ if (pcache_prev != (NET_ARP_CACHE *)0) { pcache_prev->NextPtr = (void *)pcache_next; } else { NetARP_CacheListHead = (NET_ARP_CACHE *)pcache_next; } /* Point next ARP cache to prev ARP cache. */ if (pcache_next != (NET_ARP_CACHE *)0) { pcache_next->PrevPtr = (void *)pcache_prev; } else { NetARP_CacheListTail = (NET_ARP_CACHE *)pcache_prev; } #if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED) /* Clr ARP cache's ptrs (see Note #1). */ pcache->PrevPtr = (void *)0; pcache->NextPtr = (void *)0; #endif } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheUnlinkBuf() * * Description : Unlink a network buffer from a cache's transmit queue. * * Argument(s) : pbuf Pointer to network buffer enqueued in an ARP cache transmit buffer queue. * * Return(s) : none. * * Caller(s) : Referenced in NetARP_CacheHandler(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_CacheUnlinkBuf (NET_BUF *pbuf) { #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_BUF *pbuf_prev; NET_BUF *pbuf_next; NET_BUF_HDR *pbuf_hdr; NET_BUF_HDR *pbuf_hdr_prev; NET_BUF_HDR *pbuf_hdr_next; NET_ARP_CACHE *pcache; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------- VALIDATE PTR ------------------- */ if (pbuf == (NET_BUF *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); return; } /* ------------------- VALIDATE BUF ------------------- */ used = NetBuf_IsUsed(pbuf); if (used != DEF_YES) { return; } #endif pbuf_hdr = (NET_BUF_HDR *)&pbuf->Hdr; pcache = (NET_ARP_CACHE *) pbuf_hdr->UnlinkObjPtr; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE ARP CACHE ---------------- */ used = NetARP_CacheIsUsed(pcache); if (used != DEF_YES) { return; } #endif /* ---------- UNLINK BUF FROM ARP CACHE TX Q ---------- */ pbuf_prev = (NET_BUF *)pbuf_hdr->PrevSecListPtr; pbuf_next = (NET_BUF *)pbuf_hdr->NextSecListPtr; /* Point prev ARP cache pending tx Q buf to next buf. */ if (pbuf_prev != (NET_BUF *)0) { pbuf_hdr_prev = (NET_BUF_HDR *)&pbuf_prev->Hdr; pbuf_hdr_prev->NextSecListPtr = (void *) pbuf_next; } else { pcache->BufQ_Head = (NET_BUF *) pbuf_next; } /* Point next ARP cache pending tx Q buf to prev buf. */ if (pbuf_next != (NET_BUF *)0) { pbuf_hdr_next = (NET_BUF_HDR *)&pbuf_next->Hdr; pbuf_hdr_next->PrevSecListPtr = (void *) pbuf_prev; } else { pcache->BufQ_Tail = (NET_BUF *) pbuf_prev; } /* -------------- CLR BUF'S UNLINK CTRLS -------------- */ pbuf_hdr->PrevSecListPtr = (void *)0; /* Clr pending tx Q ptrs. */ pbuf_hdr->NextSecListPtr = (void *)0; pbuf_hdr->UnlinkFnctPtr = (CPU_FNCT_PTR)0; /* Clr unlink ptrs. */ pbuf_hdr->UnlinkObjPtr = (void *)0; } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheTimeout() * * Description : Discard an ARP cache in the 'RESOLVED' state on timeout. * * Argument(s) : pcache_timeout Pointer to an ARP cache (see Note #2b). * * Return(s) : none. * * Caller(s) : Referenced in NetARP_CacheAddResolved(). * * Note(s) : (1) RFC #1122, Section 2.3.2.1 states that "an implementation of the Address Resolution * Protocol (ARP) ... MUST provide a mechanism to flush out-of-date cache entries". * * (2) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]' * type functions -- even though network timer API functions cast expiration functions * to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'). * * (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a * pointer to an object ... may be converted to a pointer to a different object * ... [but] if the resulting pointer is not correctly aligned ... the behavior * is undefined". * * And since compilers may NOT correctly convert 'void' pointers to non-'void' * pointer arguments, network timer expiration functions MUST avoid incorrect * pointer conversion behavior between 'void' pointer parameters & non-'void' * pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'. * * (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted * to or from a pointer to any ... object ... A pointer to any ... object ... * may be converted to a pointer to void and back again; the result shall * compare equal to the original pointer". * * (b) Therefore, to correctly convert 'void' pointer objects back to appropriate * network object pointer objects, network timer expiration functions MUST : * * (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ... * (2) Explicitly cast 'void' pointer arguments to specific object pointers; ... * (A) ... in this case, a 'NET_ARP_CACHE' pointer. * * See also 'net_tmr.c NetTmr_Get() Note #3'. * * (3) This function is a network timer expiration function : * * (a) Clear the timer pointer; ... * (1) Cleared in NetARP_CacheFree() via NetARP_CacheRemove(). * * (b) but do NOT re-free the timer. ********************************************************************************************************* */ static void NetARP_CacheTimeout (void *pcache_timeout) { #if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \ (NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif NET_ARP_CACHE *pcache; pcache = (NET_ARP_CACHE *)pcache_timeout; /* See Note #2b2A. */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------ VALIDATE PTR -------------------- */ if (pcache == (NET_ARP_CACHE *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); return; } /* ------------------ VALIDATE TYPE ------------------- */ if (pcache->Type != NET_ARP_TYPE_CACHE) { NET_CTR_ERR_INC(NetARP_ErrInvalidTypeCtr); return; } #endif /* ---------------- DISCARD ARP CACHE ----------------- */ NetARP_CacheRemove((NET_ARP_CACHE *)pcache, (CPU_BOOLEAN )DEF_NO); /* Clr but do NOT free tmr (see Note #3). */ } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheReqTimeout() * * Description : Retry ARP Request to resolve an ARP cache in the 'PENDING' state on ARP Request timeout. * * Argument(s) : pcache_timeout Pointer to an ARP cache (see Note #1b). * * Return(s) : none. * * Caller(s) : Referenced in NetARP_CacheAddPend(). * * Note(s) : (1) Ideally, network timer expiration functions could be defined as '[(void) (OBJECT *)]' * type functions -- even though network timer API functions cast expiration functions * to generic 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'). * * (a) (1) Unfortunately, ISO-IEC 9899-1999 ANSI-C, Section 6.3.2.3.7 states that "a * pointer to an object ... may be converted to a pointer to a different object * ... [but] if the resulting pointer is not correctly aligned ... the behavior * is undefined". * * And since compilers may NOT correctly convert 'void' pointers to non-'void' * pointer arguments, network timer expiration functions MUST avoid incorrect * pointer conversion behavior between 'void' pointer parameters & non-'void' * pointer arguments & therefore CANNOT be defined as '[(void) (OBJECT *)]'. * * (2) However, Section 6.3.2.3.1 states that "a pointer to void may be converted * to or from a pointer to any ... object ... A pointer to any ... object ... * may be converted to a pointer to void and back again; the result shall * compare equal to the original pointer". * * (b) Therefore, to correctly convert 'void' pointer objects back to appropriate * network object pointer objects, network timer expiration functions MUST : * * (1) Be defined as 'CPU_FNCT_PTR' type (i.e. '[(void) (void *)]'); & ... * (2) Explicitly cast 'void' pointer arguments to specific object pointers; ... * (A) ... in this case, a 'NET_ARP_CACHE' pointer. * * See also 'net_tmr.c NetTmr_Get() Note #3'. * * (2) This function is a network timer expiration function : * * (a) Clear the timer pointer; ... * (1) Cleared in NetARP_CacheFree() via NetARP_CacheRemove(); or * (2) Reset by NetTmr_Get(). * * (b) but do NOT re-free the timer. ********************************************************************************************************* */ static void NetARP_CacheReqTimeout (void *pcache_timeout) { #if ((NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) && \ (NET_CTR_CFG_ERR_EN == DEF_ENABLED) && \ (CPU_CFG_CRITICAL_METHOD == CPU_CRITICAL_METHOD_STATUS_LOCAL)) CPU_SR cpu_sr; #endif NET_ARP_CACHE *pcache; NET_ERR err; pcache = (NET_ARP_CACHE *)pcache_timeout; /* See Note #1b2A. */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ------------------ VALIDATE PTR -------------------- */ if (pcache == (NET_ARP_CACHE *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); return; } /* ------------------ VALIDATE TYPE ------------------- */ if (pcache->Type != NET_ARP_TYPE_CACHE) { NET_CTR_ERR_INC(NetARP_ErrInvalidTypeCtr); return; } #endif if (pcache->ReqAttemptsCtr >= NetARP_ReqMaxAttempts_nbr) { /* If nbr attempts >= max, free ARP cache. */ NetARP_CacheRemove((NET_ARP_CACHE *)pcache, (CPU_BOOLEAN )DEF_NO); /* Clr but do NOT free tmr (see Note #2). */ return; } /* ------------------ RETRY ARP REQ ------------------- */ pcache->TmrPtr = NetTmr_Get((void *) pcache, (CPU_FNCT_PTR) NetARP_CacheReqTimeout, (NET_TMR_TICK) NetARP_ReqTimeout_tick, (CPU_INT16U ) NET_TMR_FLAG_NONE, (NET_ERR *)&err); if (err != NET_TMR_ERR_NONE) { /* If tmr unavail, free ARP cache. */ NetARP_CacheRemove((NET_ARP_CACHE *)pcache, (CPU_BOOLEAN )DEF_NO); /* Clr but do NOT free tmr (see Note #2). */ return; } NetARP_TxReq(pcache); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheCfg() * * Description : (1) Configure an ARP cache : * * (a) Get ARP cache from ARP cache pool * (b) Get ARP cache timer * (c) Configure ARP cache : * (1) Configure ARP cache addresses : * (A) Protocol address * (B) Hardware address * (2) Configure ARP cache controls * * * Argument(s) : paddr_hw Pointer to hardware address (see Note #2a). * * paddr_protocol Pointer to protocol address (see Note #2b). * -------------- Argument checked in NetARP_ProbeAddrOnNet(), * NetARP_CacheAddPend(), * NetARP_CacheAddResolved(). * * timeout_fnct Pointer to timeout function. * * timeout_tick Timeout value (in 'NET_TMR_TICK' ticks). * * perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE ARP cache successfully configured. * * ---- RETURNED BY NetARP_CacheGet() : --- * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * * ------ RETURNED BY NetTmr_Get() : ------ * NET_TMR_ERR_NULL_OBJ Argument 'obj' passed a NULL pointer. * NET_TMR_ERR_NULL_FNCT Argument 'fnct' passed a NULL pointer. * NET_TMR_ERR_NONE_AVAIL NO available timers to allocate. * NET_TMR_ERR_INVALID_TYPE Network timer is NOT a valid timer type. * * Return(s) : none. * * Caller(s) : NetARP_ProbeAddrOnNet(), * NetARP_CacheAddPend(), * NetARP_CacheAddResolved(). * * Note(s) : (2) (a) If 'paddr_hw' available, points to a valid hardware address that is in network-order. * * (b) Assumes 'paddr_protocol' points to a valid protocol address that is in network-order. * * See also 'NetARP_CacheHandler() Note #2e3'. * * (3) On ANY errors, network resources MUST be appropriately freed. * * (4) During ARP cache initialization, some ARP cache controls were previously initialized * in NetARP_CacheGet() when the ARP cache was allocated from the ARP cache pool. These * ARP cache controls do NOT need to be re-initialized but are shown for completeness. ********************************************************************************************************* */ /*$PAGE*/ static NET_ARP_CACHE *NetARP_CacheCfg (CPU_INT08U *paddr_hw, CPU_INT08U *paddr_protocol, CPU_FNCT_PTR timeout_fnct, NET_TMR_TICK timeout_tick, NET_ERR *perr) { NET_ARP_CACHE *pcache; /* ------------------ GET ARP CACHE ------------------- */ pcache = NetARP_CacheGet(perr); if (pcache == (NET_ARP_CACHE *)0) { return ((NET_ARP_CACHE *)0); /* Rtn err from NetARP_CacheGet(). */ } /* ---------------- GET ARP CACHE TMR ----------------- */ pcache->TmrPtr = NetTmr_Get((void *)pcache, (CPU_FNCT_PTR)timeout_fnct, (NET_TMR_TICK)timeout_tick, (CPU_INT16U )NET_TMR_FLAG_NONE, (NET_ERR *)perr); if (*perr != NET_TMR_ERR_NONE) { /* If tmr unavail, ... */ NetARP_CacheFree(pcache, DEF_NO); /* ... free ARP cache (see Note #3). */ return ((NET_ARP_CACHE *)0); } /* ------------------ CFG ARP CACHE ------------------- */ /* Cfg ARP cache addr(s). */ if (paddr_hw != (CPU_INT08U *)0) { /* If hw addr avail, ... */ Mem_Copy((void *)&pcache->HW_Addr[0], /* ... copy hw addr into ARP cache (see Note #2a). */ (void *) paddr_hw, (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); } Mem_Copy((void *)&pcache->ProtocolAddr[0], /* Copy protocol addr into ARP cache (see Note #2b). */ (void *) paddr_protocol, (CPU_SIZE_T) NET_ARP_CFG_PROTOCOL_ADDR_LEN); /* Cfg ARP cache ctrl(s). */ #if 0 /* Init'd in NetARP_CacheGet() [see Note #4]. */ pcache->AccessedCtr = 0; pcache->ReqAttemptsCtr = 0; pcache->BufQ_Head = (NET_BUF *)0; pcache->BufQ_Tail = (NET_BUF *)0; /* Cfg'd in NetARP_CacheInsert(). */ pcache->PrevPtr = (void *)0; pcache->NextPtr = (void *)0; #endif *perr = NET_ARP_ERR_NONE; return (pcache); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheGet() * * Description : (1) Allocate & initialize an ARP cache : * * (a) Get an ARP cache * (b) Validate ARP cache * (c) Initialize ARP cache * (d) Update ARP cache pool statistics * (e) Return pointer to ARP cache * OR * Null pointer & error code, on failure * * (2) The ARP cache pool is implemented as a stack : * * (a) 'NetARP_CachePoolPtr' points to the head of the ARP cache pool. * * (b) ARP caches' 'NextPtr's link each ARP cache to form the ARP cache pool stack. * * (c) ARP caches are inserted & removed at the head of the ARP cache pool stack. * * * ARP caches are * inserted & removed * at the head * (see Note #2c) * * | NextPtr * | (see Note #2b) * v | * | * ------- ------- v ------- ------- * ARP Pool ---->| |------>| |------>| |------>| | * Pointer | | | | | | | | * | | | | | | | | * (see Note #2a) ------- ------- ------- ------- * * | | * |<---------- Pool of Free ARP Caches ---------->| * | (see Note #2) | * * * Argument(s) : perr Pointer to variable that will receive the return error code from this function : * * NET_ARP_ERR_NONE ARP cache successfully allocated & * initialized. * NET_ARP_ERR_CACHE_NONE_AVAIL NO available ARP caches to allocate. * NET_ARP_ERR_CACHE_INVALID_TYPE ARP cache is NOT a valid cache type. * * Return(s) : Pointer to ARP cache, if NO errors. * * Pointer to NULL, otherwise. * * Caller(s) : NetARP_CacheCfg(). * * Note(s) : (3) (a) ARP cache pool is accessed by 'NetARP_CachePoolPtr' during execution of * * (1) NetARP_Init() * (2) NetARP_CacheGet() * (3) NetARP_CacheFree() * * (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 ARP cache pool since no asynchronous access from other network * tasks is possible. * * (4) 'No cache available' case NOT possible during correct operation of the ARP Cache. * However, the 'else' case is included as an extra precaution in case the ARP Cache * List is incorrectly modified &/or corrupted. ********************************************************************************************************* */ /*$PAGE*/ static NET_ARP_CACHE *NetARP_CacheGet (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_ARP_CACHE *pcache; NET_ERR stat_err; /* ------------------ GET ARP CACHE ------------------- */ if (NetARP_CachePoolPtr != (NET_ARP_CACHE *)0) { /* If ARP cache pool NOT empty, get cache from pool. */ pcache = (NET_ARP_CACHE *)NetARP_CachePoolPtr; NetARP_CachePoolPtr = (NET_ARP_CACHE *)pcache->NextPtr; } else if (NetARP_CacheListTail != (NET_ARP_CACHE *)0) { /* If ARP Cache List NOT empty, ... */ /* ... get ARP cache from list tail. */ pcache = (NET_ARP_CACHE *)NetARP_CacheListTail; NetARP_CacheRemove(pcache, DEF_YES); pcache = (NET_ARP_CACHE *)NetARP_CachePoolPtr; NetARP_CachePoolPtr = (NET_ARP_CACHE *)pcache->NextPtr; } else { /* Else none avail, rtn err (see Note #4). */ NET_CTR_ERR_INC(NetARP_ErrNoneAvailCtr); *perr = NET_ARP_ERR_CACHE_NONE_AVAIL; return ((NET_ARP_CACHE *)0); } #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE ARP CACHE ---------------- */ if (pcache->Type != NET_ARP_TYPE_CACHE) { NetARP_CacheDiscard(pcache); NET_CTR_ERR_INC(NetARP_ErrInvalidTypeCtr); *perr = NET_ARP_ERR_CACHE_INVALID_TYPE; return ((NET_ARP_CACHE *)0); } #endif /* ------------------ INIT ARP CACHE ------------------ */ NetARP_CacheClr(pcache); DEF_BIT_SET(pcache->Flags, NET_ARP_FLAG_USED); /* Set ARP cache as used. */ /* ----------- UPDATE ARP CACHE POOL STATS ------------ */ NetStat_PoolEntryUsedInc(&NetARP_CachePoolStat, &stat_err); *perr = NET_ARP_ERR_NONE; return (pcache); /* ------------------ RTN ARP CACHE ------------------- */ } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheFree() * * Description : (1) Free an ARP cache : * * (a) Free ARP cache timer * (b) Free ARP cache buffer queue * (c) Clear ARP cache controls * (d) Free ARP cache back to ARP cache pool * (e) Update ARP cache pool statistics * * * Argument(s) : pcache Pointer to an ARP cache. * ------ Argument checked in NetARP_CacheCfg(), * NetARP_CacheRemove() * by NetARP_CacheHandler(), * NetARP_CacheGet(), * NetARP_CacheReqTimeout(), * NetARP_CacheTimeout(). * * tmr_free Indicate whether to free network timer : * * DEF_YES Free network timer for ARP cache. * DEF_NO Do NOT free network timer for ARP cache * [Freed by NetTmr_TaskHandler() * via NetARP_CacheRemove()]. * * Return(s) : none. * * Caller(s) : NetARP_CacheCfg(), * NetARP_CacheRemove(). * * Note(s) : (2) #### To prevent freeing an ARP cache already freed via previous ARP cache free, * NetARP_CacheFree() checks the ARP cache's 'USED' flag BEFORE freeing the cache. * * This prevention is only best-effort since any invalid duplicate ARP cache frees * MAY be asynchronous to potentially valid ARP cache gets. Thus the invalid ARP * cache free(s) MAY corrupt the ARP cache'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 ARP * cache resources from possible corruption since no asynchronous access from other * network tasks is possible. * * (3) When an ARP cache in the 'PENDING' state is freed, it discards its transmit packet * buffer queue. The discard is performed by the network interface layer since it is * the last layer to initiate transmission for these packet buffers. ********************************************************************************************************* */ /*$PAGE*/ static void NetARP_CacheFree (NET_ARP_CACHE *pcache, CPU_BOOLEAN tmr_free) { #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_CTR *pctr; NET_ERR err; #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) /* ---------------- VALIDATE TYPE ----------------- */ if (pcache->Type != NET_ARP_TYPE_CACHE) { NetARP_CacheDiscard(pcache); NET_CTR_ERR_INC(NetARP_ErrInvalidTypeCtr); return; } /* ------------ VALIDATE ARP CACHE USED ----------- */ used = DEF_BIT_IS_SET(pcache->Flags, NET_ARP_FLAG_USED); if (used != DEF_YES) { /* If ARP cache NOT used, ... */ NET_CTR_ERR_INC(NetARP_ErrNotUsedCtr); return; /* ... rtn but do NOT free (see Note #2). */ } #endif /* -------------- FREE ARP CACHE TMR -------------- */ if (tmr_free == DEF_YES) { if (pcache->TmrPtr != (NET_TMR *)0) { NetTmr_Free(pcache->TmrPtr); } } /* ------------- FREE ARP CACHE BUF Q ------------- */ #if (NET_CTR_CFG_ERR_EN == DEF_ENABLED) pctr = (NET_CTR *)&NetIF_ErrTxPktDiscardedCtr; /* See Note #3. */ #else pctr = (NET_CTR *) 0; #endif NetBuf_FreeBufQ_SecList((NET_BUF *)pcache->BufQ_Head, (NET_CTR *)pctr, (CPU_FNCT_PTR)NetARP_CacheUnlinkBuf); /* ----------------- CLR ARP CACHE ---------------- */ pcache->State = NET_ARP_CACHE_STATE_FREE; /* Set ARP cache as freed/NOT used. */ DEF_BIT_CLR(pcache->Flags, NET_ARP_FLAG_USED); #if (NET_DBG_CFG_MEM_CLR_EN == DEF_ENABLED) NetARP_CacheClr(pcache); #endif /* ---------------- FREE ARP CACHE ---------------- */ pcache->NextPtr = (void *)NetARP_CachePoolPtr; NetARP_CachePoolPtr = (NET_ARP_CACHE *)pcache; /* --------- UPDATE ARP CACHE POOL STATS ---------- */ NetStat_PoolEntryUsedDec(&NetARP_CachePoolStat, &err); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheClr() * * Description : Clear ARP cache controls. * * Argument(s) : pcache Pointer to an ARP cache. * ------ Argument validated in NetARP_Init(), * NetARP_CacheGet(), * NetARP_CacheFree(). * * Return(s) : none. * * Caller(s) : NetARP_Init(), * NetARP_CacheGet(), * NetARP_CacheFree(). * * Note(s) : none. ********************************************************************************************************* */ static void NetARP_CacheClr (NET_ARP_CACHE *pcache) { pcache->PrevPtr = (void *)0; pcache->NextPtr = (void *)0; pcache->BufQ_Head = (NET_BUF *)0; pcache->BufQ_Tail = (NET_BUF *)0; pcache->TmrPtr = (NET_TMR *)0; pcache->AccessedCtr = 0; pcache->ReqAttemptsCtr = 0; pcache->State = NET_ARP_CACHE_STATE_FREE; pcache->Flags = NET_ARP_FLAG_NONE; Mem_Clr((void *)&pcache->HW_Addr[0], (CPU_SIZE_T) NET_ARP_CFG_HW_ADDR_LEN); Mem_Clr((void *)&pcache->ProtocolAddr[0], (CPU_SIZE_T) NET_ARP_CFG_PROTOCOL_ADDR_LEN); } /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheIsUsed() * * Description : Validate ARP cache in use. * * Argument(s) : pcache Pointer to object to validate as an ARP cache in use. * * Return(s) : DEF_YES, ARP cache valid & in use. * * DEF_NO, ARP cache invalid or NOT in use. * * Caller(s) : various. * * Note(s) : (1) NetARP_CacheIsUsed() MUST be called with the global network lock already acquired. ********************************************************************************************************* */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static CPU_BOOLEAN NetARP_CacheIsUsed (NET_ARP_CACHE *pcache) { CPU_BOOLEAN used; /* ------------------ VALIDATE PTR -------------------- */ if (pcache == (NET_ARP_CACHE *)0) { return (DEF_NO); } /* ------------------ VALIDATE TYPE ------------------- */ if (pcache->Type != NET_ARP_TYPE_CACHE) { return (DEF_NO); } /* ------------- VALIDATE ARP CACHE USED -------------- */ used = DEF_BIT_IS_SET(pcache->Flags, NET_ARP_FLAG_USED); return (used); } #endif /*$PAGE*/ /* ********************************************************************************************************* * NetARP_CacheDiscard() * * Description : (1) Discard an invalid/corrupted ARP cache : * * (a) Discard ARP cache from available cache pool See Note #2 * (b) Update ARP cache pool statistics * * (2) Assumes ARP cache is invalid/corrupt & MUST be removed. ARP cache removed * simply by NOT returning the ARP cache back to the ARP cache pool. * * * Argument(s) : pcache Pointer to an invalid/corrupted ARP cache. * * Return(s) : none. * * Caller(s) : NetARP_CacheGet(), * NetARP_CacheFree(). * * Note(s) : none. ********************************************************************************************************* */ #if (NET_ERR_CFG_ARG_CHK_DBG_EN == DEF_ENABLED) static void NetARP_CacheDiscard (NET_ARP_CACHE *pcache) { #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 ARP CACHE ----------------- */ if (pcache == (NET_ARP_CACHE *)0) { NET_CTR_ERR_INC(NetARP_ErrNullPtrCtr); return; } /* --------------- UPDATE DISCARD STATS --------------- */ NetStat_PoolEntryLostInc(&NetARP_CachePoolStat, &stat_err); } #endif /*$PAGE*/ /* ********************************************************************************************************* * MODULE END * * Note(s) : (1) See 'MODULE Note #1' & 'net_arp.h MODULE Note #1'. ********************************************************************************************************* */ #endif /* End of ARP module include (see Note #1). */