--- /dev/null
+/*\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