]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_ARP.c
index c98a7e8703653d7d616713cf2f543a68419f403a..7d8ed18c692fbb19447a874be2e54062708ace59 100644 (file)
-/*\r
- * FreeRTOS+TCP V2.2.0\r
- * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://aws.amazon.com/freertos\r
- * http://www.FreeRTOS.org\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-#include <stdio.h>\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "queue.h"\r
-#include "semphr.h"\r
-\r
-/* FreeRTOS+TCP includes. */\r
-#include "FreeRTOS_IP.h"\r
-#include "FreeRTOS_Sockets.h"\r
-#include "FreeRTOS_IP_Private.h"\r
-#include "FreeRTOS_ARP.h"\r
-#include "FreeRTOS_UDP_IP.h"\r
-#include "FreeRTOS_DHCP.h"\r
-#if( ipconfigUSE_LLMNR == 1 )\r
-       #include "FreeRTOS_DNS.h"\r
-#endif /* ipconfigUSE_LLMNR */\r
-#include "NetworkInterface.h"\r
-#include "NetworkBufferManagement.h"\r
-\r
-\r
-/* When the age of an entry in the ARP table reaches this value (it counts down\r
-to zero, so this is an old entry) an ARP request will be sent to see if the\r
-entry is still valid and can therefore be refreshed. */\r
-#define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST          ( 3 )\r
-\r
-/* The time between gratuitous ARPs. */\r
-#ifndef arpGRATUITOUS_ARP_PERIOD\r
-       #define arpGRATUITOUS_ARP_PERIOD                                        ( pdMS_TO_TICKS( 20000 ) )\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/*\r
- * Lookup an MAC address in the ARP cache from the IP address.\r
- */\r
-static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress );\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The ARP cache. */\r
-static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];\r
-\r
-/* The time at which the last gratuitous ARP was sent.  Gratuitous ARPs are used\r
-to ensure ARP tables are up to date and to detect IP address conflicts. */\r
-static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;\r
-\r
-/*\r
- * IP-clash detection is currently only used internally. When DHCP doesn't respond, the\r
- * driver can try out a random LinkLayer IP address (169.254.x.x).  It will send out a\r
- * gratuitos ARP message and, after a period of time, check the variables here below:\r
- */\r
-#if( ipconfigARP_USE_CLASH_DETECTION != 0 )\r
-       /* Becomes non-zero if another device responded to a gratuitos ARP message. */\r
-       BaseType_t xARPHadIPClash;\r
-       /* MAC-address of the other device containing the same IP-address. */\r
-       MACAddress_t xARPClashMacAddress;\r
-#endif /* ipconfigARP_USE_CLASH_DETECTION */\r
-\r
-/* Part of the Ethernet and ARP headers are always constant when sending an IPv4\r
-ARP packet.  This array defines the constant parts, allowing this part of the\r
-packet to be filled in using a simple memcpy() instead of individual writes. */\r
-static const uint8_t xDefaultPartARPPacketHeader[] =\r
-{\r
-       0xff, 0xff, 0xff, 0xff, 0xff, 0xff,     /* Ethernet destination address. */\r
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* Ethernet source address. */\r
-       0x08, 0x06,                                                     /* Ethernet frame type (ipARP_FRAME_TYPE). */\r
-       0x00, 0x01,                                                     /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */\r
-       0x08, 0x00,                                                             /* usProtocolType. */\r
-       ipMAC_ADDRESS_LENGTH_BYTES,                     /* ucHardwareAddressLength. */\r
-       ipIP_ADDRESS_LENGTH_BYTES,                              /* ucProtocolAddressLength. */\r
-       0x00, 0x01,                                                     /* usOperation (ipARP_REQUEST). */\r
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* xSenderHardwareAddress. */\r
-       0x00, 0x00, 0x00, 0x00,                                 /* ulSenderProtocolAddress. */\r
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00              /* xTargetHardwareAddress. */\r
-};\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )\r
-{\r
-eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
-ARPHeader_t *pxARPHeader;\r
-uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;\r
-\r
-       pxARPHeader = &( pxARPFrame->xARPHeader );\r
-\r
-       /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */\r
-       memcpy( ( void *)&( ulSenderProtocolAddress ), ( void * )pxARPHeader->ucSenderProtocolAddress, sizeof( ulSenderProtocolAddress ) );\r
-       /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */\r
-       ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;\r
-\r
-       traceARP_PACKET_RECEIVED();\r
-\r
-       /* Don't do anything if the local IP address is zero because\r
-       that means a DHCP request has not completed. */\r
-       if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )\r
-       {\r
-               switch( pxARPHeader->usOperation )\r
-               {\r
-                       case ipARP_REQUEST      :\r
-                               /* The packet contained an ARP request.  Was it for the IP\r
-                               address of the node running this code? */\r
-                               if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
-                               {\r
-                                       iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );\r
-\r
-                                       /* The request is for the address of this node.  Add the\r
-                                       entry into the ARP cache, or refresh the entry if it\r
-                                       already exists. */\r
-                                       vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );\r
-\r
-                                       /* Generate a reply payload in the same buffer. */\r
-                                       pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;\r
-                                       if( ulTargetProtocolAddress == ulSenderProtocolAddress )\r
-                                       {\r
-                                               /* A double IP address is detected! */\r
-                                               /* Give the sources MAC address the value of the broadcast address, will be swapped later */\r
-                                               memcpy( pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) );\r
-                                               memset( pxARPHeader->xTargetHardwareAddress.ucBytes, '\0', sizeof( MACAddress_t ) );\r
-                                               pxARPHeader->ulTargetProtocolAddress = 0UL;\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) );\r
-                                               pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;\r
-                                       }\r
-                                       memcpy( pxARPHeader->xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );\r
-                                       memcpy( ( void* )pxARPHeader->ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPHeader->ucSenderProtocolAddress ) );\r
-\r
-                                       eReturn = eReturnEthernetFrame;\r
-                               }\r
-                               break;\r
-\r
-                       case ipARP_REPLY :\r
-                               iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );\r
-                               vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );\r
-                               /* Process received ARP frame to see if there is a clash. */\r
-                               #if( ipconfigARP_USE_CLASH_DETECTION != 0 )\r
-                               {\r
-                                       if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
-                                       {\r
-                                               xARPHadIPClash = pdTRUE;\r
-                                               memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );\r
-                                       }\r
-                               }\r
-                               #endif /* ipconfigARP_USE_CLASH_DETECTION */\r
-                               break;\r
-\r
-                       default :\r
-                               /* Invalid. */\r
-                               break;\r
-               }\r
-       }\r
-\r
-       return eReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )\r
-\r
-       uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )\r
-       {\r
-       BaseType_t x;\r
-       uint32_t lResult = 0;\r
-\r
-               /* For each entry in the ARP cache table. */\r
-               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
-               {\r
-                       if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )\r
-                       {\r
-                               lResult = xARPCache[ x ].ulIPAddress;\r
-                               memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) );\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               return lResult;\r
-       }\r
-\r
-#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */\r
-/*-----------------------------------------------------------*/\r
-\r
-void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress )\r
-{\r
-BaseType_t x = 0;\r
-BaseType_t xIpEntry = -1;\r
-BaseType_t xMacEntry = -1;\r
-BaseType_t xUseEntry = 0;\r
-uint8_t ucMinAgeFound = 0U;\r
-\r
-       #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )\r
-               /* Only process the IP address if it is on the local network.\r
-               Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address\r
-               and netmask are still unknown. */\r
-               if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||\r
-                       ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )\r
-       #else\r
-               /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with\r
-               a different netmask will also be stored.  After when replying to a UDP\r
-               message from a different netmask, the IP address can be looped up and a\r
-               reply sent.  This option is useful for systems with multiple gateways,\r
-               the reply will surely arrive.  If ipconfigARP_STORES_REMOTE_ADDRESSES is\r
-               zero the the gateway address is the only option. */\r
-               if( pdTRUE )\r
-       #endif\r
-       {\r
-               /* Start with the maximum possible number. */\r
-               ucMinAgeFound--;\r
-\r
-               /* For each entry in the ARP cache table. */\r
-               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
-               {\r
-                       /* Does this line in the cache table hold an entry for the IP\r
-                       address being queried? */\r
-                       if( xARPCache[ x ].ulIPAddress == ulIPAddress )\r
-                       {\r
-                               if( pxMACAddress == NULL )\r
-                               {\r
-                                       /* In case the parameter pxMACAddress is NULL, an entry will be reserved to\r
-                                       indicate that there is an outstanding ARP request, This entry will have\r
-                                       "ucValid == pdFALSE". */\r
-                                       xIpEntry = x;\r
-                                       break;\r
-                               }\r
-\r
-                               /* See if the MAC-address also matches. */\r
-                               if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )\r
-                               {\r
-                                       /* This function will be called for each received packet\r
-                                       As this is by far the most common path the coding standard\r
-                                       is relaxed in this case and a return is permitted as an\r
-                                       optimisation. */\r
-                                       xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;\r
-                                       xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;\r
-                                       return;\r
-                               }\r
-\r
-                               /* Found an entry containing ulIPAddress, but the MAC address\r
-                               doesn't match.  Might be an entry with ucValid=pdFALSE, waiting\r
-                               for an ARP reply.  Still want to see if there is match with the\r
-                               given MAC address.ucBytes.  If found, either of the two entries\r
-                               must be cleared. */\r
-                               xIpEntry = x;\r
-                       }\r
-                       else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )\r
-                       {\r
-                               /* Found an entry with the given MAC-address, but the IP-address\r
-                               is different.  Continue looping to find a possible match with\r
-                               ulIPAddress. */\r
-       #if( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )\r
-                               /* If ARP stores the MAC address of IP addresses outside the\r
-                               network, than the MAC address of the gateway should not be\r
-                               overwritten. */\r
-                               BaseType_t bIsLocal[ 2 ];\r
-                               bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );\r
-                               bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );\r
-                               if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )\r
-                               {\r
-                                       xMacEntry = x;\r
-                               }\r
-       #else\r
-                               xMacEntry = x;\r
-       #endif\r
-                       }\r
-                       /* _HT_\r
-                       Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */\r
-                       else if( xARPCache[ x ].ucAge < ucMinAgeFound )\r
-                       {\r
-                               /* As the table is traversed, remember the table row that\r
-                               contains the oldest entry (the lowest age count, as ages are\r
-                               decremented to zero) so the row can be re-used if this function\r
-                               needs to add an entry that does not already exist. */\r
-                               ucMinAgeFound = xARPCache[ x ].ucAge;\r
-                               xUseEntry = x;\r
-                       }\r
-               }\r
-\r
-               if( xMacEntry >= 0 )\r
-               {\r
-                       xUseEntry = xMacEntry;\r
-\r
-                       if( xIpEntry >= 0 )\r
-                       {\r
-                               /* Both the MAC address as well as the IP address were found in\r
-                               different locations: clear the entry which matches the\r
-                               IP-address */\r
-                               memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) );\r
-                       }\r
-               }\r
-               else if( xIpEntry >= 0 )\r
-               {\r
-                       /* An entry containing the IP-address was found, but it had a different MAC address */\r
-                       xUseEntry = xIpEntry;\r
-               }\r
-\r
-               /* If the entry was not found, we use the oldest entry and set the IPaddress */\r
-               xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;\r
-\r
-               if( pxMACAddress != NULL )\r
-               {\r
-                       memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );\r
-\r
-                       iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, (*pxMACAddress) );\r
-                       /* And this entry does not need immediate attention */\r
-                       xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;\r
-                       xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;\r
-               }\r
-               else if( xIpEntry < 0 )\r
-               {\r
-                       xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;\r
-                       xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )\r
-       eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress )\r
-       {\r
-       BaseType_t x;\r
-       eARPLookupResult_t eReturn = eARPCacheMiss;\r
-\r
-               /* Loop through each entry in the ARP cache. */\r
-               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
-               {\r
-                       /* Does this row in the ARP cache table hold an entry for the MAC\r
-                       address being searched? */\r
-                       if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )\r
-                       {\r
-                               *pulIPAddress = xARPCache[ x ].ulIPAddress;\r
-                               eReturn = eARPCacheHit;\r
-                               break;\r
-                       }\r
-               }\r
-\r
-               return eReturn;\r
-       }\r
-#endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress )\r
-{\r
-eARPLookupResult_t eReturn;\r
-uint32_t ulAddressToLookup;\r
-\r
-#if( ipconfigUSE_LLMNR == 1 )\r
-       if( *pulIPAddress == ipLLMNR_IP_ADDR )  /* Is in network byte order. */\r
-       {\r
-               /* The LLMNR IP-address has a fixed virtual MAC address. */\r
-               memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );\r
-               eReturn = eARPCacheHit;\r
-       }\r
-       else\r
-#endif\r
-       if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) ||      /* Is it the general broadcast address 255.255.255.255? */\r
-               ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) )/* Or a local broadcast address, eg 192.168.1.255? */\r
-       {\r
-               /* This is a broadcast so uses the broadcast MAC address. */\r
-               memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );\r
-               eReturn = eARPCacheHit;\r
-       }\r
-       else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )\r
-       {\r
-               /* The IP address has not yet been assigned, so there is nothing that\r
-               can be done. */\r
-               eReturn = eCantSendPacket;\r
-       }\r
-       else\r
-       {\r
-               eReturn = eARPCacheMiss;\r
-\r
-               if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )\r
-               {\r
-#if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )\r
-                       eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );\r
-\r
-                       if( eReturn == eARPCacheHit )\r
-                       {\r
-                               /* The stack is configured to store 'remote IP addresses', i.e. addresses\r
-                               belonging to a different the netmask.  prvCacheLookup() returned a hit, so\r
-                               the MAC address is known */\r
-                       }\r
-                       else\r
-#endif\r
-                       {\r
-                               /* The IP address is off the local network, so look up the\r
-                               hardware address of the router, if any. */\r
-                               if( xNetworkAddressing.ulGatewayAddress != ( uint32_t )0u )\r
-                               {\r
-                                       ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;\r
-                               }\r
-                               else\r
-                               {\r
-                                       ulAddressToLookup = *pulIPAddress;\r
-                               }\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* The IP address is on the local network, so lookup the requested\r
-                       IP address directly. */\r
-                       ulAddressToLookup = *pulIPAddress;\r
-               }\r
-\r
-               if( eReturn == eARPCacheMiss )\r
-               {\r
-                       if( ulAddressToLookup == 0UL )\r
-                       {\r
-                               /* The address is not on the local network, and there is not a\r
-                               router. */\r
-                               eReturn = eCantSendPacket;\r
-                       }\r
-                       else\r
-                       {\r
-                               eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );\r
-\r
-                               if( eReturn == eARPCacheMiss )\r
-                               {\r
-                                       /* It might be that the ARP has to go to the gateway. */\r
-                                       *pulIPAddress = ulAddressToLookup;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       return eReturn;\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress )\r
-{\r
-BaseType_t x;\r
-eARPLookupResult_t eReturn = eARPCacheMiss;\r
-\r
-       /* Loop through each entry in the ARP cache. */\r
-       for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
-       {\r
-               /* Does this row in the ARP cache table hold an entry for the IP address\r
-               being queried? */\r
-               if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )\r
-               {\r
-                       /* A matching valid entry was found. */\r
-                       if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )\r
-                       {\r
-                               /* This entry is waiting an ARP reply, so is not valid. */\r
-                               eReturn = eCantSendPacket;\r
-                       }\r
-                       else\r
-                       {\r
-                               /* A valid entry was found. */\r
-                               memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );\r
-                               eReturn = eARPCacheHit;\r
-                       }\r
-                       break;\r
-               }\r
-       }\r
-\r
-       return eReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vARPAgeCache( void )\r
-{\r
-BaseType_t x;\r
-TickType_t xTimeNow;\r
-\r
-       /* Loop through each entry in the ARP cache. */\r
-       for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
-       {\r
-               /* If the entry is valid (its age is greater than zero). */\r
-               if( xARPCache[ x ].ucAge > 0U )\r
-               {\r
-                       /* Decrement the age value of the entry in this ARP cache table row.\r
-                       When the age reaches zero it is no longer considered valid. */\r
-                       ( xARPCache[ x ].ucAge )--;\r
-\r
-                       /* If the entry is not yet valid, then it is waiting an ARP\r
-                       reply, and the ARP request should be retransmitted. */\r
-                       if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )\r
-                       {\r
-                               FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );\r
-                       }\r
-                       else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )\r
-                       {\r
-                               /* This entry will get removed soon.  See if the MAC address is\r
-                               still valid to prevent this happening. */\r
-                               iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );\r
-                               FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* The age has just ticked down, with nothing to do. */\r
-                       }\r
-\r
-                       if( xARPCache[ x ].ucAge == 0u )\r
-                       {\r
-                               /* The entry is no longer valid.  Wipe it out. */\r
-                               iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );\r
-                               xARPCache[ x ].ulIPAddress = 0UL;\r
-                       }\r
-               }\r
-       }\r
-\r
-       xTimeNow = xTaskGetTickCount ();\r
-\r
-       if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )\r
-       {\r
-               FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );\r
-               xLastGratuitousARPTime = xTimeNow;\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vARPSendGratuitous( void )\r
-{\r
-       /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next\r
-       time vARPAgeCache() is called. */\r
-       xLastGratuitousARPTime = ( TickType_t ) 0;\r
-\r
-       /* Let the IP-task call vARPAgeCache(). */\r
-       xSendEventToIPTask( eARPTimerEvent );\r
-}\r
-\r
-/*-----------------------------------------------------------*/\r
-void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )\r
-{\r
-NetworkBufferDescriptor_t *pxNetworkBuffer;\r
-\r
-       /* This is called from the context of the IP event task, so a block time\r
-       must not be used. */\r
-       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0 );\r
-\r
-       if( pxNetworkBuffer != NULL )\r
-       {\r
-               pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
-               vARPGenerateRequestPacket( pxNetworkBuffer );\r
-\r
-               #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
-               {\r
-                       if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
-                       {\r
-                       BaseType_t xIndex;\r
-\r
-                               for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
-                               {\r
-                                       pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
-                               }\r
-                               pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
-                       }\r
-               }\r
-               #endif\r
-               if( xIsCallingFromIPTask() != 0 )\r
-               {\r
-                       /* Only the IP-task is allowed to call this function directly. */\r
-                       xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );\r
-               }\r
-               else\r
-               {\r
-               IPStackEvent_t xSendEvent;\r
-\r
-                       /* Send a message to the IP-task to send this ARP packet. */\r
-                       xSendEvent.eEventType = eNetworkTxEvent;\r
-                       xSendEvent.pvData = ( void * ) pxNetworkBuffer;\r
-                       if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )\r
-                       {\r
-                               /* Failed to send the message, so release the network buffer. */\r
-                               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
-{\r
-ARPPacket_t *pxARPPacket;\r
-\r
-       /* Buffer allocation ensures that buffers always have space\r
-       for an ARP packet. See buffer allocation implementations 1\r
-       and 2 under portable/BufferManagement. */\r
-       configASSERT( pxNetworkBuffer );\r
-       configASSERT( pxNetworkBuffer->xDataLength >= sizeof(ARPPacket_t) );\r
-\r
-       pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
-\r
-       /* memcpy the const part of the header information into the correct\r
-       location in the packet.  This copies:\r
-               xEthernetHeader.ulDestinationAddress\r
-               xEthernetHeader.usFrameType;\r
-               xARPHeader.usHardwareType;\r
-               xARPHeader.usProtocolType;\r
-               xARPHeader.ucHardwareAddressLength;\r
-               xARPHeader.ucProtocolAddressLength;\r
-               xARPHeader.usOperation;\r
-               xARPHeader.xTargetHardwareAddress;\r
-       */\r
-       memcpy( ( void * ) pxARPPacket, ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );\r
-       memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
-       memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
-\r
-       memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );\r
-       pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;\r
-\r
-       pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );\r
-\r
-       iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void FreeRTOS_ClearARP( void )\r
-{\r
-       memset( xARPCache, '\0', sizeof( xARPCache ) );\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-#if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )\r
-\r
-       void FreeRTOS_PrintARPCache( void )\r
-       {\r
-       BaseType_t x, xCount = 0;\r
-\r
-               /* Loop through each entry in the ARP cache. */\r
-               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
-               {\r
-                       if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) )\r
-                       {\r
-                               /* See if the MAC-address also matches, and we're all happy */\r
-                               FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",\r
-                                       x,\r
-                                       xARPCache[ x ].ucAge,\r
-                                       xARPCache[ x ].ulIPAddress,\r
-                                       xARPCache[ x ].xMACAddress.ucBytes[0],\r
-                                       xARPCache[ x ].xMACAddress.ucBytes[1],\r
-                                       xARPCache[ x ].xMACAddress.ucBytes[2],\r
-                                       xARPCache[ x ].xMACAddress.ucBytes[3],\r
-                                       xARPCache[ x ].xMACAddress.ucBytes[4],\r
-                                       xARPCache[ x ].xMACAddress.ucBytes[5] ) );\r
-                               xCount++;\r
-                       }\r
-               }\r
-\r
-               FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );\r
-       }\r
-\r
-#endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */\r
+/*
+ * FreeRTOS+TCP V2.2.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+#include <stdio.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "FreeRTOS_ARP.h"
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_DHCP.h"
+#if( ipconfigUSE_LLMNR == 1 )
+       #include "FreeRTOS_DNS.h"
+#endif /* ipconfigUSE_LLMNR */
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+
+/* When the age of an entry in the ARP table reaches this value (it counts down
+to zero, so this is an old entry) an ARP request will be sent to see if the
+entry is still valid and can therefore be refreshed. */
+#define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST          ( 3 )
+
+/* The time between gratuitous ARPs. */
+#ifndef arpGRATUITOUS_ARP_PERIOD
+       #define arpGRATUITOUS_ARP_PERIOD                                        ( pdMS_TO_TICKS( 20000 ) )
+#endif
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Lookup an MAC address in the ARP cache from the IP address.
+ */
+static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress );
+
+/*-----------------------------------------------------------*/
+
+/* The ARP cache. */
+static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
+
+/* The time at which the last gratuitous ARP was sent.  Gratuitous ARPs are used
+to ensure ARP tables are up to date and to detect IP address conflicts. */
+static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;
+
+/*
+ * IP-clash detection is currently only used internally. When DHCP doesn't respond, the
+ * driver can try out a random LinkLayer IP address (169.254.x.x).  It will send out a
+ * gratuitos ARP message and, after a period of time, check the variables here below:
+ */
+#if( ipconfigARP_USE_CLASH_DETECTION != 0 )
+       /* Becomes non-zero if another device responded to a gratuitos ARP message. */
+       BaseType_t xARPHadIPClash;
+       /* MAC-address of the other device containing the same IP-address. */
+       MACAddress_t xARPClashMacAddress;
+#endif /* ipconfigARP_USE_CLASH_DETECTION */
+
+/* Part of the Ethernet and ARP headers are always constant when sending an IPv4
+ARP packet.  This array defines the constant parts, allowing this part of the
+packet to be filled in using a simple memcpy() instead of individual writes. */
+static const uint8_t xDefaultPartARPPacketHeader[] =
+{
+       0xff, 0xff, 0xff, 0xff, 0xff, 0xff,     /* Ethernet destination address. */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* Ethernet source address. */
+       0x08, 0x06,                                                     /* Ethernet frame type (ipARP_FRAME_TYPE). */
+       0x00, 0x01,                                                     /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
+       0x08, 0x00,                                                             /* usProtocolType. */
+       ipMAC_ADDRESS_LENGTH_BYTES,                     /* ucHardwareAddressLength. */
+       ipIP_ADDRESS_LENGTH_BYTES,                              /* ucProtocolAddressLength. */
+       0x00, 0x01,                                                     /* usOperation (ipARP_REQUEST). */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* xSenderHardwareAddress. */
+       0x00, 0x00, 0x00, 0x00,                                 /* ulSenderProtocolAddress. */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00              /* xTargetHardwareAddress. */
+};
+
+/*-----------------------------------------------------------*/
+
+eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )
+{
+eFrameProcessingResult_t eReturn = eReleaseBuffer;
+ARPHeader_t *pxARPHeader;
+uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
+
+       pxARPHeader = &( pxARPFrame->xARPHeader );
+
+       /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */
+       memcpy( ( void *)&( ulSenderProtocolAddress ), ( void * )pxARPHeader->ucSenderProtocolAddress, sizeof( ulSenderProtocolAddress ) );
+       /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
+       ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
+
+       traceARP_PACKET_RECEIVED();
+
+       /* Don't do anything if the local IP address is zero because
+       that means a DHCP request has not completed. */
+       if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )
+       {
+               switch( pxARPHeader->usOperation )
+               {
+                       case ipARP_REQUEST      :
+                               /* The packet contained an ARP request.  Was it for the IP
+                               address of the node running this code? */
+                               if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
+                               {
+                                       iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
+
+                                       /* The request is for the address of this node.  Add the
+                                       entry into the ARP cache, or refresh the entry if it
+                                       already exists. */
+                                       vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
+
+                                       /* Generate a reply payload in the same buffer. */
+                                       pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
+                                       if( ulTargetProtocolAddress == ulSenderProtocolAddress )
+                                       {
+                                               /* A double IP address is detected! */
+                                               /* Give the sources MAC address the value of the broadcast address, will be swapped later */
+                                               memcpy( pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) );
+                                               memset( pxARPHeader->xTargetHardwareAddress.ucBytes, '\0', sizeof( MACAddress_t ) );
+                                               pxARPHeader->ulTargetProtocolAddress = 0UL;
+                                       }
+                                       else
+                                       {
+                                               memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) );
+                                               pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
+                                       }
+                                       memcpy( pxARPHeader->xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
+                                       memcpy( ( void* )pxARPHeader->ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
+
+                                       eReturn = eReturnEthernetFrame;
+                               }
+                               break;
+
+                       case ipARP_REPLY :
+                               iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
+                               vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
+                               /* Process received ARP frame to see if there is a clash. */
+                               #if( ipconfigARP_USE_CLASH_DETECTION != 0 )
+                               {
+                                       if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
+                                       {
+                                               xARPHadIPClash = pdTRUE;
+                                               memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
+                                       }
+                               }
+                               #endif /* ipconfigARP_USE_CLASH_DETECTION */
+                               break;
+
+                       default :
+                               /* Invalid. */
+                               break;
+               }
+       }
+
+       return eReturn;
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
+
+       uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
+       {
+       BaseType_t x;
+       uint32_t lResult = 0;
+
+               /* For each entry in the ARP cache table. */
+               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+               {
+                       if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
+                       {
+                               lResult = xARPCache[ x ].ulIPAddress;
+                               memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) );
+                               break;
+                       }
+               }
+
+               return lResult;
+       }
+
+#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
+/*-----------------------------------------------------------*/
+
+void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress )
+{
+BaseType_t x = 0;
+BaseType_t xIpEntry = -1;
+BaseType_t xMacEntry = -1;
+BaseType_t xUseEntry = 0;
+uint8_t ucMinAgeFound = 0U;
+
+       #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
+               /* Only process the IP address if it is on the local network.
+               Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address
+               and netmask are still unknown. */
+               if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||
+                       ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
+       #else
+               /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
+               a different netmask will also be stored.  After when replying to a UDP
+               message from a different netmask, the IP address can be looped up and a
+               reply sent.  This option is useful for systems with multiple gateways,
+               the reply will surely arrive.  If ipconfigARP_STORES_REMOTE_ADDRESSES is
+               zero the the gateway address is the only option. */
+               if( pdTRUE )
+       #endif
+       {
+               /* Start with the maximum possible number. */
+               ucMinAgeFound--;
+
+               /* For each entry in the ARP cache table. */
+               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+               {
+                       /* Does this line in the cache table hold an entry for the IP
+                       address being queried? */
+                       if( xARPCache[ x ].ulIPAddress == ulIPAddress )
+                       {
+                               if( pxMACAddress == NULL )
+                               {
+                                       /* In case the parameter pxMACAddress is NULL, an entry will be reserved to
+                                       indicate that there is an outstanding ARP request, This entry will have
+                                       "ucValid == pdFALSE". */
+                                       xIpEntry = x;
+                                       break;
+                               }
+
+                               /* See if the MAC-address also matches. */
+                               if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
+                               {
+                                       /* This function will be called for each received packet
+                                       As this is by far the most common path the coding standard
+                                       is relaxed in this case and a return is permitted as an
+                                       optimisation. */
+                                       xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
+                                       xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
+                                       return;
+                               }
+
+                               /* Found an entry containing ulIPAddress, but the MAC address
+                               doesn't match.  Might be an entry with ucValid=pdFALSE, waiting
+                               for an ARP reply.  Still want to see if there is match with the
+                               given MAC address.ucBytes.  If found, either of the two entries
+                               must be cleared. */
+                               xIpEntry = x;
+                       }
+                       else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
+                       {
+                               /* Found an entry with the given MAC-address, but the IP-address
+                               is different.  Continue looping to find a possible match with
+                               ulIPAddress. */
+       #if( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
+                               /* If ARP stores the MAC address of IP addresses outside the
+                               network, than the MAC address of the gateway should not be
+                               overwritten. */
+                               BaseType_t bIsLocal[ 2 ];
+                               bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
+                               bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
+                               if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )
+                               {
+                                       xMacEntry = x;
+                               }
+       #else
+                               xMacEntry = x;
+       #endif
+                       }
+                       /* _HT_
+                       Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
+                       else if( xARPCache[ x ].ucAge < ucMinAgeFound )
+                       {
+                               /* As the table is traversed, remember the table row that
+                               contains the oldest entry (the lowest age count, as ages are
+                               decremented to zero) so the row can be re-used if this function
+                               needs to add an entry that does not already exist. */
+                               ucMinAgeFound = xARPCache[ x ].ucAge;
+                               xUseEntry = x;
+                       }
+               }
+
+               if( xMacEntry >= 0 )
+               {
+                       xUseEntry = xMacEntry;
+
+                       if( xIpEntry >= 0 )
+                       {
+                               /* Both the MAC address as well as the IP address were found in
+                               different locations: clear the entry which matches the
+                               IP-address */
+                               memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) );
+                       }
+               }
+               else if( xIpEntry >= 0 )
+               {
+                       /* An entry containing the IP-address was found, but it had a different MAC address */
+                       xUseEntry = xIpEntry;
+               }
+
+               /* If the entry was not found, we use the oldest entry and set the IPaddress */
+               xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;
+
+               if( pxMACAddress != NULL )
+               {
+                       memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
+
+                       iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, (*pxMACAddress) );
+                       /* And this entry does not need immediate attention */
+                       xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
+                       xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
+               }
+               else if( xIpEntry < 0 )
+               {
+                       xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
+                       xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
+       eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress )
+       {
+       BaseType_t x;
+       eARPLookupResult_t eReturn = eARPCacheMiss;
+
+               /* Loop through each entry in the ARP cache. */
+               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+               {
+                       /* Does this row in the ARP cache table hold an entry for the MAC
+                       address being searched? */
+                       if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
+                       {
+                               *pulIPAddress = xARPCache[ x ].ulIPAddress;
+                               eReturn = eARPCacheHit;
+                               break;
+                       }
+               }
+
+               return eReturn;
+       }
+#endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
+
+/*-----------------------------------------------------------*/
+
+eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress )
+{
+eARPLookupResult_t eReturn;
+uint32_t ulAddressToLookup;
+
+#if( ipconfigUSE_LLMNR == 1 )
+       if( *pulIPAddress == ipLLMNR_IP_ADDR )  /* Is in network byte order. */
+       {
+               /* The LLMNR IP-address has a fixed virtual MAC address. */
+               memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );
+               eReturn = eARPCacheHit;
+       }
+       else
+#endif
+       if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) ||      /* Is it the general broadcast address 255.255.255.255? */
+               ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) )/* Or a local broadcast address, eg 192.168.1.255? */
+       {
+               /* This is a broadcast so uses the broadcast MAC address. */
+               memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
+               eReturn = eARPCacheHit;
+       }
+       else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
+       {
+               /* The IP address has not yet been assigned, so there is nothing that
+               can be done. */
+               eReturn = eCantSendPacket;
+       }
+       else
+       {
+               eReturn = eARPCacheMiss;
+
+               if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
+               {
+#if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
+                       eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );
+
+                       if( eReturn == eARPCacheHit )
+                       {
+                               /* The stack is configured to store 'remote IP addresses', i.e. addresses
+                               belonging to a different the netmask.  prvCacheLookup() returned a hit, so
+                               the MAC address is known */
+                       }
+                       else
+#endif
+                       {
+                               /* The IP address is off the local network, so look up the
+                               hardware address of the router, if any. */
+                               if( xNetworkAddressing.ulGatewayAddress != ( uint32_t )0u )
+                               {
+                                       ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
+                               }
+                               else
+                               {
+                                       ulAddressToLookup = *pulIPAddress;
+                               }
+                       }
+               }
+               else
+               {
+                       /* The IP address is on the local network, so lookup the requested
+                       IP address directly. */
+                       ulAddressToLookup = *pulIPAddress;
+               }
+
+               if( eReturn == eARPCacheMiss )
+               {
+                       if( ulAddressToLookup == 0UL )
+                       {
+                               /* The address is not on the local network, and there is not a
+                               router. */
+                               eReturn = eCantSendPacket;
+                       }
+                       else
+                       {
+                               eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );
+
+                               if( eReturn == eARPCacheMiss )
+                               {
+                                       /* It might be that the ARP has to go to the gateway. */
+                                       *pulIPAddress = ulAddressToLookup;
+                               }
+                       }
+               }
+       }
+
+       return eReturn;
+}
+
+/*-----------------------------------------------------------*/
+
+static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress )
+{
+BaseType_t x;
+eARPLookupResult_t eReturn = eARPCacheMiss;
+
+       /* Loop through each entry in the ARP cache. */
+       for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+       {
+               /* Does this row in the ARP cache table hold an entry for the IP address
+               being queried? */
+               if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
+               {
+                       /* A matching valid entry was found. */
+                       if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
+                       {
+                               /* This entry is waiting an ARP reply, so is not valid. */
+                               eReturn = eCantSendPacket;
+                       }
+                       else
+                       {
+                               /* A valid entry was found. */
+                               memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
+                               eReturn = eARPCacheHit;
+                       }
+                       break;
+               }
+       }
+
+       return eReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vARPAgeCache( void )
+{
+BaseType_t x;
+TickType_t xTimeNow;
+
+       /* Loop through each entry in the ARP cache. */
+       for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+       {
+               /* If the entry is valid (its age is greater than zero). */
+               if( xARPCache[ x ].ucAge > 0U )
+               {
+                       /* Decrement the age value of the entry in this ARP cache table row.
+                       When the age reaches zero it is no longer considered valid. */
+                       ( xARPCache[ x ].ucAge )--;
+
+                       /* If the entry is not yet valid, then it is waiting an ARP
+                       reply, and the ARP request should be retransmitted. */
+                       if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
+                       {
+                               FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
+                       }
+                       else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
+                       {
+                               /* This entry will get removed soon.  See if the MAC address is
+                               still valid to prevent this happening. */
+                               iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
+                               FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
+                       }
+                       else
+                       {
+                               /* The age has just ticked down, with nothing to do. */
+                       }
+
+                       if( xARPCache[ x ].ucAge == 0u )
+                       {
+                               /* The entry is no longer valid.  Wipe it out. */
+                               iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
+                               xARPCache[ x ].ulIPAddress = 0UL;
+                       }
+               }
+       }
+
+       xTimeNow = xTaskGetTickCount ();
+
+       if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
+       {
+               FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
+               xLastGratuitousARPTime = xTimeNow;
+       }
+}
+/*-----------------------------------------------------------*/
+
+void vARPSendGratuitous( void )
+{
+       /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
+       time vARPAgeCache() is called. */
+       xLastGratuitousARPTime = ( TickType_t ) 0;
+
+       /* Let the IP-task call vARPAgeCache(). */
+       xSendEventToIPTask( eARPTimerEvent );
+}
+
+/*-----------------------------------------------------------*/
+void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
+{
+NetworkBufferDescriptor_t *pxNetworkBuffer;
+
+       /* This is called from the context of the IP event task, so a block time
+       must not be used. */
+       pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0 );
+
+       if( pxNetworkBuffer != NULL )
+       {
+               pxNetworkBuffer->ulIPAddress = ulIPAddress;
+               vARPGenerateRequestPacket( pxNetworkBuffer );
+
+               #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+               {
+                       if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
+                       {
+                       BaseType_t xIndex;
+
+                               for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
+                               {
+                                       pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
+                               }
+                               pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
+                       }
+               }
+               #endif
+               if( xIsCallingFromIPTask() != 0 )
+               {
+                       /* Only the IP-task is allowed to call this function directly. */
+                       xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
+               }
+               else
+               {
+               IPStackEvent_t xSendEvent;
+
+                       /* Send a message to the IP-task to send this ARP packet. */
+                       xSendEvent.eEventType = eNetworkTxEvent;
+                       xSendEvent.pvData = ( void * ) pxNetworkBuffer;
+                       if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
+                       {
+                               /* Failed to send the message, so release the network buffer. */
+                               vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
+                       }
+               }
+       }
+}
+
+void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
+{
+ARPPacket_t *pxARPPacket;
+
+       /* Buffer allocation ensures that buffers always have space
+       for an ARP packet. See buffer allocation implementations 1
+       and 2 under portable/BufferManagement. */
+       configASSERT( pxNetworkBuffer );
+       configASSERT( pxNetworkBuffer->xDataLength >= sizeof(ARPPacket_t) );
+
+       pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
+
+       /* memcpy the const part of the header information into the correct
+       location in the packet.  This copies:
+               xEthernetHeader.ulDestinationAddress
+               xEthernetHeader.usFrameType;
+               xARPHeader.usHardwareType;
+               xARPHeader.usProtocolType;
+               xARPHeader.ucHardwareAddressLength;
+               xARPHeader.ucProtocolAddressLength;
+               xARPHeader.usOperation;
+               xARPHeader.xTargetHardwareAddress;
+       */
+       memcpy( ( void * ) pxARPPacket, ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );
+       memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+       memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
+
+       memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
+       pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
+
+       pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
+
+       iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
+}
+/*-----------------------------------------------------------*/
+
+void FreeRTOS_ClearARP( void )
+{
+       memset( xARPCache, '\0', sizeof( xARPCache ) );
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
+
+       void FreeRTOS_PrintARPCache( void )
+       {
+       BaseType_t x, xCount = 0;
+
+               /* Loop through each entry in the ARP cache. */
+               for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
+               {
+                       if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) )
+                       {
+                               /* See if the MAC-address also matches, and we're all happy */
+                               FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",
+                                       x,
+                                       xARPCache[ x ].ucAge,
+                                       xARPCache[ x ].ulIPAddress,
+                                       xARPCache[ x ].xMACAddress.ucBytes[0],
+                                       xARPCache[ x ].xMACAddress.ucBytes[1],
+                                       xARPCache[ x ].xMACAddress.ucBytes[2],
+                                       xARPCache[ x ].xMACAddress.ucBytes[3],
+                                       xARPCache[ x ].xMACAddress.ucBytes[4],
+                                       xARPCache[ x ].xMACAddress.ucBytes[5] ) );
+                               xCount++;
+                       }
+               }
+
+               FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
+       }
+
+#endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */