xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_ARP.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_ARP.c
30  * @brief Implements the Address Resolution Protocol for the FreeRTOS+TCP network stack.
31  */
32 
33 /* Standard includes. */
34 #include <stdint.h>
35 #include <stdio.h>
36 
37 /* FreeRTOS includes. */
38 #include "FreeRTOS.h"
39 #include "task.h"
40 #include "queue.h"
41 #include "semphr.h"
42 
43 /* FreeRTOS+TCP includes. */
44 #include "FreeRTOS_IP.h"
45 #include "FreeRTOS_IP_Timers.h"
46 #include "FreeRTOS_Sockets.h"
47 #include "FreeRTOS_IP_Private.h"
48 #include "FreeRTOS_ARP.h"
49 #include "FreeRTOS_UDP_IP.h"
50 #include "FreeRTOS_DHCP.h"
51 #if ( ipconfigUSE_LLMNR == 1 )
52     #include "FreeRTOS_DNS.h"
53 #endif /* ipconfigUSE_LLMNR */
54 #include "NetworkBufferManagement.h"
55 #include "NetworkInterface.h"
56 
57 /** @brief When the age of an entry in the ARP table reaches this value (it counts down
58  * to zero, so this is an old entry) an ARP request will be sent to see if the
59  * entry is still valid and can therefore be refreshed. */
60 #define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST    ( 3 )
61 
62 /** @brief The time between gratuitous ARPs. */
63 #ifndef arpGRATUITOUS_ARP_PERIOD
64     #define arpGRATUITOUS_ARP_PERIOD    ( pdMS_TO_TICKS( 20000U ) )
65 #endif
66 
67 /** @brief When there is another device which has the same IP address as the IP address
68  * of this device, a defensive ARP request should be sent out. However, according to
69  * RFC 5227 section 1.1, there must be a minimum interval of 10 seconds between
70  * consecutive defensive ARP packets. */
71 #ifndef arpIP_CLASH_RESET_TIMEOUT_MS
72     #define arpIP_CLASH_RESET_TIMEOUT_MS    10000U
73 #endif
74 
75 /** @brief Maximum number of defensive ARPs to be sent for an ARP clash per
76  * arpIP_CLASH_RESET_TIMEOUT_MS period. The retries are limited to one as outlined
77  * by RFC 5227 section 2.4 part b.*/
78 #ifndef arpIP_CLASH_MAX_RETRIES
79     #define arpIP_CLASH_MAX_RETRIES    1U
80 #endif
81 
82 /*
83  * Lookup an MAC address in the ARP cache from the IP address.
84  */
85 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
86                                           MACAddress_t * const pxMACAddress );
87 
88 /*-----------------------------------------------------------*/
89 
90 static void vProcessARPPacketReply( const ARPPacket_t * pxARPFrame,
91                                     uint32_t ulSenderProtocolAddress );
92 
93 /*-----------------------------------------------------------*/
94 
95 /** @brief The ARP cache. */
96 _static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
97 
98 /** @brief  The time at which the last gratuitous ARP was sent.  Gratuitous ARPs are used
99  * to ensure ARP tables are up to date and to detect IP address conflicts. */
100 static TickType_t xLastGratuitousARPTime = 0U;
101 
102 /*
103  * IP-clash detection is currently only used internally. When DHCP doesn't respond, the
104  * driver can try out a random LinkLayer IP address (169.254.x.x).  It will send out a
105  * gratuitous ARP message and, after a period of time, check the variables here below:
106  */
107 #if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
108     /* Becomes non-zero if another device responded to a gratuitous ARP message. */
109     BaseType_t xARPHadIPClash;
110     /* MAC-address of the other device containing the same IP-address. */
111     MACAddress_t xARPClashMacAddress;
112 #endif /* ipconfigARP_USE_CLASH_DETECTION */
113 
114 /*-----------------------------------------------------------*/
115 
116 /**
117  * @brief Process the ARP packets.
118  *
119  * @param[in] pxARPFrame: The ARP Frame (the ARP packet).
120  *
121  * @return An enum which says whether to return the frame or to release it.
122  */
eARPProcessPacket(ARPPacket_t * const pxARPFrame)123 eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )
124 {
125     eFrameProcessingResult_t eReturn = eReleaseBuffer;
126     ARPHeader_t * pxARPHeader;
127     uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
128 /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
129     const void * pvCopySource;
130     void * pvCopyDest;
131 
132     /* Next defensive request must not be sent for arpIP_CLASH_RESET_TIMEOUT_MS
133      * period. */
134     static TickType_t uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS );
135 
136     /* This local variable is used to keep track of number of ARP requests sent and
137      * also to limit the requests to arpIP_CLASH_MAX_RETRIES per arpIP_CLASH_RESET_TIMEOUT_MS
138      * period. */
139     static UBaseType_t uxARPClashCounter = 0U;
140     /* The time at which the last ARP clash was sent. */
141     static TimeOut_t xARPClashTimeOut;
142 
143     pxARPHeader = &( pxARPFrame->xARPHeader );
144 
145     /* The field ucSenderProtocolAddress is badly aligned, copy byte-by-byte. */
146 
147     /*
148      * Use helper variables for memcpy() to remain
149      * compliant with MISRA Rule 21.15.  These should be
150      * optimized away.
151      */
152     pvCopySource = pxARPHeader->ucSenderProtocolAddress;
153     pvCopyDest = &ulSenderProtocolAddress;
154     ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulSenderProtocolAddress ) );
155     /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
156     ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
157 
158     if( uxARPClashCounter != 0U )
159     {
160         /* Has the timeout been reached? */
161         if( xTaskCheckForTimeOut( &xARPClashTimeOut, &uxARPClashTimeoutPeriod ) == pdTRUE )
162         {
163             /* We have waited long enough, reset the counter. */
164             uxARPClashCounter = 0;
165         }
166     }
167 
168     /* Introduce a do while loop to allow use of breaks. */
169     do
170     {
171         /* Only Ethernet hardware type is supported.
172          * Only IPv4 address can be present in the ARP packet.
173          * The hardware length (the MAC address) must be 6 bytes. And,
174          * The Protocol address length must be 4 bytes as it is IPv4. */
175         if( ( pxARPHeader->usHardwareType != ipARP_HARDWARE_TYPE_ETHERNET ) ||
176             ( pxARPHeader->usProtocolType != ipARP_PROTOCOL_TYPE ) ||
177             ( pxARPHeader->ucHardwareAddressLength != ipMAC_ADDRESS_LENGTH_BYTES ) ||
178             ( pxARPHeader->ucProtocolAddressLength != ipIP_ADDRESS_LENGTH_BYTES ) )
179         {
180             /* One or more fields are not valid. */
181             iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
182             break;
183         }
184 
185         /* Check whether the lowest bit of the highest byte is 1 to check for
186          * multicast address or even a broadcast address (FF:FF:FF:FF:FF:FF). */
187         if( ( pxARPHeader->xSenderHardwareAddress.ucBytes[ 0 ] & 0x01U ) == 0x01U )
188         {
189             /* Senders address is a multicast OR broadcast address which is not
190              * allowed for an ARP packet. Drop the packet. See RFC 1812 section
191              * 3.3.2. */
192             iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
193             break;
194         }
195 
196         uint32_t ulHostEndianProtocolAddr = FreeRTOS_ntohl( ulSenderProtocolAddress );
197 
198         if( ( ipFIRST_LOOPBACK_IPv4 <= ulHostEndianProtocolAddr ) &&
199             ( ulHostEndianProtocolAddr < ipLAST_LOOPBACK_IPv4 ) )
200         {
201             /* The local loopback addresses must never appear outside a host. See RFC 1122
202              * section 3.2.1.3. */
203             iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
204             break;
205         }
206 
207         /* Check whether there is a clash with another device for this IP address. */
208         if( ( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER ) &&
209             ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
210         {
211             if( uxARPClashCounter < arpIP_CLASH_MAX_RETRIES )
212             {
213                 /* Increment the counter. */
214                 uxARPClashCounter++;
215 
216                 /* Send out a defensive ARP request. */
217                 FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
218 
219                 /* Since an ARP Request for this IP was just sent, do not send a gratuitous
220                  * ARP for arpGRATUITOUS_ARP_PERIOD. */
221                 xLastGratuitousARPTime = xTaskGetTickCount();
222 
223                 /* Note the time at which this request was sent. */
224                 vTaskSetTimeOutState( &xARPClashTimeOut );
225 
226                 /* Reset the time-out period to the given value. */
227                 uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS );
228             }
229 
230             /* Process received ARP frame to see if there is a clash. */
231             #if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
232                 {
233                     xARPHadIPClash = pdTRUE;
234                     /* Remember the MAC-address of the other device which has the same IP-address. */
235                     ( void ) memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
236                 }
237             #endif /* ipconfigARP_USE_CLASH_DETECTION */
238 
239             break;
240         }
241 
242         traceARP_PACKET_RECEIVED();
243 
244         /* Don't do anything if the local IP address is zero because
245          * that means a DHCP request has not completed. */
246         if( *ipLOCAL_IP_ADDRESS_POINTER != 0U )
247         {
248             switch( pxARPHeader->usOperation )
249             {
250                 case ipARP_REQUEST:
251 
252                     /* The packet contained an ARP request.  Was it for the IP
253                      * address of the node running this code? And does the MAC
254                      * address claim that it is coming from this device itself? */
255                     if( ( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER ) &&
256                         ( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS,
257                                   ( void * ) ( pxARPHeader->xSenderHardwareAddress.ucBytes ),
258                                   ipMAC_ADDRESS_LENGTH_BYTES ) != 0 ) )
259                     {
260                         iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
261 
262                         /* The request is for the address of this node.  Add the
263                          * entry into the ARP cache, or refresh the entry if it
264                          * already exists. */
265                         vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
266 
267                         /* Generate a reply payload in the same buffer. */
268                         pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
269 
270                         ( void ) memcpy( &( pxARPHeader->xTargetHardwareAddress ),
271                                          &( pxARPHeader->xSenderHardwareAddress ),
272                                          sizeof( MACAddress_t ) );
273 
274                         pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
275 
276                         /*
277                          * Use helper variables for memcpy() to remain
278                          * compliant with MISRA Rule 21.15.  These should be
279                          * optimized away.
280                          */
281                         pvCopySource = ipLOCAL_MAC_ADDRESS;
282                         pvCopyDest = pxARPHeader->xSenderHardwareAddress.ucBytes;
283                         ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
284 
285                         pvCopySource = ipLOCAL_IP_ADDRESS_POINTER;
286                         pvCopyDest = pxARPHeader->ucSenderProtocolAddress;
287                         ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
288 
289                         eReturn = eReturnEthernetFrame;
290                     }
291 
292                     break;
293 
294                 case ipARP_REPLY:
295                     vProcessARPPacketReply( pxARPFrame, ulSenderProtocolAddress );
296 
297                     break;
298 
299                 default:
300                     /* Invalid. */
301                     break;
302             }
303         }
304     } while( ipFALSE_BOOL );
305 
306     return eReturn;
307 }
308 /*-----------------------------------------------------------*/
309 
310 /**
311  * @brief A device has sent an ARP reply, process it.
312  * @param[in] pxARPFrame: The ARP packet received.
313  * @param[in] ulSenderProtocolAddress: The IPv4 address involved.
314  */
vProcessARPPacketReply(const ARPPacket_t * pxARPFrame,uint32_t ulSenderProtocolAddress)315 static void vProcessARPPacketReply( const ARPPacket_t * pxARPFrame,
316                                     uint32_t ulSenderProtocolAddress )
317 {
318     const ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader );
319     uint32_t ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
320 
321     /* If the packet is meant for this device or if the entry already exists. */
322     if( ( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER ) ||
323         ( xIsIPInARPCache( ulSenderProtocolAddress ) == pdTRUE ) )
324     {
325         iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
326         vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
327     }
328 
329     if( pxARPWaitingNetworkBuffer != NULL )
330     {
331         /* MISRA Ref 11.3.1 [Misaligned access] */
332 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
333         /* coverity[misra_c_2012_rule_11_3_violation] */
334         const IPPacket_t * pxARPWaitingIPPacket = ( ( IPPacket_t * ) pxARPWaitingNetworkBuffer->pucEthernetBuffer );
335         const IPHeader_t * pxARPWaitingIPHeader = &( pxARPWaitingIPPacket->xIPHeader );
336 
337         if( ulSenderProtocolAddress == pxARPWaitingIPHeader->ulSourceIPAddress )
338         {
339             IPStackEvent_t xEventMessage;
340             const TickType_t xDontBlock = ( TickType_t ) 0;
341 
342             xEventMessage.eEventType = eNetworkRxEvent;
343             xEventMessage.pvData = ( void * ) pxARPWaitingNetworkBuffer;
344 
345             if( xSendEventStructToIPTask( &xEventMessage, xDontBlock ) != pdPASS )
346             {
347                 /* Failed to send the message, so release the network buffer. */
348                 vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer );
349             }
350 
351             /* Clear the buffer. */
352             pxARPWaitingNetworkBuffer = NULL;
353 
354             /* Found an ARP resolution, disable ARP resolution timer. */
355             vIPSetARPResolutionTimerEnableState( pdFALSE );
356 
357             iptrace_DELAYED_ARP_REQUEST_REPLIED();
358         }
359     }
360 }
361 
362 /**
363  * @brief Check whether an IP address is in the ARP cache.
364  *
365  * @param[in] ulAddressToLookup: The 32-bit representation of an IP address to
366  *                    check for.
367  *
368  * @return When the IP-address is found: pdTRUE, else pdFALSE.
369  */
xIsIPInARPCache(uint32_t ulAddressToLookup)370 BaseType_t xIsIPInARPCache( uint32_t ulAddressToLookup )
371 {
372     BaseType_t x, xReturn = pdFALSE;
373 
374     /* Loop through each entry in the ARP cache. */
375     for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
376     {
377         /* Does this row in the ARP cache table hold an entry for the IP address
378          * being queried? */
379         if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
380         {
381             xReturn = pdTRUE;
382 
383             /* A matching valid entry was found. */
384             if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
385             {
386                 /* This entry is waiting an ARP reply, so is not valid. */
387                 xReturn = pdFALSE;
388             }
389 
390             break;
391         }
392     }
393 
394     return xReturn;
395 }
396 
397 /**
398  * @brief Check whether a packet needs ARP resolution if it is on local subnet. If required send an ARP request.
399  *
400  * @param[in] pxNetworkBuffer: The network buffer with the packet to be checked.
401  *
402  * @return pdTRUE if the packet needs ARP resolution, pdFALSE otherwise.
403  */
xCheckRequiresARPResolution(const NetworkBufferDescriptor_t * pxNetworkBuffer)404 BaseType_t xCheckRequiresARPResolution( const NetworkBufferDescriptor_t * pxNetworkBuffer )
405 {
406     BaseType_t xNeedsARPResolution = pdFALSE;
407 
408     /* MISRA Ref 11.3.1 [Misaligned access] */
409 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
410     /* coverity[misra_c_2012_rule_11_3_violation] */
411     const IPPacket_t * pxIPPacket = ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
412     const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
413 
414     if( ( pxIPHeader->ulSourceIPAddress & xNetworkAddressing.ulNetMask ) == ( *ipLOCAL_IP_ADDRESS_POINTER & xNetworkAddressing.ulNetMask ) )
415     {
416         /* If the IP is on the same subnet and we do not have an ARP entry already,
417          * then we should send out ARP for finding the MAC address. */
418         if( xIsIPInARPCache( pxIPHeader->ulSourceIPAddress ) == pdFALSE )
419         {
420             FreeRTOS_OutputARPRequest( pxIPHeader->ulSourceIPAddress );
421 
422             /* This packet needs resolution since this is on the same subnet
423              * but not in the ARP cache. */
424             xNeedsARPResolution = pdTRUE;
425         }
426     }
427 
428     return xNeedsARPResolution;
429 }
430 
431 #if ( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
432 
433 /**
434  * @brief Remove an ARP cache entry that matches with .pxMACAddress.
435  *
436  * @param[in] pxMACAddress: Pointer to the MAC address whose entry shall
437  *                          be removed..
438  * @return When the entry was found and remove: the IP-address, otherwise zero.
439  */
ulARPRemoveCacheEntryByMac(const MACAddress_t * pxMACAddress)440     uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
441     {
442         BaseType_t x;
443         uint32_t lResult = 0;
444 
445         configASSERT( pxMACAddress != NULL );
446 
447         /* For each entry in the ARP cache table. */
448         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
449         {
450             if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
451             {
452                 lResult = xARPCache[ x ].ulIPAddress;
453                 ( void ) memset( &xARPCache[ x ], 0, sizeof( xARPCache[ x ] ) );
454                 break;
455             }
456         }
457 
458         return lResult;
459     }
460 
461 #endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
462 /*-----------------------------------------------------------*/
463 
464 /**
465  * @brief Add/update the ARP cache entry MAC-address to IP-address mapping.
466  *
467  * @param[in] pxMACAddress: Pointer to the MAC address whose mapping is being
468  *                          updated.
469  * @param[in] ulIPAddress: 32-bit representation of the IP-address whose mapping
470  *                         is being updated.
471  */
vARPRefreshCacheEntry(const MACAddress_t * pxMACAddress,const uint32_t ulIPAddress)472 void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
473                             const uint32_t ulIPAddress )
474 {
475     BaseType_t x = 0;
476     BaseType_t xIpEntry = -1;
477     BaseType_t xMacEntry = -1;
478     BaseType_t xUseEntry = 0;
479     BaseType_t xAllDone = pdFALSE;
480     uint8_t ucMinAgeFound = 0U;
481 
482     #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
483         /* Only process the IP address if it is on the local network. */
484         if( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
485     #else
486 
487         /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
488          * a different netmask will also be stored.  After when replying to a UDP
489          * message from a different netmask, the IP address can be looped up and a
490          * reply sent.  This option is useful for systems with multiple gateways,
491          * the reply will surely arrive.  If ipconfigARP_STORES_REMOTE_ADDRESSES is
492          * zero the the gateway address is the only option. */
493 
494         if( pdTRUE )
495     #endif
496     {
497         /* Start with the maximum possible number. */
498         ucMinAgeFound--;
499 
500         /* For each entry in the ARP cache table. */
501         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
502         {
503             BaseType_t xMatchingMAC;
504 
505             if( pxMACAddress != NULL )
506             {
507                 if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
508                 {
509                     xMatchingMAC = pdTRUE;
510                 }
511                 else
512                 {
513                     xMatchingMAC = pdFALSE;
514                 }
515             }
516             else
517             {
518                 xMatchingMAC = pdFALSE;
519             }
520 
521             /* Does this line in the cache table hold an entry for the IP
522              * address being queried? */
523             if( xARPCache[ x ].ulIPAddress == ulIPAddress )
524             {
525                 if( pxMACAddress == NULL )
526                 {
527                     /* In case the parameter pxMACAddress is NULL, an entry will be reserved to
528                      * indicate that there is an outstanding ARP request, This entry will have
529                      * "ucValid == pdFALSE". */
530                     xIpEntry = x;
531                     break;
532                 }
533 
534                 /* See if the MAC-address also matches. */
535                 if( xMatchingMAC != pdFALSE )
536                 {
537                     /* A perfect match is found, update the entry and leave this
538                      * function by setting 'xAllDone' to pdTRUE. */
539                     xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
540                     xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
541                     xAllDone = pdTRUE;
542                     break;
543                 }
544 
545                 /* Found an entry containing ulIPAddress, but the MAC address
546                  * doesn't match.  Might be an entry with ucValid=pdFALSE, waiting
547                  * for an ARP reply.  Still want to see if there is match with the
548                  * given MAC address.ucBytes.  If found, either of the two entries
549                  * must be cleared. */
550                 xIpEntry = x;
551             }
552             else if( xMatchingMAC != pdFALSE )
553             {
554                 /* Found an entry with the given MAC-address, but the IP-address
555                  * is different.  Continue looping to find a possible match with
556                  * ulIPAddress. */
557                 #if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
558 
559                     /* If ARP stores the MAC address of IP addresses outside the
560                      * network, than the MAC address of the gateway should not be
561                      * overwritten. */
562                     BaseType_t bIsLocal[ 2 ];
563                     bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
564                     bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
565 
566                     if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )
567                     {
568                         xMacEntry = x;
569                     }
570                 #else /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
571                     xMacEntry = x;
572                 #endif /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
573             }
574 
575             /* _HT_
576              * Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
577             else if( xARPCache[ x ].ucAge < ucMinAgeFound )
578             {
579                 /* As the table is traversed, remember the table row that
580                  * contains the oldest entry (the lowest age count, as ages are
581                  * decremented to zero) so the row can be re-used if this function
582                  * needs to add an entry that does not already exist. */
583                 ucMinAgeFound = xARPCache[ x ].ucAge;
584                 xUseEntry = x;
585             }
586             else
587             {
588                 /* Nothing happens to this cache entry for now. */
589             }
590         }
591 
592         if( xAllDone == pdFALSE )
593         {
594             /* A perfect match was not found. See if either the MAC-address
595              * or the IP-address has a match. */
596             if( xMacEntry >= 0 )
597             {
598                 xUseEntry = xMacEntry;
599 
600                 if( xIpEntry >= 0 )
601                 {
602                     /* Both the MAC address as well as the IP address were found in
603                      * different locations: clear the entry which matches the
604                      * IP-address */
605                     ( void ) memset( &( xARPCache[ xIpEntry ] ), 0, sizeof( ARPCacheRow_t ) );
606                 }
607             }
608             else if( xIpEntry >= 0 )
609             {
610                 /* An entry containing the IP-address was found, but it had a different MAC address */
611                 xUseEntry = xIpEntry;
612             }
613             else
614             {
615                 /* No matching entry found. */
616             }
617 
618             /* If the entry was not found, we use the oldest entry and set the IPaddress */
619             xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;
620 
621             if( pxMACAddress != NULL )
622             {
623                 ( void ) memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
624 
625                 iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ( *pxMACAddress ) );
626                 /* And this entry does not need immediate attention */
627                 xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
628                 xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
629             }
630             else if( xIpEntry < 0 )
631             {
632                 xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
633                 xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
634             }
635             else
636             {
637                 /* Nothing will be stored. */
638             }
639         }
640     }
641 }
642 /*-----------------------------------------------------------*/
643 
644 #if ( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
645 
646 /**
647  * @brief Retrieve an entry from the cache table
648  *
649  * @param[in] pxMACAddress: The MAC-address of the entry of interest.
650  * @param[out] pulIPAddress: set to the IP-address found, or unchanged when not found.
651  *
652  * @return Either eARPCacheMiss or eARPCacheHit.
653  */
eARPGetCacheEntryByMac(const MACAddress_t * const pxMACAddress,uint32_t * pulIPAddress)654     eARPLookupResult_t eARPGetCacheEntryByMac( const MACAddress_t * const pxMACAddress,
655                                                uint32_t * pulIPAddress )
656     {
657         BaseType_t x;
658         eARPLookupResult_t eReturn = eARPCacheMiss;
659 
660         configASSERT( pxMACAddress != NULL );
661         configASSERT( pulIPAddress != NULL );
662 
663         /* Loop through each entry in the ARP cache. */
664         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
665         {
666             /* Does this row in the ARP cache table hold an entry for the MAC
667              * address being searched? */
668             if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
669             {
670                 *pulIPAddress = xARPCache[ x ].ulIPAddress;
671                 eReturn = eARPCacheHit;
672                 break;
673             }
674         }
675 
676         return eReturn;
677     }
678 #endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
679 
680 /*-----------------------------------------------------------*/
681 
682 /**
683  * @brief Look for ulIPAddress in the ARP cache.
684  *
685  * @param[in,out] pulIPAddress: Pointer to the IP-address to be queried to the ARP cache.
686  * @param[in,out] pxMACAddress: Pointer to a MACAddress_t variable where the MAC address
687  *                          will be stored, if found.
688  *
689  * @return If the IP address exists, copy the associated MAC address into pxMACAddress,
690  *         refresh the ARP cache entry's age, and return eARPCacheHit. If the IP
691  *         address does not exist in the ARP cache return eARPCacheMiss. If the packet
692  *         cannot be sent for any reason (maybe DHCP is still in process, or the
693  *         addressing needs a gateway but there isn't a gateway defined) then return
694  *         eCantSendPacket.
695  */
eARPGetCacheEntry(uint32_t * pulIPAddress,MACAddress_t * const pxMACAddress)696 eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress,
697                                       MACAddress_t * const pxMACAddress )
698 {
699     eARPLookupResult_t eReturn;
700     uint32_t ulAddressToLookup;
701 
702     configASSERT( pxMACAddress != NULL );
703     configASSERT( pulIPAddress != NULL );
704 
705     ulAddressToLookup = *pulIPAddress;
706 
707     if( xIsIPv4Multicast( ulAddressToLookup ) != 0 )
708     {
709         /* Get the lowest 23 bits of the IP-address. */
710         vSetMultiCastIPv4MacAddress( ulAddressToLookup, pxMACAddress );
711 
712         eReturn = eARPCacheHit;
713     }
714     else if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) ||               /* Is it the general broadcast address 255.255.255.255? */
715              ( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) ) /* Or a local broadcast address, eg 192.168.1.255? */
716     {
717         /* This is a broadcast so it uses the broadcast MAC address. */
718         ( void ) memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
719         eReturn = eARPCacheHit;
720     }
721     else if( *ipLOCAL_IP_ADDRESS_POINTER == 0U )
722     {
723         /* The IP address has not yet been assigned, so there is nothing that
724          * can be done. */
725         eReturn = eCantSendPacket;
726     }
727     else if( *ipLOCAL_IP_ADDRESS_POINTER == *pulIPAddress )
728     {
729         /* The address of this device. May be useful for the loopback device. */
730         eReturn = eARPCacheHit;
731         ( void ) memcpy( pxMACAddress->ucBytes, ipLOCAL_MAC_ADDRESS, sizeof( pxMACAddress->ucBytes ) );
732     }
733     else
734     {
735         eReturn = eARPCacheMiss;
736 
737         if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
738         {
739             /* No matching end-point is found, look for a gateway. */
740             #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
741                 eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );
742 
743                 if( eReturn == eARPCacheHit )
744                 {
745                     /* The stack is configured to store 'remote IP addresses', i.e. addresses
746                      * belonging to a different the netmask.  prvCacheLookup() returned a hit, so
747                      * the MAC address is known. */
748                 }
749                 else
750             #endif
751             {
752                 /* The IP address is off the local network, so look up the
753                  * hardware address of the router, if any. */
754                 if( xNetworkAddressing.ulGatewayAddress != ( uint32_t ) 0U )
755                 {
756                     ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
757                 }
758                 else
759                 {
760                     ulAddressToLookup = *pulIPAddress;
761                 }
762             }
763         }
764         else
765         {
766             /* The IP address is on the local network, so lookup the requested
767              * IP address directly. */
768             ulAddressToLookup = *pulIPAddress;
769         }
770 
771         #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
772             if( eReturn == eARPCacheMiss ) /*lint !e774: (Info -- Boolean within 'if' always evaluates to True, depending on configuration. */
773         #else
774             /* No cache look-up was done, so the result is still 'eARPCacheMiss'. */
775         #endif
776         {
777             if( ulAddressToLookup == 0U )
778             {
779                 /* The address is not on the local network, and there is not a
780                  * router. */
781                 eReturn = eCantSendPacket;
782             }
783             else
784             {
785                 eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );
786 
787                 if( eReturn == eARPCacheMiss )
788                 {
789                     /* It might be that the ARP has to go to the gateway. */
790                     *pulIPAddress = ulAddressToLookup;
791                 }
792             }
793         }
794     }
795 
796     return eReturn;
797 }
798 
799 /*-----------------------------------------------------------*/
800 
801 /**
802  * @brief Lookup an IP address in the ARP cache.
803  *
804  * @param[in] ulAddressToLookup: The 32-bit representation of an IP address to
805  *                               lookup.
806  * @param[out] pxMACAddress: A pointer to MACAddress_t variable where, if there
807  *                          is an ARP cache hit, the MAC address corresponding to
808  *                          the IP address will be stored.
809  *
810  * @return When the IP-address is found: eARPCacheHit, when not found: eARPCacheMiss,
811  *         and when waiting for a ARP reply: eCantSendPacket.
812  */
prvCacheLookup(uint32_t ulAddressToLookup,MACAddress_t * const pxMACAddress)813 static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
814                                           MACAddress_t * const pxMACAddress )
815 {
816     BaseType_t x;
817     eARPLookupResult_t eReturn = eARPCacheMiss;
818 
819     /* Loop through each entry in the ARP cache. */
820     for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
821     {
822         /* Does this row in the ARP cache table hold an entry for the IP address
823          * being queried? */
824         if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
825         {
826             /* A matching valid entry was found. */
827             if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
828             {
829                 /* This entry is waiting an ARP reply, so is not valid. */
830                 eReturn = eCantSendPacket;
831             }
832             else
833             {
834                 /* A valid entry was found. */
835                 ( void ) memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
836                 eReturn = eARPCacheHit;
837             }
838 
839             break;
840         }
841     }
842 
843     return eReturn;
844 }
845 /*-----------------------------------------------------------*/
846 
847 /**
848  * @brief A call to this function will update (or 'Age') the ARP cache entries.
849  *        The function will also try to prevent a removal of entry by sending
850  *        an ARP query. It will also check whether we are waiting on an ARP
851  *        reply - if we are, then an ARP request will be re-sent.
852  *        In case an ARP entry has 'Aged' to 0, it will be removed from the ARP
853  *        cache.
854  */
vARPAgeCache(void)855 void vARPAgeCache( void )
856 {
857     BaseType_t x;
858     TickType_t xTimeNow;
859 
860     /* Loop through each entry in the ARP cache. */
861     for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
862     {
863         /* If the entry is valid (its age is greater than zero). */
864         if( xARPCache[ x ].ucAge > 0U )
865         {
866             /* Decrement the age value of the entry in this ARP cache table row.
867              * When the age reaches zero it is no longer considered valid. */
868             ( xARPCache[ x ].ucAge )--;
869 
870             /* If the entry is not yet valid, then it is waiting an ARP
871              * reply, and the ARP request should be retransmitted. */
872             if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
873             {
874                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
875             }
876             else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
877             {
878                 /* This entry will get removed soon.  See if the MAC address is
879                  * still valid to prevent this happening. */
880                 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
881                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
882             }
883             else
884             {
885                 /* The age has just ticked down, with nothing to do. */
886             }
887 
888             if( xARPCache[ x ].ucAge == 0U )
889             {
890                 /* The entry is no longer valid.  Wipe it out. */
891                 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
892                 xARPCache[ x ].ulIPAddress = 0U;
893             }
894         }
895     }
896 
897     xTimeNow = xTaskGetTickCount();
898 
899     if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
900     {
901         FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
902         xLastGratuitousARPTime = xTimeNow;
903     }
904 }
905 /*-----------------------------------------------------------*/
906 
907 /**
908  * @brief Send a Gratuitous ARP packet to allow this node to announce the IP-MAC
909  *        mapping to the entire network.
910  */
vARPSendGratuitous(void)911 void vARPSendGratuitous( void )
912 {
913     /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
914      * time vARPAgeCache() is called. */
915     xLastGratuitousARPTime = ( TickType_t ) 0;
916 
917     /* Let the IP-task call vARPAgeCache(). */
918     ( void ) xSendEventToIPTask( eARPTimerEvent );
919 }
920 
921 /*-----------------------------------------------------------*/
922 
923 /**
924  * @brief Create and send an ARP request packet.
925  *
926  * @param[in] ulIPAddress: A 32-bit representation of the IP-address whose
927  *                         physical (MAC) address is required.
928  */
FreeRTOS_OutputARPRequest(uint32_t ulIPAddress)929 void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
930 {
931     NetworkBufferDescriptor_t * pxNetworkBuffer;
932 
933     /* This is called from the context of the IP event task, so a block time
934      * must not be used. */
935     pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0U );
936 
937     if( pxNetworkBuffer != NULL )
938     {
939         pxNetworkBuffer->ulIPAddress = ulIPAddress;
940         vARPGenerateRequestPacket( pxNetworkBuffer );
941 
942         #if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
943             {
944                 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
945                 {
946                     BaseType_t xIndex;
947 
948                     for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
949                     {
950                         pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
951                     }
952 
953                     pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
954                 }
955             }
956         #endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
957 
958         if( xIsCallingFromIPTask() != pdFALSE )
959         {
960             iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
961             /* Only the IP-task is allowed to call this function directly. */
962             ( void ) xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
963         }
964         else
965         {
966             IPStackEvent_t xSendEvent;
967 
968             /* Send a message to the IP-task to send this ARP packet. */
969             xSendEvent.eEventType = eNetworkTxEvent;
970             xSendEvent.pvData = pxNetworkBuffer;
971 
972             if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
973             {
974                 /* Failed to send the message, so release the network buffer. */
975                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
976             }
977         }
978     }
979 }
980 /*-----------------------------------------------------------*/
981 
982 /**
983  * @brief  Wait for address resolution: look-up the IP-address in the ARP-cache, and if
984  *         needed send an ARP request, and wait for a reply.  This function is useful when
985  *         called before FreeRTOS_sendto().
986  *
987  * @param[in] ulIPAddress: The IP-address to look-up.
988  * @param[in] uxTicksToWait: The maximum number of clock ticks to wait for a reply.
989  *
990  * @return Zero when successful.
991  */
xARPWaitResolution(uint32_t ulIPAddress,TickType_t uxTicksToWait)992 BaseType_t xARPWaitResolution( uint32_t ulIPAddress,
993                                TickType_t uxTicksToWait )
994 {
995     BaseType_t xResult = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
996     TimeOut_t xTimeOut;
997     MACAddress_t xMACAddress;
998     eARPLookupResult_t xLookupResult;
999     size_t uxSendCount = ipconfigMAX_ARP_RETRANSMISSIONS;
1000     uint32_t ulIPAddressCopy = ulIPAddress;
1001 
1002     /* The IP-task is not supposed to call this function. */
1003     configASSERT( xIsCallingFromIPTask() == pdFALSE );
1004 
1005     xLookupResult = eARPGetCacheEntry( &( ulIPAddressCopy ), &( xMACAddress ) );
1006 
1007     if( xLookupResult == eARPCacheMiss )
1008     {
1009         const TickType_t uxSleepTime = pdMS_TO_TICKS( 250U );
1010 
1011         /* We might use ipconfigMAX_ARP_RETRANSMISSIONS here. */
1012         vTaskSetTimeOutState( &xTimeOut );
1013 
1014         while( uxSendCount > 0U )
1015         {
1016             FreeRTOS_OutputARPRequest( ulIPAddressCopy );
1017 
1018             vTaskDelay( uxSleepTime );
1019 
1020             xLookupResult = eARPGetCacheEntry( &( ulIPAddressCopy ), &( xMACAddress ) );
1021 
1022             if( ( xTaskCheckForTimeOut( &( xTimeOut ), &( uxTicksToWait ) ) == pdTRUE ) ||
1023                 ( xLookupResult != eARPCacheMiss ) )
1024             {
1025                 break;
1026             }
1027 
1028             /* Decrement the count. */
1029             uxSendCount--;
1030         }
1031     }
1032 
1033     if( xLookupResult == eARPCacheHit )
1034     {
1035         xResult = 0;
1036     }
1037 
1038     return xResult;
1039 }
1040 /*-----------------------------------------------------------*/
1041 
1042 /**
1043  * @brief Generate an ARP request packet by copying various constant details to
1044  *        the buffer.
1045  *
1046  * @param[in,out] pxNetworkBuffer: Pointer to the buffer which has to be filled with
1047  *                             the ARP request packet details.
1048  */
vARPGenerateRequestPacket(NetworkBufferDescriptor_t * const pxNetworkBuffer)1049 void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
1050 {
1051 /* Part of the Ethernet and ARP headers are always constant when sending an IPv4
1052  * ARP packet.  This array defines the constant parts, allowing this part of the
1053  * packet to be filled in using a simple memcpy() instead of individual writes. */
1054     static const uint8_t xDefaultPartARPPacketHeader[] =
1055     {
1056         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
1057         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
1058         0x08, 0x06,                         /* Ethernet frame type (ipARP_FRAME_TYPE). */
1059         0x00, 0x01,                         /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
1060         0x08, 0x00,                         /* usProtocolType. */
1061         ipMAC_ADDRESS_LENGTH_BYTES,         /* ucHardwareAddressLength. */
1062         ipIP_ADDRESS_LENGTH_BYTES,          /* ucProtocolAddressLength. */
1063         0x00, 0x01,                         /* usOperation (ipARP_REQUEST). */
1064         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
1065         0x00, 0x00, 0x00, 0x00,             /* ulSenderProtocolAddress. */
1066         0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* xTargetHardwareAddress. */
1067     };
1068 
1069     ARPPacket_t * pxARPPacket;
1070 
1071 /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
1072     const void * pvCopySource;
1073     void * pvCopyDest;
1074 
1075     /* Buffer allocation ensures that buffers always have space
1076      * for an ARP packet. See buffer allocation implementations 1
1077      * and 2 under portable/BufferManagement. */
1078     configASSERT( pxNetworkBuffer != NULL );
1079     configASSERT( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) );
1080 
1081     /* MISRA Ref 11.3.1 [Misaligned access] */
1082 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1083     /* coverity[misra_c_2012_rule_11_3_violation] */
1084     pxARPPacket = ( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
1085 
1086     /* memcpy the const part of the header information into the correct
1087      * location in the packet.  This copies:
1088      *  xEthernetHeader.ulDestinationAddress
1089      *  xEthernetHeader.usFrameType;
1090      *  xARPHeader.usHardwareType;
1091      *  xARPHeader.usProtocolType;
1092      *  xARPHeader.ucHardwareAddressLength;
1093      *  xARPHeader.ucProtocolAddressLength;
1094      *  xARPHeader.usOperation;
1095      *  xARPHeader.xTargetHardwareAddress;
1096      */
1097 
1098     /*
1099      * Use helper variables for memcpy() to remain
1100      * compliant with MISRA Rule 21.15.  These should be
1101      * optimized away.
1102      */
1103     pvCopySource = xDefaultPartARPPacketHeader;
1104     pvCopyDest = pxARPPacket;
1105     ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartARPPacketHeader ) );
1106 
1107     pvCopySource = ipLOCAL_MAC_ADDRESS;
1108     pvCopyDest = pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes;
1109     ( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
1110 
1111     pvCopySource = ipLOCAL_MAC_ADDRESS;
1112     pvCopyDest = pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes;
1113     ( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
1114 
1115     pvCopySource = ipLOCAL_IP_ADDRESS_POINTER;
1116     pvCopyDest = pxARPPacket->xARPHeader.ucSenderProtocolAddress;
1117     ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
1118     pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
1119 
1120     pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
1121 
1122     iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
1123 }
1124 /*-----------------------------------------------------------*/
1125 
1126 /**
1127  * @brief A call to this function will clear the ARP cache.
1128  */
FreeRTOS_ClearARP(void)1129 void FreeRTOS_ClearARP( void )
1130 {
1131     ( void ) memset( xARPCache, 0, sizeof( xARPCache ) );
1132 }
1133 /*-----------------------------------------------------------*/
1134 
1135 #if 1
1136 
1137 /**
1138  * @brief  This function will check if the target IP-address belongs to this device.
1139  *         If so, the packet will be passed to the IP-stack, who will answer it.
1140  *         The function is to be called within the function xNetworkInterfaceOutput().
1141  *
1142  * @param[in] pxDescriptor: The network buffer which is to be checked for loop-back.
1143  * @param[in] bReleaseAfterSend: pdTRUE: Driver is allowed to transfer ownership of descriptor.
1144  *                              pdFALSE: Driver is not allowed to take ownership of descriptor,
1145  *                                       make a copy of it.
1146  *
1147  * @return pdTRUE/pdFALSE: There is/isn't a loopback address in the packet.
1148  */
xCheckLoopback(NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t bReleaseAfterSend)1149     BaseType_t xCheckLoopback( NetworkBufferDescriptor_t * const pxDescriptor,
1150                                BaseType_t bReleaseAfterSend )
1151     {
1152         BaseType_t xResult = pdFALSE;
1153         NetworkBufferDescriptor_t * pxUseDescriptor = pxDescriptor;
1154 
1155         /* MISRA Ref 11.3.1 [Misaligned access] */
1156 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1157         /* coverity[misra_c_2012_rule_11_3_violation] */
1158         const IPPacket_t * pxIPPacket = ( ( IPPacket_t * ) pxUseDescriptor->pucEthernetBuffer );
1159 
1160         if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
1161         {
1162             if( memcmp( pxIPPacket->xEthernetHeader.xDestinationAddress.ucBytes, ipLOCAL_MAC_ADDRESS, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
1163             {
1164                 xResult = pdTRUE;
1165 
1166                 if( bReleaseAfterSend == pdFALSE )
1167                 {
1168                     /* Driver is not allowed to transfer the ownership
1169                      * of descriptor,  so make a copy of it */
1170                     pxUseDescriptor =
1171                         pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, pxDescriptor->xDataLength );
1172                 }
1173 
1174                 if( pxUseDescriptor != NULL )
1175                 {
1176                     IPStackEvent_t xRxEvent;
1177 
1178                     xRxEvent.eEventType = eNetworkRxEvent;
1179                     xRxEvent.pvData = pxUseDescriptor;
1180 
1181                     if( xSendEventStructToIPTask( &xRxEvent, 0U ) != pdTRUE )
1182                     {
1183                         vReleaseNetworkBufferAndDescriptor( pxUseDescriptor );
1184                         iptraceETHERNET_RX_EVENT_LOST();
1185                         FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
1186                     }
1187                 }
1188             }
1189         }
1190 
1191         return xResult;
1192     }
1193 
1194 #endif /* 0 */
1195 /*-----------------------------------------------------------*/
1196 
1197 #if ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
1198 
FreeRTOS_PrintARPCache(void)1199     void FreeRTOS_PrintARPCache( void )
1200     {
1201         BaseType_t x, xCount = 0;
1202 
1203         /* Loop through each entry in the ARP cache. */
1204         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
1205         {
1206             if( ( xARPCache[ x ].ulIPAddress != 0U ) && ( xARPCache[ x ].ucAge > ( uint8_t ) 0U ) )
1207             {
1208                 /* See if the MAC-address also matches, and we're all happy */
1209                 FreeRTOS_printf( ( "ARP %2d: %3u - %16xip : %02x:%02x:%02x : %02x:%02x:%02x\n",
1210                                    ( int ) x,
1211                                    xARPCache[ x ].ucAge,
1212                                    ( unsigned ) xARPCache[ x ].ulIPAddress,
1213                                    xARPCache[ x ].xMACAddress.ucBytes[ 0 ],
1214                                    xARPCache[ x ].xMACAddress.ucBytes[ 1 ],
1215                                    xARPCache[ x ].xMACAddress.ucBytes[ 2 ],
1216                                    xARPCache[ x ].xMACAddress.ucBytes[ 3 ],
1217                                    xARPCache[ x ].xMACAddress.ucBytes[ 4 ],
1218                                    xARPCache[ x ].xMACAddress.ucBytes[ 5 ] ) );
1219                 xCount++;
1220             }
1221         }
1222 
1223         FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
1224     }
1225 
1226 #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
1227