diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c')
-rw-r--r-- | FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c | 1350 |
1 files changed, 675 insertions, 675 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c index c98a7e870..7d8ed18c6 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c @@ -1,675 +1,675 @@ -/*
- * 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 ) */
+/* + * 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 ) */ |