]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_ARP.c
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
new file mode 100644 (file)
index 0000000..5f2ff25
--- /dev/null
@@ -0,0 +1,682 @@
+/*\r
+ * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.\r
+ * Authors include Hein Tibosch and Richard Barry\r
+ *\r
+ *******************************************************************************\r
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
+ ***                                                                         ***\r
+ ***                                                                         ***\r
+ ***   FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP     ***\r
+ ***   demos have a dependency on FreeRTOS+FAT, which is only in the Labs    ***\r
+ ***   download):                                                            ***\r
+ ***                                                                         ***\r
+ ***   FreeRTOS+TCP is functional and has been used in commercial products   ***\r
+ ***   for some time.  Be aware however that we are still refining its       ***\r
+ ***   design, the source code does not yet quite conform to the strict      ***\r
+ ***   coding and style standards mandated by Real Time Engineers ltd., and  ***\r
+ ***   the documentation and testing is not necessarily complete.            ***\r
+ ***                                                                         ***\r
+ ***   PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE    ***\r
+ ***   URL: http://www.FreeRTOS.org/contact  Active early adopters may, at   ***\r
+ ***   the sole discretion of Real Time Engineers Ltd., be offered versions  ***\r
+ ***   under a license other than that described below.                      ***\r
+ ***                                                                         ***\r
+ ***                                                                         ***\r
+ ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
+ *******************************************************************************\r
+ *\r
+ * FreeRTOS+TCP can be used under two different free open source licenses.  The\r
+ * license that applies is dependent on the processor on which FreeRTOS+TCP is\r
+ * executed, as follows:\r
+ *\r
+ * If FreeRTOS+TCP is executed on one of the processors listed under the Special\r
+ * License Arrangements heading of the FreeRTOS+TCP license information web\r
+ * page, then it can be used under the terms of the FreeRTOS Open Source\r
+ * License.  If FreeRTOS+TCP is used on any other processor, then it can be used\r
+ * under the terms of the GNU General Public License V2.  Links to the relevant\r
+ * licenses follow:\r
+ *\r
+ * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license\r
+ * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license\r
+ * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt\r
+ *\r
+ * FreeRTOS+TCP is distributed in the hope that it will be useful.  You cannot\r
+ * use FreeRTOS+TCP unless you agree that you use the software 'as is'.\r
+ * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied\r
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
+ * implied, expressed, or statutory.\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://www.FreeRTOS.org/plus\r
+ * http://www.FreeRTOS.org/labs\r
+ *\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, xIpEntry = -1, xMacEntry = -1, 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
+\r
+               xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );\r
+       }\r
+}\r
+\r
+void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
+{\r
+ARPPacket_t *pxARPPacket;\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->xEthernetHeader ), ( 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