]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c
Sync with TCP version from AWS, including:
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_ARP.c
1 /*\r
2  * FreeRTOS+TCP V2.0.3\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 /* Standard includes. */\r
27 #include <stdint.h>\r
28 #include <stdio.h>\r
29 \r
30 /* FreeRTOS includes. */\r
31 #include "FreeRTOS.h"\r
32 #include "task.h"\r
33 #include "queue.h"\r
34 #include "semphr.h"\r
35 \r
36 /* FreeRTOS+TCP includes. */\r
37 #include "FreeRTOS_IP.h"\r
38 #include "FreeRTOS_Sockets.h"\r
39 #include "FreeRTOS_IP_Private.h"\r
40 #include "FreeRTOS_ARP.h"\r
41 #include "FreeRTOS_UDP_IP.h"\r
42 #include "FreeRTOS_DHCP.h"\r
43 #if( ipconfigUSE_LLMNR == 1 )\r
44         #include "FreeRTOS_DNS.h"\r
45 #endif /* ipconfigUSE_LLMNR */\r
46 #include "NetworkInterface.h"\r
47 #include "NetworkBufferManagement.h"\r
48 \r
49 \r
50 /* When the age of an entry in the ARP table reaches this value (it counts down\r
51 to zero, so this is an old entry) an ARP request will be sent to see if the\r
52 entry is still valid and can therefore be refreshed. */\r
53 #define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST           ( 3 )\r
54 \r
55 /* The time between gratuitous ARPs. */\r
56 #ifndef arpGRATUITOUS_ARP_PERIOD\r
57         #define arpGRATUITOUS_ARP_PERIOD                                        ( pdMS_TO_TICKS( 20000 ) )\r
58 #endif\r
59 \r
60 /*-----------------------------------------------------------*/\r
61 \r
62 /*\r
63  * Lookup an MAC address in the ARP cache from the IP address.\r
64  */\r
65 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress );\r
66 \r
67 /*-----------------------------------------------------------*/\r
68 \r
69 /* The ARP cache. */\r
70 static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];\r
71 \r
72 /* The time at which the last gratuitous ARP was sent.  Gratuitous ARPs are used\r
73 to ensure ARP tables are up to date and to detect IP address conflicts. */\r
74 static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;\r
75 \r
76 /*\r
77  * IP-clash detection is currently only used internally. When DHCP doesn't respond, the\r
78  * driver can try out a random LinkLayer IP address (169.254.x.x).  It will send out a\r
79  * gratuitos ARP message and, after a period of time, check the variables here below:\r
80  */\r
81 #if( ipconfigARP_USE_CLASH_DETECTION != 0 )\r
82         /* Becomes non-zero if another device responded to a gratuitos ARP message. */\r
83         BaseType_t xARPHadIPClash;\r
84         /* MAC-address of the other device containing the same IP-address. */\r
85         MACAddress_t xARPClashMacAddress;\r
86 #endif /* ipconfigARP_USE_CLASH_DETECTION */\r
87 \r
88 /* Part of the Ethernet and ARP headers are always constant when sending an IPv4\r
89 ARP packet.  This array defines the constant parts, allowing this part of the\r
90 packet to be filled in using a simple memcpy() instead of individual writes. */\r
91 static const uint8_t xDefaultPartARPPacketHeader[] =\r
92 {\r
93         0xff, 0xff, 0xff, 0xff, 0xff, 0xff,     /* Ethernet destination address. */\r
94         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* Ethernet source address. */\r
95         0x08, 0x06,                                                     /* Ethernet frame type (ipARP_FRAME_TYPE). */\r
96         0x00, 0x01,                                                     /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */\r
97         0x08, 0x00,                                                             /* usProtocolType. */\r
98         ipMAC_ADDRESS_LENGTH_BYTES,                     /* ucHardwareAddressLength. */\r
99         ipIP_ADDRESS_LENGTH_BYTES,                              /* ucProtocolAddressLength. */\r
100         0x00, 0x01,                                                     /* usOperation (ipARP_REQUEST). */\r
101         0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     /* xSenderHardwareAddress. */\r
102         0x00, 0x00, 0x00, 0x00,                                 /* ulSenderProtocolAddress. */\r
103         0x00, 0x00, 0x00, 0x00, 0x00, 0x00              /* xTargetHardwareAddress. */\r
104 };\r
105 \r
106 /*-----------------------------------------------------------*/\r
107 \r
108 eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )\r
109 {\r
110 eFrameProcessingResult_t eReturn = eReleaseBuffer;\r
111 ARPHeader_t *pxARPHeader;\r
112 uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;\r
113 \r
114         pxARPHeader = &( pxARPFrame->xARPHeader );\r
115 \r
116         /* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */\r
117         memcpy( ( void *)&( ulSenderProtocolAddress ), ( void * )pxARPHeader->ucSenderProtocolAddress, sizeof( ulSenderProtocolAddress ) );\r
118         /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */\r
119         ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;\r
120 \r
121         traceARP_PACKET_RECEIVED();\r
122 \r
123         /* Don't do anything if the local IP address is zero because\r
124         that means a DHCP request has not completed. */\r
125         if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )\r
126         {\r
127                 switch( pxARPHeader->usOperation )\r
128                 {\r
129                         case ipARP_REQUEST      :\r
130                                 /* The packet contained an ARP request.  Was it for the IP\r
131                                 address of the node running this code? */\r
132                                 if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
133                                 {\r
134                                         iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );\r
135 \r
136                                         /* The request is for the address of this node.  Add the\r
137                                         entry into the ARP cache, or refresh the entry if it\r
138                                         already exists. */\r
139                                         vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );\r
140 \r
141                                         /* Generate a reply payload in the same buffer. */\r
142                                         pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;\r
143                                         if( ulTargetProtocolAddress == ulSenderProtocolAddress )\r
144                                         {\r
145                                                 /* A double IP address is detected! */\r
146                                                 /* Give the sources MAC address the value of the broadcast address, will be swapped later */\r
147                                                 memcpy( pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes, xBroadcastMACAddress.ucBytes, sizeof( xBroadcastMACAddress ) );\r
148                                                 memset( pxARPHeader->xTargetHardwareAddress.ucBytes, '\0', sizeof( MACAddress_t ) );\r
149                                                 pxARPHeader->ulTargetProtocolAddress = 0UL;\r
150                                         }\r
151                                         else\r
152                                         {\r
153                                                 memcpy( pxARPHeader->xTargetHardwareAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( MACAddress_t ) );\r
154                                                 pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;\r
155                                         }\r
156                                         memcpy( pxARPHeader->xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );\r
157                                         memcpy( ( void* )pxARPHeader->ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPHeader->ucSenderProtocolAddress ) );\r
158 \r
159                                         eReturn = eReturnEthernetFrame;\r
160                                 }\r
161                                 break;\r
162 \r
163                         case ipARP_REPLY :\r
164                                 iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );\r
165                                 vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );\r
166                                 /* Process received ARP frame to see if there is a clash. */\r
167                                 #if( ipconfigARP_USE_CLASH_DETECTION != 0 )\r
168                                 {\r
169                                         if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )\r
170                                         {\r
171                                                 xARPHadIPClash = pdTRUE;\r
172                                                 memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );\r
173                                         }\r
174                                 }\r
175                                 #endif /* ipconfigARP_USE_CLASH_DETECTION */\r
176                                 break;\r
177 \r
178                         default :\r
179                                 /* Invalid. */\r
180                                 break;\r
181                 }\r
182         }\r
183 \r
184         return eReturn;\r
185 }\r
186 /*-----------------------------------------------------------*/\r
187 \r
188 #if( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )\r
189 \r
190         uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )\r
191         {\r
192         BaseType_t x;\r
193         uint32_t lResult = 0;\r
194 \r
195                 /* For each entry in the ARP cache table. */\r
196                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
197                 {\r
198                         if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )\r
199                         {\r
200                                 lResult = xARPCache[ x ].ulIPAddress;\r
201                                 memset( &xARPCache[ x ], '\0', sizeof( xARPCache[ x ] ) );\r
202                                 break;\r
203                         }\r
204                 }\r
205 \r
206                 return lResult;\r
207         }\r
208 \r
209 #endif  /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */\r
210 /*-----------------------------------------------------------*/\r
211 \r
212 void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress, const uint32_t ulIPAddress )\r
213 {\r
214 BaseType_t x, xIpEntry = -1, xMacEntry = -1, xUseEntry = 0;\r
215 uint8_t ucMinAgeFound = 0U;\r
216 \r
217         #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )\r
218                 /* Only process the IP address if it is on the local network.\r
219                 Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address\r
220                 and netmask are still unknown. */\r
221                 if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||\r
222                         ( *ipLOCAL_IP_ADDRESS_POINTER == 0ul ) )\r
223         #else\r
224                 /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with\r
225                 a different netmask will also be stored.  After when replying to a UDP\r
226                 message from a different netmask, the IP address can be looped up and a\r
227                 reply sent.  This option is useful for systems with multiple gateways,\r
228                 the reply will surely arrive.  If ipconfigARP_STORES_REMOTE_ADDRESSES is\r
229                 zero the the gateway address is the only option. */\r
230                 if( pdTRUE )\r
231         #endif\r
232         {\r
233                 /* Start with the maximum possible number. */\r
234                 ucMinAgeFound--;\r
235 \r
236                 /* For each entry in the ARP cache table. */\r
237                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
238                 {\r
239                         /* Does this line in the cache table hold an entry for the IP\r
240                         address being queried? */\r
241                         if( xARPCache[ x ].ulIPAddress == ulIPAddress )\r
242                         {\r
243                                 if( pxMACAddress == NULL )\r
244                                 {\r
245                                         /* In case the parameter pxMACAddress is NULL, an entry will be reserved to\r
246                                         indicate that there is an outstanding ARP request, This entry will have\r
247                                         "ucValid == pdFALSE". */\r
248                                         xIpEntry = x;\r
249                                         break;\r
250                                 }\r
251 \r
252                                 /* See if the MAC-address also matches. */\r
253                                 if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )\r
254                                 {\r
255                                         /* This function will be called for each received packet\r
256                                         As this is by far the most common path the coding standard\r
257                                         is relaxed in this case and a return is permitted as an\r
258                                         optimisation. */\r
259                                         xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;\r
260                                         xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;\r
261                                         return;\r
262                                 }\r
263 \r
264                                 /* Found an entry containing ulIPAddress, but the MAC address\r
265                                 doesn't match.  Might be an entry with ucValid=pdFALSE, waiting\r
266                                 for an ARP reply.  Still want to see if there is match with the\r
267                                 given MAC address.ucBytes.  If found, either of the two entries\r
268                                 must be cleared. */\r
269                                 xIpEntry = x;\r
270                         }\r
271                         else if( ( pxMACAddress != NULL ) && ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )\r
272                         {\r
273                                 /* Found an entry with the given MAC-address, but the IP-address\r
274                                 is different.  Continue looping to find a possible match with\r
275                                 ulIPAddress. */\r
276         #if( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )\r
277                                 /* If ARP stores the MAC address of IP addresses outside the\r
278                                 network, than the MAC address of the gateway should not be\r
279                                 overwritten. */\r
280                                 BaseType_t bIsLocal[ 2 ];\r
281                                 bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );\r
282                                 bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );\r
283                                 if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )\r
284                                 {\r
285                                         xMacEntry = x;\r
286                                 }\r
287         #else\r
288                                 xMacEntry = x;\r
289         #endif\r
290                         }\r
291                         /* _HT_\r
292                         Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */\r
293                         else if( xARPCache[ x ].ucAge < ucMinAgeFound )\r
294                         {\r
295                                 /* As the table is traversed, remember the table row that\r
296                                 contains the oldest entry (the lowest age count, as ages are\r
297                                 decremented to zero) so the row can be re-used if this function\r
298                                 needs to add an entry that does not already exist. */\r
299                                 ucMinAgeFound = xARPCache[ x ].ucAge;\r
300                                 xUseEntry = x;\r
301                         }\r
302                 }\r
303 \r
304                 if( xMacEntry >= 0 )\r
305                 {\r
306                         xUseEntry = xMacEntry;\r
307 \r
308                         if( xIpEntry >= 0 )\r
309                         {\r
310                                 /* Both the MAC address as well as the IP address were found in\r
311                                 different locations: clear the entry which matches the\r
312                                 IP-address */\r
313                                 memset( &xARPCache[ xIpEntry ], '\0', sizeof( xARPCache[ xIpEntry ] ) );\r
314                         }\r
315                 }\r
316                 else if( xIpEntry >= 0 )\r
317                 {\r
318                         /* An entry containing the IP-address was found, but it had a different MAC address */\r
319                         xUseEntry = xIpEntry;\r
320                 }\r
321 \r
322                 /* If the entry was not found, we use the oldest entry and set the IPaddress */\r
323                 xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;\r
324 \r
325                 if( pxMACAddress != NULL )\r
326                 {\r
327                         memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );\r
328 \r
329                         iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, (*pxMACAddress) );\r
330                         /* And this entry does not need immediate attention */\r
331                         xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;\r
332                         xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;\r
333                 }\r
334                 else if( xIpEntry < 0 )\r
335                 {\r
336                         xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;\r
337                         xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;\r
338                 }\r
339         }\r
340 }\r
341 /*-----------------------------------------------------------*/\r
342 \r
343 #if( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )\r
344         eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress, uint32_t *pulIPAddress )\r
345         {\r
346         BaseType_t x;\r
347         eARPLookupResult_t eReturn = eARPCacheMiss;\r
348 \r
349                 /* Loop through each entry in the ARP cache. */\r
350                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
351                 {\r
352                         /* Does this row in the ARP cache table hold an entry for the MAC\r
353                         address being searched? */\r
354                         if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )\r
355                         {\r
356                                 *pulIPAddress = xARPCache[ x ].ulIPAddress;\r
357                                 eReturn = eARPCacheHit;\r
358                                 break;\r
359                         }\r
360                 }\r
361 \r
362                 return eReturn;\r
363         }\r
364 #endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */\r
365 \r
366 /*-----------------------------------------------------------*/\r
367 \r
368 eARPLookupResult_t eARPGetCacheEntry( uint32_t *pulIPAddress, MACAddress_t * const pxMACAddress )\r
369 {\r
370 eARPLookupResult_t eReturn;\r
371 uint32_t ulAddressToLookup;\r
372 \r
373 #if( ipconfigUSE_LLMNR == 1 )\r
374         if( *pulIPAddress == ipLLMNR_IP_ADDR )  /* Is in network byte order. */\r
375         {\r
376                 /* The LLMNR IP-address has a fixed virtual MAC address. */\r
377                 memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );\r
378                 eReturn = eARPCacheHit;\r
379         }\r
380         else\r
381 #endif\r
382         if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) ||      /* Is it the general broadcast address 255.255.255.255? */\r
383                 ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) )/* Or a local broadcast address, eg 192.168.1.255? */\r
384         {\r
385                 /* This is a broadcast so uses the broadcast MAC address. */\r
386                 memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );\r
387                 eReturn = eARPCacheHit;\r
388         }\r
389         else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )\r
390         {\r
391                 /* The IP address has not yet been assigned, so there is nothing that\r
392                 can be done. */\r
393                 eReturn = eCantSendPacket;\r
394         }\r
395         else\r
396         {\r
397                 eReturn = eARPCacheMiss;\r
398 \r
399                 if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )\r
400                 {\r
401 #if( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )\r
402                         eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );\r
403 \r
404                         if( eReturn == eARPCacheHit )\r
405                         {\r
406                                 /* The stack is configured to store 'remote IP addresses', i.e. addresses\r
407                                 belonging to a different the netmask.  prvCacheLookup() returned a hit, so\r
408                                 the MAC address is known */\r
409                         }\r
410                         else\r
411 #endif\r
412                         {\r
413                                 /* The IP address is off the local network, so look up the\r
414                                 hardware address of the router, if any. */\r
415                                 if( xNetworkAddressing.ulGatewayAddress != ( uint32_t )0u )\r
416                                 {\r
417                                         ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;\r
418                                 }\r
419                                 else\r
420                                 {\r
421                                         ulAddressToLookup = *pulIPAddress;\r
422                                 }\r
423                         }\r
424                 }\r
425                 else\r
426                 {\r
427                         /* The IP address is on the local network, so lookup the requested\r
428                         IP address directly. */\r
429                         ulAddressToLookup = *pulIPAddress;\r
430                 }\r
431 \r
432                 if( eReturn == eARPCacheMiss )\r
433                 {\r
434                         if( ulAddressToLookup == 0UL )\r
435                         {\r
436                                 /* The address is not on the local network, and there is not a\r
437                                 router. */\r
438                                 eReturn = eCantSendPacket;\r
439                         }\r
440                         else\r
441                         {\r
442                                 eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );\r
443 \r
444                                 if( eReturn == eARPCacheMiss )\r
445                                 {\r
446                                         /* It might be that the ARP has to go to the gateway. */\r
447                                         *pulIPAddress = ulAddressToLookup;\r
448                                 }\r
449                         }\r
450                 }\r
451         }\r
452 \r
453         return eReturn;\r
454 }\r
455 \r
456 /*-----------------------------------------------------------*/\r
457 \r
458 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup, MACAddress_t * const pxMACAddress )\r
459 {\r
460 BaseType_t x;\r
461 eARPLookupResult_t eReturn = eARPCacheMiss;\r
462 \r
463         /* Loop through each entry in the ARP cache. */\r
464         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
465         {\r
466                 /* Does this row in the ARP cache table hold an entry for the IP address\r
467                 being queried? */\r
468                 if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )\r
469                 {\r
470                         /* A matching valid entry was found. */\r
471                         if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )\r
472                         {\r
473                                 /* This entry is waiting an ARP reply, so is not valid. */\r
474                                 eReturn = eCantSendPacket;\r
475                         }\r
476                         else\r
477                         {\r
478                                 /* A valid entry was found. */\r
479                                 memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );\r
480                                 eReturn = eARPCacheHit;\r
481                         }\r
482                         break;\r
483                 }\r
484         }\r
485 \r
486         return eReturn;\r
487 }\r
488 /*-----------------------------------------------------------*/\r
489 \r
490 void vARPAgeCache( void )\r
491 {\r
492 BaseType_t x;\r
493 TickType_t xTimeNow;\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                 /* If the entry is valid (its age is greater than zero). */\r
499                 if( xARPCache[ x ].ucAge > 0U )\r
500                 {\r
501                         /* Decrement the age value of the entry in this ARP cache table row.\r
502                         When the age reaches zero it is no longer considered valid. */\r
503                         ( xARPCache[ x ].ucAge )--;\r
504 \r
505                         /* If the entry is not yet valid, then it is waiting an ARP\r
506                         reply, and the ARP request should be retransmitted. */\r
507                         if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )\r
508                         {\r
509                                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );\r
510                         }\r
511                         else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )\r
512                         {\r
513                                 /* This entry will get removed soon.  See if the MAC address is\r
514                                 still valid to prevent this happening. */\r
515                                 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );\r
516                                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );\r
517                         }\r
518                         else\r
519                         {\r
520                                 /* The age has just ticked down, with nothing to do. */\r
521                         }\r
522 \r
523                         if( xARPCache[ x ].ucAge == 0u )\r
524                         {\r
525                                 /* The entry is no longer valid.  Wipe it out. */\r
526                                 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );\r
527                                 xARPCache[ x ].ulIPAddress = 0UL;\r
528                         }\r
529                 }\r
530         }\r
531 \r
532         xTimeNow = xTaskGetTickCount ();\r
533 \r
534         if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )\r
535         {\r
536                 FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );\r
537                 xLastGratuitousARPTime = xTimeNow;\r
538         }\r
539 }\r
540 /*-----------------------------------------------------------*/\r
541 \r
542 void vARPSendGratuitous( void )\r
543 {\r
544         /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next\r
545         time vARPAgeCache() is called. */\r
546         xLastGratuitousARPTime = ( TickType_t ) 0;\r
547 \r
548         /* Let the IP-task call vARPAgeCache(). */\r
549         xSendEventToIPTask( eARPTimerEvent );\r
550 }\r
551 \r
552 /*-----------------------------------------------------------*/\r
553 void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )\r
554 {\r
555 NetworkBufferDescriptor_t *pxNetworkBuffer;\r
556 \r
557         /* This is called from the context of the IP event task, so a block time\r
558         must not be used. */\r
559         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0 );\r
560 \r
561         if( pxNetworkBuffer != NULL )\r
562         {\r
563                 pxNetworkBuffer->ulIPAddress = ulIPAddress;\r
564                 vARPGenerateRequestPacket( pxNetworkBuffer );\r
565 \r
566                 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
567                 {\r
568                         if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )\r
569                         {\r
570                         BaseType_t xIndex;\r
571 \r
572                                 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )\r
573                                 {\r
574                                         pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;\r
575                                 }\r
576                                 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;\r
577                         }\r
578                 }\r
579                 #endif\r
580 \r
581                 xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );\r
582         }\r
583 }\r
584 \r
585 void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )\r
586 {\r
587 ARPPacket_t *pxARPPacket;\r
588 \r
589         pxARPPacket = ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer;\r
590 \r
591         /* memcpy the const part of the header information into the correct\r
592         location in the packet.  This copies:\r
593                 xEthernetHeader.ulDestinationAddress\r
594                 xEthernetHeader.usFrameType;\r
595                 xARPHeader.usHardwareType;\r
596                 xARPHeader.usProtocolType;\r
597                 xARPHeader.ucHardwareAddressLength;\r
598                 xARPHeader.ucProtocolAddressLength;\r
599                 xARPHeader.usOperation;\r
600                 xARPHeader.xTargetHardwareAddress;\r
601         */\r
602         memcpy( ( void * ) &( pxARPPacket->xEthernetHeader ), ( void * ) xDefaultPartARPPacketHeader, sizeof( xDefaultPartARPPacketHeader ) );\r
603         memcpy( ( void * ) pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
604         memcpy( ( void * ) pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes, ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );\r
605 \r
606         memcpy( ( void* )pxARPPacket->xARPHeader.ucSenderProtocolAddress, ( void* )ipLOCAL_IP_ADDRESS_POINTER, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );\r
607         pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;\r
608 \r
609         pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );\r
610 \r
611         iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );\r
612 }\r
613 /*-----------------------------------------------------------*/\r
614 \r
615 void FreeRTOS_ClearARP( void )\r
616 {\r
617         memset( xARPCache, '\0', sizeof( xARPCache ) );\r
618 }\r
619 /*-----------------------------------------------------------*/\r
620 \r
621 #if( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )\r
622 \r
623         void FreeRTOS_PrintARPCache( void )\r
624         {\r
625         BaseType_t x, xCount = 0;\r
626 \r
627                 /* Loop through each entry in the ARP cache. */\r
628                 for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )\r
629                 {\r
630                         if( ( xARPCache[ x ].ulIPAddress != 0ul ) && ( xARPCache[ x ].ucAge > 0U ) )\r
631                         {\r
632                                 /* See if the MAC-address also matches, and we're all happy */\r
633                                 FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",\r
634                                         x,\r
635                                         xARPCache[ x ].ucAge,\r
636                                         xARPCache[ x ].ulIPAddress,\r
637                                         xARPCache[ x ].xMACAddress.ucBytes[0],\r
638                                         xARPCache[ x ].xMACAddress.ucBytes[1],\r
639                                         xARPCache[ x ].xMACAddress.ucBytes[2],\r
640                                         xARPCache[ x ].xMACAddress.ucBytes[3],\r
641                                         xARPCache[ x ].xMACAddress.ucBytes[4],\r
642                                         xARPCache[ x ].xMACAddress.ucBytes[5] ) );\r
643                                 xCount++;\r
644                         }\r
645                 }\r
646 \r
647                 FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );\r
648         }\r
649 \r
650 #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */\r