/* * FreeRTOS+TCP V2.2.1 * 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 #include /* 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 */ /*-----------------------------------------------------------*/ 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. */ ( void ) memcpy( ( void * )&( ulSenderProtocolAddress ), ( const 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 */ ( void ) memcpy( ( void * ) pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, ( const void * ) xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) ); ( void ) memset( pxARPHeader->xTargetHardwareAddress.ucBytes, 0, sizeof( MACAddress_t ) ); pxARPHeader->ulTargetProtocolAddress = 0UL; } else { ( void ) memcpy( ( void * ) pxARPHeader->xTargetHardwareAddress.ucBytes, ( const void * ) pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) ); pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress; } ( void ) memcpy( ( void * ) pxARPHeader->xSenderHardwareAddress.ucBytes, ( const void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) ); ( void ) memcpy( ( void * ) pxARPHeader->ucSenderProtocolAddress, ( const 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; ( void ) memcpy( ( void * ) xARPClashMacAddress.ucBytes, ( const void * ) 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; ( void ) 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; } else { /* Do nothing. */ } } 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 */ ( void ) 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; } else { /* Do nothing! xUseEntry retains its value */ } /* If the entry was not found, we use the oldest entry and set the IPaddress */ xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress; if( pxMACAddress != NULL ) { ( void ) memcpy( ( void * ) xARPCache[ xUseEntry ].xMACAddress.ucBytes, ( const void * ) 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; } else { /* Do nothing. (pxMACAddress == NULL) and (xIPEntry > 0) * Implies that an IP address was found but we don't have * a MAC address for it. Therefore, no action required */ } } } /*-----------------------------------------------------------*/ #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( ( void * ) pxMACAddress->ucBytes, ( const void * ) 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. */ ( void ) memcpy( ( void * ) pxMACAddress->ucBytes, ( const void * ) 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. */ ( void ) memcpy( ( void * ) pxMACAddress->ucBytes, ( const void * ) 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. */ ( void ) memcpy( ( void * ) pxMACAddress->ucBytes, ( const void * ) 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(). */ ( void )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. */ if( xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE ) != pdTRUE ) { /* Not sent? Bad news. Maybe link is down? */ #if ( ipconfigHAS_DEBUG_PRINTF != 0 ) FreeRTOS_printf( ( "xNetworkInterfaceOutput failed. Link down?\n" ) ); #else ; /* Do nothing */ #endif } } 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; /* 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. */ }; /* Buffer allocation ensures that buffers always have space * for an ARP packet. See buffer allocation implementations 1 * and 2 under portable/BufferManagement. */ configASSERT( pxNetworkBuffer != NULL ); 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; */ ( void ) memcpy( ( void * ) pxARPPacket, ( const void * )xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) ); ( void ) memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes, ( const void * ) ipLOCAL_MAC_ADDRESS, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES ); ( void ) memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( const void * )ipLOCAL_MAC_ADDRESS, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES ); ( void ) memcpy( ( void * )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( const 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 ) { ( void ) memset( xARPCache, 0, sizeof( xARPCache ) ); } /*-----------------------------------------------------------*/ #if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) /* MISRA c 2012 rule 8.7 relaxed since this function can be * called from external location when debugging is enabled */ /* coverity[misra_c_2012_rule_8_7_violation] */ 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 ) */