]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
Added +TCP code to main repo.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_ARP.c
1 /*\r
2  * FreeRTOS+TCP Labs Build 160919 (C) 2016 Real Time Engineers ltd.\r
3  * Authors include Hein Tibosch and Richard Barry\r
4  *\r
5  *******************************************************************************\r
6  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
7  ***                                                                         ***\r
8  ***                                                                         ***\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
11  ***   download):                                                            ***\r
12  ***                                                                         ***\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
18  ***                                                                         ***\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
23  ***                                                                         ***\r
24  ***                                                                         ***\r
25  ***** NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ******* NOTE ***\r
26  *******************************************************************************\r
27  *\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
31  *\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
37  * licenses follow:\r
38  *\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
42  *\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
49  *\r
50  * 1 tab == 4 spaces!\r
51  *\r
52  * http://www.FreeRTOS.org\r
53  * http://www.FreeRTOS.org/plus\r
54  * http://www.FreeRTOS.org/labs\r
55  *\r
56  */\r
57 \r
58 /* Standard includes. */\r
59 #include <stdint.h>\r
60 #include <stdio.h>\r
61 \r
62 /* FreeRTOS includes. */\r
63 #include "FreeRTOS.h"\r
64 #include "task.h"\r
65 #include "queue.h"\r
66 #include "semphr.h"\r
67 \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
80 \r
81 \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
86 \r
87 /* The time between gratuitous ARPs. */\r
88 #ifndef arpGRATUITOUS_ARP_PERIOD\r
89         #define arpGRATUITOUS_ARP_PERIOD                                        ( pdMS_TO_TICKS( 20000 ) )\r
90 #endif\r
91 \r
92 /*-----------------------------------------------------------*/\r
93 \r
94 /*\r
95  * Lookup an MAC address in the ARP cache from the IP address.\r
96  */\r
97 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress );\r
98 \r
99 /*-----------------------------------------------------------*/\r
100 \r
101 /* The ARP cache. */\r
102 static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];\r
103 \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
107 \r
108 /*\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
112  */\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
119 \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
124 {\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
136 };\r
137 \r
138 /*-----------------------------------------------------------*/\r
139 \r
140 eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )\r
141 {\r
142 eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
143 ARPHeader_t *pxARPHeader;\r
144 uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;\r
145 \r
146         pxARPHeader = &( pxARPFrame->xARPHeader );\r
147 \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
152 \r
153         traceARP_PACKET_RECEIVED();\r
154 \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
158         {\r
159                 switch( pxARPHeader->usOperation )\r
160                 {\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
165                                 {\r
166                                         iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );\r
167 \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
170                                         already exists. */\r
171                                         vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );\r
172 \r
173                                         /* Generate a reply payload in the same buffer. */\r
174                                         pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;\r
175                                         if( ulTargetProtocolAddress == ulSenderProtocolAddress )\r
176                                         {\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
182                                         }\r
183                                         else\r
184                                         {\r
185                                                 memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) );\r
186                                                 pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;\r
187                                         }\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
190 \r
191                                         eReturn = eReturnEthernetFrame;\r
192                                 }\r
193                                 break;\r
194 \r
195                         case ipARP_REPLY :\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
200                                 {\r
201                                         if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
202                                         {\r
203                                                 xARPHadIPClash = pdTRUE;\r
204                                                 memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );\r
205                                         }\r
206                                 }\r
207                                 #endif /* ipconfigARP_USE_CLASH_DETECTION */\r
208                                 break;\r
209 \r
210                         default :\r
211                                 /* Invalid. */\r
212                                 break;\r
213                 }\r
214         }\r
215 \r
216         return eReturn;\r
217 }\r
218 /*-----------------------------------------------------------*/\r
219 \r
220 #if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )\r
221 \r
222         uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )\r
223         {\r
224         BaseType_t x;\r
225         uint32_t lResult = 0;\r
226 \r
227                 /* For each entry in the ARP cache table. */\r
228                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
229                 {\r
230                         if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )\r
231                         {\r
232                                 lResult = xARPCache[ x ].ulIPAddress;\r
233                                 memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) );\r
234                                 break;\r
235                         }\r
236                 }\r
237 \r
238                 return lResult;\r
239         }\r
240 \r
241 #endif  /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */\r
242 /*-----------------------------------------------------------*/\r
243 \r
244 void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress )\r
245 {\r
246 BaseType_t x, xIpEntry = -1, xMacEntry = -1, xUseEntry = 0;\r
247 uint8_t ucMinAgeFound = 0U;\r
248 \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
255         #else\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
262                 if( pdTRUE )\r
263         #endif\r
264         {\r
265                 /* Start with the maximum possible number. */\r
266                 ucMinAgeFound--;\r
267 \r
268                 /* For each entry in the ARP cache table. */\r
269                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
270                 {\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
274                         {\r
275                                 if( pxMACAddress == NULL )\r
276                                 {\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
280                                         xIpEntry = x;\r
281                                         break;\r
282                                 }\r
283 \r
284                                 /* See if the MAC-address also matches. */\r
285                                 if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )\r
286                                 {\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
290                                         optimisation. */\r
291                                         xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;\r
292                                         xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;\r
293                                         return;\r
294                                 }\r
295 \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
301                                 xIpEntry = x;\r
302                         }\r
303                         else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )\r
304                         {\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
307                                 ulIPAddress. */\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
311                                 overwritten. */\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
316                                 {\r
317                                         xMacEntry = x;\r
318                                 }\r
319         #else\r
320                                 xMacEntry = x;\r
321         #endif\r
322                         }\r
323                         /* _HT_\r
324                         Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */\r
325                         else if( xARPCache[ x ].ucAge < ucMinAgeFound )\r
326                         {\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
332                                 xUseEntry = x;\r
333                         }\r
334                 }\r
335 \r
336                 if( xMacEntry >= 0 )\r
337                 {\r
338                         xUseEntry = xMacEntry;\r
339 \r
340                         if( xIpEntry >= 0 )\r
341                         {\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
344                                 IP-address */\r
345                                 memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) );\r
346                         }\r
347                 }\r
348                 else if( xIpEntry >= 0 )\r
349                 {\r
350                         /* An entry containing the IP-address was found, but it had a different MAC address */\r
351                         xUseEntry = xIpEntry;\r
352                 }\r
353 \r
354                 /* If the entry was not found, we use the oldest entry and set the IPaddress */\r
355                 xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;\r
356 \r
357                 if( pxMACAddress != NULL )\r
358                 {\r
359                         memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );\r
360 \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
365                 }\r
366                 else if( xIpEntry < 0 )\r
367                 {\r
368                         xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;\r
369                         xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;\r
370                 }\r
371         }\r
372 }\r
373 /*-----------------------------------------------------------*/\r
374 \r
375 #if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )\r
376         eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress )\r
377         {\r
378         BaseType_t x;\r
379         eARPLookupResult_t eReturn = eARPCacheMiss;\r
380 \r
381                 /* Loop through each entry in the ARP cache. */\r
382                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
383                 {\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
387                         {\r
388                                 *pulIPAddress = xARPCache[ x ].ulIPAddress;\r
389                                 eReturn = eARPCacheHit;\r
390                                 break;\r
391                         }\r
392                 }\r
393 \r
394                 return eReturn;\r
395         }\r
396 #endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */\r
397 \r
398 /*-----------------------------------------------------------*/\r
399 \r
400 eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress )\r
401 {\r
402 eARPLookupResult_t eReturn;\r
403 uint32_t ulAddressToLookup;\r
404 \r
405 #if( ipconfigUSE_LLMNR == 1 )\r
406         if( *pulIPAddress == ipLLMNR_IP_ADDR )  /* Is in network byte order. */\r
407         {\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
411         }\r
412         else\r
413 #endif\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
416         {\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
420         }\r
421         else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )\r
422         {\r
423                 /* The IP address has not yet been assigned, so there is nothing that\r
424                 can be done. */\r
425                 eReturn = eCantSendPacket;\r
426         }\r
427         else\r
428         {\r
429                 eReturn = eARPCacheMiss;\r
430 \r
431                 if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )\r
432                 {\r
433 #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )\r
434                         eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );\r
435 \r
436                         if( eReturn == eARPCacheHit )\r
437                         {\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
441                         }\r
442                         else\r
443 #endif\r
444                         {\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
448                                 {\r
449                                         ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;\r
450                                 }\r
451                                 else\r
452                                 {\r
453                                         ulAddressToLookup = *pulIPAddress;\r
454                                 }\r
455                         }\r
456                 }\r
457                 else\r
458                 {\r
459                         /* The IP address is on the local network, so lookup the requested\r
460                         IP address directly. */\r
461                         ulAddressToLookup = *pulIPAddress;\r
462                 }\r
463 \r
464                 if( eReturn == eARPCacheMiss )\r
465                 {\r
466                         if( ulAddressToLookup == 0UL )\r
467                         {\r
468                                 /* The address is not on the local network, and there is not a\r
469                                 router. */\r
470                                 eReturn = eCantSendPacket;\r
471                         }\r
472                         else\r
473                         {\r
474                                 eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );\r
475 \r
476                                 if( eReturn == eARPCacheMiss )\r
477                                 {\r
478                                         /* It might be that the ARP has to go to the gateway. */\r
479                                         *pulIPAddress = ulAddressToLookup;\r
480                                 }\r
481                         }\r
482                 }\r
483         }\r
484 \r
485         return eReturn;\r
486 }\r
487 \r
488 /*-----------------------------------------------------------*/\r
489 \r
490 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress )\r
491 {\r
492 BaseType_t x;\r
493 eARPLookupResult_t eReturn = eARPCacheMiss;\r
494 \r
495         /* Loop through each entry in the ARP cache. */\r
496         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
497         {\r
498                 /* Does this row in the ARP cache table hold an entry for the IP address\r
499                 being queried? */\r
500                 if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )\r
501                 {\r
502                         /* A matching valid entry was found. */\r
503                         if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )\r
504                         {\r
505                                 /* This entry is waiting an ARP reply, so is not valid. */\r
506                                 eReturn = eCantSendPacket;\r
507                         }\r
508                         else\r
509                         {\r
510                                 /* A valid entry was found. */\r
511                                 memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );\r
512                                 eReturn = eARPCacheHit;\r
513                         }\r
514                         break;\r
515                 }\r
516         }\r
517 \r
518         return eReturn;\r
519 }\r
520 /*-----------------------------------------------------------*/\r
521 \r
522 void vARPAgeCache( void )\r
523 {\r
524 BaseType_t x;\r
525 TickType_t xTimeNow;\r
526 \r
527         /* Loop through each entry in the ARP cache. */\r
528         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
529         {\r
530                 /* If the entry is valid (its age is greater than zero). */\r
531                 if( xARPCache[ x ].ucAge > 0U )\r
532                 {\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
536 \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
540                         {\r
541                                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );\r
542                         }\r
543                         else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )\r
544                         {\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
549                         }\r
550                         else\r
551                         {\r
552                                 /* The age has just ticked down, with nothing to do. */\r
553                         }\r
554 \r
555                         if( xARPCache[ x ].ucAge == 0u )\r
556                         {\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
560                         }\r
561                 }\r
562         }\r
563 \r
564         xTimeNow = xTaskGetTickCount ();\r
565 \r
566         if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )\r
567         {\r
568                 FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );\r
569                 xLastGratuitousARPTime = xTimeNow;\r
570         }\r
571 }\r
572 /*-----------------------------------------------------------*/\r
573 \r
574 void vARPSendGratuitous( void )\r
575 {\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
579 \r
580         /* Let the IP-task call vARPAgeCache(). */\r
581         xSendEventToIPTask( eARPTimerEvent );\r
582 }\r
583 \r
584 /*-----------------------------------------------------------*/\r
585 void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )\r
586 {\r
587 NetworkBufferDescriptor_t *pxNetworkBuffer;\r
588 \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
592 \r
593         if( pxNetworkBuffer != NULL )\r
594         {\r
595                 pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
596                 vARPGenerateRequestPacket( pxNetworkBuffer );\r
597 \r
598                 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
599                 {\r
600                         if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
601                         {\r
602                         BaseType_t xIndex;\r
603 \r
604                                 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
605                                 {\r
606                                         pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
607                                 }\r
608                                 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
609                         }\r
610                 }\r
611                 #endif\r
612 \r
613                 xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );\r
614         }\r
615 }\r
616 \r
617 void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
618 {\r
619 ARPPacket_t *pxARPPacket;\r
620 \r
621         pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
622 \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
633         */\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
637 \r
638         memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );\r
639         pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;\r
640 \r
641         pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );\r
642 \r
643         iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );\r
644 }\r
645 /*-----------------------------------------------------------*/\r
646 \r
647 void FreeRTOS_ClearARP( void )\r
648 {\r
649         memset( xARPCache, '\0', sizeof( xARPCache ) );\r
650 }\r
651 /*-----------------------------------------------------------*/\r
652 \r
653 #if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )\r
654 \r
655         void FreeRTOS_PrintARPCache( void )\r
656         {\r
657         BaseType_t x, xCount = 0;\r
658 \r
659                 /* Loop through each entry in the ARP cache. */\r
660                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
661                 {\r
662                         if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) )\r
663                         {\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
666                                         x,\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
675                                 xCount++;\r
676                         }\r
677                 }\r
678 \r
679                 FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );\r
680         }\r
681 \r
682 #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */\r