2 * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.
\r
3 * Authors include Hein Tibosch and Richard Barry
\r
5 *******************************************************************************
\r
6 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
9 *** FREERTOS+TCP IS STILL IN THE LAB (mainly because the FTP and HTTP ***
\r
10 *** demos have a dependency on FreeRTOS+FAT, which is only in the Labs ***
\r
13 *** FreeRTOS+TCP is functional and has been used in commercial products ***
\r
14 *** for some time. Be aware however that we are still refining its ***
\r
15 *** design, the source code does not yet quite conform to the strict ***
\r
16 *** coding and style standards mandated by Real Time Engineers ltd., and ***
\r
17 *** the documentation and testing is not necessarily complete. ***
\r
19 *** PLEASE REPORT EXPERIENCES USING THE SUPPORT RESOURCES FOUND ON THE ***
\r
20 *** URL: http://www.FreeRTOS.org/contact Active early adopters may, at ***
\r
21 *** the sole discretion of Real Time Engineers Ltd., be offered versions ***
\r
22 *** under a license other than that described below. ***
\r
25 ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***
\r
26 *******************************************************************************
\r
28 * FreeRTOS+TCP can be used under two different free open source licenses. The
\r
29 * license that applies is dependent on the processor on which FreeRTOS+TCP is
\r
30 * executed, as follows:
\r
32 * If FreeRTOS+TCP is executed on one of the processors listed under the Special
\r
33 * License Arrangements heading of the FreeRTOS+TCP license information web
\r
34 * page, then it can be used under the terms of the FreeRTOS Open Source
\r
35 * License. If FreeRTOS+TCP is used on any other processor, then it can be used
\r
36 * under the terms of the GNU General Public License V2. Links to the relevant
\r
39 * The FreeRTOS+TCP License Information Page: http://www.FreeRTOS.org/tcp_license
\r
40 * The FreeRTOS Open Source License: http://www.FreeRTOS.org/license
\r
41 * The GNU General Public License Version 2: http://www.FreeRTOS.org/gpl-2.0.txt
\r
43 * FreeRTOS+TCP is distributed in the hope that it will be useful. You cannot
\r
44 * use FreeRTOS+TCP unless you agree that you use the software 'as is'.
\r
45 * FreeRTOS+TCP is provided WITHOUT ANY WARRANTY; without even the implied
\r
46 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
47 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
48 * implied, expressed, or statutory.
\r
50 * 1 tab == 4 spaces!
\r
52 * http://www.FreeRTOS.org
\r
53 * http://www.FreeRTOS.org/plus
\r
54 * http://www.FreeRTOS.org/labs
\r
58 /* Standard includes. */
\r
62 /* FreeRTOS includes. */
\r
63 #include "FreeRTOS.h"
\r
68 /* FreeRTOS+TCP includes. */
\r
69 #include "FreeRTOS_IP.h"
\r
70 #include "FreeRTOS_Sockets.h"
\r
71 #include "FreeRTOS_IP_Private.h"
\r
72 #include "FreeRTOS_ARP.h"
\r
73 #include "FreeRTOS_UDP_IP.h"
\r
74 #include "FreeRTOS_DHCP.h"
\r
75 #if( ipconfigUSE_LLMNR == 1 )
\r
76 #include "FreeRTOS_DNS.h"
\r
77 #endif /* ipconfigUSE_LLMNR */
\r
78 #include "NetworkInterface.h"
\r
79 #include "NetworkBufferManagement.h"
\r
82 /* When the age of an entry in the ARP table reaches this value (it counts down
\r
83 to zero, so this is an old entry) an ARP request will be sent to see if the
\r
84 entry is still valid and can therefore be refreshed. */
\r
85 #define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 )
\r
87 /* The time between gratuitous ARPs. */
\r
88 #ifndef arpGRATUITOUS_ARP_PERIOD
\r
89 #define arpGRATUITOUS_ARP_PERIOD ( pdMS_TO_TICKS( 20000 ) )
\r
92 /*-----------------------------------------------------------*/
\r
95 * Lookup an MAC address in the ARP cache from the IP address.
\r
97 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress );
\r
99 /*-----------------------------------------------------------*/
\r
101 /* The ARP cache. */
\r
102 static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
\r
104 /* The time at which the last gratuitous ARP was sent. Gratuitous ARPs are used
\r
105 to ensure ARP tables are up to date and to detect IP address conflicts. */
\r
106 static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;
\r
109 * IP-clash detection is currently only used internally. When DHCP doesn't respond, the
\r
110 * driver can try out a random LinkLayer IP address (169.254.x.x). It will send out a
\r
111 * gratuitos ARP message and, after a period of time, check the variables here below:
\r
113 #if( ipconfigARP_USE_CLASH_DETECTION != 0 )
\r
114 /* Becomes non-zero if another device responded to a gratuitos ARP message. */
\r
115 BaseType_t xARPHadIPClash;
\r
116 /* MAC-address of the other device containing the same IP-address. */
\r
117 MACAddress_t xARPClashMacAddress;
\r
118 #endif /* ipconfigARP_USE_CLASH_DETECTION */
\r
120 /* Part of the Ethernet and ARP headers are always constant when sending an IPv4
\r
121 ARP packet. This array defines the constant parts, allowing this part of the
\r
122 packet to be filled in using a simple memcpy() instead of individual writes. */
\r
123 static const uint8_t xDefaultPartARPPacketHeader[] =
\r
125 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
\r
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
\r
127 0x08, 0x06, /* Ethernet frame type (ipARP_FRAME_TYPE). */
\r
128 0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
\r
129 0x08, 0x00, /* usProtocolType. */
\r
130 ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */
\r
131 ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */
\r
132 0x00, 0x01, /* usOperation (ipARP_REQUEST). */
\r
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
\r
134 0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */
\r
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */
\r
138 /*-----------------------------------------------------------*/
\r
140 eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )
\r
142 eFrameProcessingResult_t eReturn = eReleaseBuffer;
\r
143 ARPHeader_t *pxARPHeader;
\r
144 uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
\r
146 pxARPHeader = &( pxARPFrame->xARPHeader );
\r
148 /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */
\r
149 memcpy( ( void *)&( ulSenderProtocolAddress ), ( void * )pxARPHeader->ucSenderProtocolAddress, sizeof( ulSenderProtocolAddress ) );
\r
150 /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
\r
151 ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
\r
153 traceARP_PACKET_RECEIVED();
\r
155 /* Don't do anything if the local IP address is zero because
\r
156 that means a DHCP request has not completed. */
\r
157 if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )
\r
159 switch( pxARPHeader->usOperation )
\r
161 case ipARP_REQUEST :
\r
162 /* The packet contained an ARP request. Was it for the IP
\r
163 address of the node running this code? */
\r
164 if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
\r
166 iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
\r
168 /* The request is for the address of this node. Add the
\r
169 entry into the ARP cache, or refresh the entry if it
\r
171 vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
\r
173 /* Generate a reply payload in the same buffer. */
\r
174 pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
\r
175 if( ulTargetProtocolAddress == ulSenderProtocolAddress )
\r
177 /* A double IP address is detected! */
\r
178 /* Give the sources MAC address the value of the broadcast address, will be swapped later */
\r
179 memcpy( pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) );
\r
180 memset( pxARPHeader->xTargetHardwareAddress.ucBytes, '\0', sizeof( MACAddress_t ) );
\r
181 pxARPHeader->ulTargetProtocolAddress = 0UL;
\r
185 memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) );
\r
186 pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
\r
188 memcpy( pxARPHeader->xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
\r
189 memcpy( ( void* )pxARPHeader->ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
\r
191 eReturn = eReturnEthernetFrame;
\r
196 iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
\r
197 vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
\r
198 /* Process received ARP frame to see if there is a clash. */
\r
199 #if( ipconfigARP_USE_CLASH_DETECTION != 0 )
\r
201 if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
\r
203 xARPHadIPClash = pdTRUE;
\r
204 memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
\r
207 #endif /* ipconfigARP_USE_CLASH_DETECTION */
\r
218 /*-----------------------------------------------------------*/
\r
220 #if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
\r
222 uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
\r
225 uint32_t lResult = 0;
\r
227 /* For each entry in the ARP cache table. */
\r
228 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
230 if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
\r
232 lResult = xARPCache[ x ].ulIPAddress;
\r
233 memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) );
\r
241 #endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
\r
242 /*-----------------------------------------------------------*/
\r
244 void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress )
\r
246 BaseType_t x, xIpEntry = -1, xMacEntry = -1, xUseEntry = 0;
\r
247 uint8_t ucMinAgeFound = 0U;
\r
249 #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
\r
250 /* Only process the IP address if it is on the local network.
\r
251 Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address
\r
252 and netmask are still unknown. */
\r
253 if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||
\r
254 ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )
\r
256 /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
\r
257 a different netmask will also be stored. After when replying to a UDP
\r
258 message from a different netmask, the IP address can be looped up and a
\r
259 reply sent. This option is useful for systems with multiple gateways,
\r
260 the reply will surely arrive. If ipconfigARP_STORES_REMOTE_ADDRESSES is
\r
261 zero the the gateway address is the only option. */
\r
265 /* Start with the maximum possible number. */
\r
268 /* For each entry in the ARP cache table. */
\r
269 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
271 /* Does this line in the cache table hold an entry for the IP
\r
272 address being queried? */
\r
273 if( xARPCache[ x ].ulIPAddress == ulIPAddress )
\r
275 if( pxMACAddress == NULL )
\r
277 /* In case the parameter pxMACAddress is NULL, an entry will be reserved to
\r
278 indicate that there is an outstanding ARP request, This entry will have
\r
279 "ucValid == pdFALSE". */
\r
284 /* See if the MAC-address also matches. */
\r
285 if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
\r
287 /* This function will be called for each received packet
\r
288 As this is by far the most common path the coding standard
\r
289 is relaxed in this case and a return is permitted as an
\r
291 xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
\r
292 xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
\r
296 /* Found an entry containing ulIPAddress, but the MAC address
\r
297 doesn't match. Might be an entry with ucValid=pdFALSE, waiting
\r
298 for an ARP reply. Still want to see if there is match with the
\r
299 given MAC address.ucBytes. If found, either of the two entries
\r
300 must be cleared. */
\r
303 else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
\r
305 /* Found an entry with the given MAC-address, but the IP-address
\r
306 is different. Continue looping to find a possible match with
\r
308 #if( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
\r
309 /* If ARP stores the MAC address of IP addresses outside the
\r
310 network, than the MAC address of the gateway should not be
\r
312 BaseType_t bIsLocal[ 2 ];
\r
313 bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
\r
314 bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
\r
315 if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )
\r
324 Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
\r
325 else if( xARPCache[ x ].ucAge < ucMinAgeFound )
\r
327 /* As the table is traversed, remember the table row that
\r
328 contains the oldest entry (the lowest age count, as ages are
\r
329 decremented to zero) so the row can be re-used if this function
\r
330 needs to add an entry that does not already exist. */
\r
331 ucMinAgeFound = xARPCache[ x ].ucAge;
\r
336 if( xMacEntry >= 0 )
\r
338 xUseEntry = xMacEntry;
\r
340 if( xIpEntry >= 0 )
\r
342 /* Both the MAC address as well as the IP address were found in
\r
343 different locations: clear the entry which matches the
\r
345 memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) );
\r
348 else if( xIpEntry >= 0 )
\r
350 /* An entry containing the IP-address was found, but it had a different MAC address */
\r
351 xUseEntry = xIpEntry;
\r
354 /* If the entry was not found, we use the oldest entry and set the IPaddress */
\r
355 xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;
\r
357 if( pxMACAddress != NULL )
\r
359 memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
\r
361 iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, (*pxMACAddress) );
\r
362 /* And this entry does not need immediate attention */
\r
363 xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
\r
364 xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
\r
366 else if( xIpEntry < 0 )
\r
368 xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
\r
369 xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
\r
373 /*-----------------------------------------------------------*/
\r
375 #if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
\r
376 eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress )
\r
379 eARPLookupResult_t eReturn = eARPCacheMiss;
\r
381 /* Loop through each entry in the ARP cache. */
\r
382 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
384 /* Does this row in the ARP cache table hold an entry for the MAC
\r
385 address being searched? */
\r
386 if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
\r
388 *pulIPAddress = xARPCache[ x ].ulIPAddress;
\r
389 eReturn = eARPCacheHit;
\r
396 #endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
\r
398 /*-----------------------------------------------------------*/
\r
400 eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress )
\r
402 eARPLookupResult_t eReturn;
\r
403 uint32_t ulAddressToLookup;
\r
405 #if( ipconfigUSE_LLMNR == 1 )
\r
406 if( *pulIPAddress == ipLLMNR_IP_ADDR ) /* Is in network byte order. */
\r
408 /* The LLMNR IP-address has a fixed virtual MAC address. */
\r
409 memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );
\r
410 eReturn = eARPCacheHit;
\r
414 if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) || /* Is it the general broadcast address 255.255.255.255? */
\r
415 ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) )/* Or a local broadcast address, eg 192.168.1.255? */
\r
417 /* This is a broadcast so uses the broadcast MAC address. */
\r
418 memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
\r
419 eReturn = eARPCacheHit;
\r
421 else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
\r
423 /* The IP address has not yet been assigned, so there is nothing that
\r
425 eReturn = eCantSendPacket;
\r
429 eReturn = eARPCacheMiss;
\r
431 if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
\r
433 #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
\r
434 eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );
\r
436 if( eReturn == eARPCacheHit )
\r
438 /* The stack is configured to store 'remote IP addresses', i.e. addresses
\r
439 belonging to a different the netmask. prvCacheLookup() returned a hit, so
\r
440 the MAC address is known */
\r
445 /* The IP address is off the local network, so look up the
\r
446 hardware address of the router, if any. */
\r
447 if( xNetworkAddressing.ulGatewayAddress != ( uint32_t )0u )
\r
449 ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
\r
453 ulAddressToLookup = *pulIPAddress;
\r
459 /* The IP address is on the local network, so lookup the requested
\r
460 IP address directly. */
\r
461 ulAddressToLookup = *pulIPAddress;
\r
464 if( eReturn == eARPCacheMiss )
\r
466 if( ulAddressToLookup == 0UL )
\r
468 /* The address is not on the local network, and there is not a
\r
470 eReturn = eCantSendPacket;
\r
474 eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );
\r
476 if( eReturn == eARPCacheMiss )
\r
478 /* It might be that the ARP has to go to the gateway. */
\r
479 *pulIPAddress = ulAddressToLookup;
\r
488 /*-----------------------------------------------------------*/
\r
490 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress )
\r
493 eARPLookupResult_t eReturn = eARPCacheMiss;
\r
495 /* Loop through each entry in the ARP cache. */
\r
496 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
498 /* Does this row in the ARP cache table hold an entry for the IP address
\r
500 if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
\r
502 /* A matching valid entry was found. */
\r
503 if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
\r
505 /* This entry is waiting an ARP reply, so is not valid. */
\r
506 eReturn = eCantSendPacket;
\r
510 /* A valid entry was found. */
\r
511 memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
\r
512 eReturn = eARPCacheHit;
\r
520 /*-----------------------------------------------------------*/
\r
522 void vARPAgeCache( void )
\r
525 TickType_t xTimeNow;
\r
527 /* Loop through each entry in the ARP cache. */
\r
528 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
530 /* If the entry is valid (its age is greater than zero). */
\r
531 if( xARPCache[ x ].ucAge > 0U )
\r
533 /* Decrement the age value of the entry in this ARP cache table row.
\r
534 When the age reaches zero it is no longer considered valid. */
\r
535 ( xARPCache[ x ].ucAge )--;
\r
537 /* If the entry is not yet valid, then it is waiting an ARP
\r
538 reply, and the ARP request should be retransmitted. */
\r
539 if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
\r
541 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
\r
543 else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
\r
545 /* This entry will get removed soon. See if the MAC address is
\r
546 still valid to prevent this happening. */
\r
547 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
\r
548 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
\r
552 /* The age has just ticked down, with nothing to do. */
\r
555 if( xARPCache[ x ].ucAge == 0u )
\r
557 /* The entry is no longer valid. Wipe it out. */
\r
558 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
\r
559 xARPCache[ x ].ulIPAddress = 0UL;
\r
564 xTimeNow = xTaskGetTickCount ();
\r
566 if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
\r
568 FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
\r
569 xLastGratuitousARPTime = xTimeNow;
\r
572 /*-----------------------------------------------------------*/
\r
574 void vARPSendGratuitous( void )
\r
576 /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
\r
577 time vARPAgeCache() is called. */
\r
578 xLastGratuitousARPTime = ( TickType_t ) 0;
\r
580 /* Let the IP-task call vARPAgeCache(). */
\r
581 xSendEventToIPTask( eARPTimerEvent );
\r
584 /*-----------------------------------------------------------*/
\r
585 void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
\r
587 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
589 /* This is called from the context of the IP event task, so a block time
\r
590 must not be used. */
\r
591 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0 );
\r
593 if( pxNetworkBuffer != NULL )
\r
595 pxNetworkBuffer->ulIPAddress = ulIPAddress;
\r
596 vARPGenerateRequestPacket( pxNetworkBuffer );
\r
598 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
600 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
\r
604 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
\r
606 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
\r
608 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
\r
613 xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
\r
617 void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
\r
619 ARPPacket_t *pxARPPacket;
\r
621 pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;
\r
623 /* memcpy the const part of the header information into the correct
\r
624 location in the packet. This copies:
\r
625 xEthernetHeader.ulDestinationAddress
\r
626 xEthernetHeader.usFrameType;
\r
627 xARPHeader.usHardwareType;
\r
628 xARPHeader.usProtocolType;
\r
629 xARPHeader.ucHardwareAddressLength;
\r
630 xARPHeader.ucProtocolAddressLength;
\r
631 xARPHeader.usOperation;
\r
632 xARPHeader.xTargetHardwareAddress;
\r
634 memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );
\r
635 memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
636 memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
\r
638 memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
\r
639 pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
\r
641 pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
\r
643 iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
\r
645 /*-----------------------------------------------------------*/
\r
647 void FreeRTOS_ClearARP( void )
\r
649 memset( xARPCache, '\0', sizeof( xARPCache ) );
\r
651 /*-----------------------------------------------------------*/
\r
653 #if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
\r
655 void FreeRTOS_PrintARPCache( void )
\r
657 BaseType_t x, xCount = 0;
\r
659 /* Loop through each entry in the ARP cache. */
\r
660 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
\r
662 if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) )
\r
664 /* See if the MAC-address also matches, and we're all happy */
\r
665 FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",
\r
667 xARPCache[ x ].ucAge,
\r
668 xARPCache[ x ].ulIPAddress,
\r
669 xARPCache[ x ].xMACAddress.ucBytes[0],
\r
670 xARPCache[ x ].xMACAddress.ucBytes[1],
\r
671 xARPCache[ x ].xMACAddress.ucBytes[2],
\r
672 xARPCache[ x ].xMACAddress.ucBytes[3],
\r
673 xARPCache[ x ].xMACAddress.ucBytes[4],
\r
674 xARPCache[ x ].xMACAddress.ucBytes[5] ) );
\r
679 FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
\r
682 #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
\r