xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_ARP.c (revision 44765e48401de8f5325f1ad5774a6f185fd33dd7)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
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 #include "FreeRTOS_Routing.h"
57 #include "FreeRTOS_ND.h"
58 
59 
60 /** @brief When the age of an entry in the ARP table reaches this value (it counts down
61  * to zero, so this is an old entry) an ARP request will be sent to see if the
62  * entry is still valid and can therefore be refreshed. */
63 #define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST    ( 3U )
64 
65 /** @brief The time between gratuitous ARPs. */
66 #ifndef arpGRATUITOUS_ARP_PERIOD
67     #define arpGRATUITOUS_ARP_PERIOD    ( pdMS_TO_TICKS( 20000U ) )
68 #endif
69 
70 /** @brief When there is another device which has the same IP address as the IP address
71  * of this device, a defensive ARP request should be sent out. However, according to
72  * RFC 5227 section 1.1, there must be a minimum interval of 10 seconds between
73  * consecutive defensive ARP packets. */
74 #ifndef arpIP_CLASH_RESET_TIMEOUT_MS
75     #define arpIP_CLASH_RESET_TIMEOUT_MS    10000U
76 #endif
77 
78 /** @brief Maximum number of defensive ARPs to be sent for an ARP clash per
79  * arpIP_CLASH_RESET_TIMEOUT_MS period. The retries are limited to one as outlined
80  * by RFC 5227 section 2.4 part b.*/
81 #ifndef arpIP_CLASH_MAX_RETRIES
82     #define arpIP_CLASH_MAX_RETRIES    1U
83 #endif
84 
85 #if ( ipconfigUSE_IPv4 != 0 )
86 
87     static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame,
88                                           NetworkEndPoint_t * pxTargetEndPoint,
89                                           uint32_t ulSenderProtocolAddress );
90 
91     static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame,
92                                         NetworkEndPoint_t * pxTargetEndPoint,
93                                         uint32_t ulSenderProtocolAddress );
94 
95 /*
96  * Lookup an MAC address in the ARP cache from the IP address.
97  */
98     static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
99                                               MACAddress_t * const pxMACAddress,
100                                               NetworkEndPoint_t ** ppxEndPoint );
101 
102     static eARPLookupResult_t eARPGetCacheEntryGateWay( uint32_t * pulIPAddress,
103                                                         MACAddress_t * const pxMACAddress,
104                                                         struct xNetworkEndPoint ** ppxEndPoint );
105 
106 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
107 
108 static BaseType_t prvFindCacheEntry( const MACAddress_t * pxMACAddress,
109                                      const uint32_t ulIPAddress,
110                                      struct xNetworkEndPoint * pxEndPoint,
111                                      CacheLocation_t * pxLocation );
112 
113 /*-----------------------------------------------------------*/
114 
115 /** @brief The ARP cache. */
116 _static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
117 
118 /** @brief  The time at which the last gratuitous ARP was sent.  Gratuitous ARPs are used
119  * to ensure ARP tables are up to date and to detect IP address conflicts. */
120 static TickType_t xLastGratuitousARPTime = 0U;
121 
122 /*
123  * IP-clash detection is currently only used internally. When DHCP doesn't respond, the
124  * driver can try out a random LinkLayer IP address (169.254.x.x).  It will send out a
125  * gratuitous ARP message and, after a period of time, check the variables here below:
126  */
127 #if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
128     /* Becomes non-zero if another device responded to a gratuitous ARP message. */
129     BaseType_t xARPHadIPClash;
130     /* MAC-address of the other device containing the same IP-address. */
131     MACAddress_t xARPClashMacAddress;
132 #endif /* ipconfigARP_USE_CLASH_DETECTION */
133 
134 /*-----------------------------------------------------------*/
135 
136 #if ( ipconfigUSE_IPv4 != 0 )
137 
138 /**
139  * @brief Process the ARP packets.
140  *
141  * @param[in] pxNetworkBuffer The network buffer with the packet to be processed.
142  *
143  * @return An enum which says whether to return the frame or to release it.
144  */
eARPProcessPacket(const NetworkBufferDescriptor_t * pxNetworkBuffer)145     eFrameProcessingResult_t eARPProcessPacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
146     {
147         /* MISRA Ref 11.3.1 [Misaligned access] */
148         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
149         /* coverity[misra_c_2012_rule_11_3_violation] */
150         ARPPacket_t * pxARPFrame = ( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
151         eFrameProcessingResult_t eReturn = eReleaseBuffer;
152         const ARPHeader_t * pxARPHeader;
153         uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
154 
155         /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
156         const void * pvCopySource;
157         void * pvCopyDest;
158         NetworkEndPoint_t * pxTargetEndPoint = pxNetworkBuffer->pxEndPoint;
159 
160         /* Next defensive request must not be sent for arpIP_CLASH_RESET_TIMEOUT_MS
161          * period. */
162         static TickType_t uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS );
163 
164         /* This local variable is used to keep track of number of ARP requests sent and
165          * also to limit the requests to arpIP_CLASH_MAX_RETRIES per arpIP_CLASH_RESET_TIMEOUT_MS
166          * period. */
167         static UBaseType_t uxARPClashCounter = 0U;
168         /* The time at which the last ARP clash was sent. */
169         static TimeOut_t xARPClashTimeOut;
170 
171         pxARPHeader = &( pxARPFrame->xARPHeader );
172 
173         /* Only Ethernet hardware type is supported.
174          * Only IPv4 address can be present in the ARP packet.
175          * The hardware length (the MAC address) must be 6 bytes. And,
176          * The Protocol address length must be 4 bytes as it is IPv4. */
177         if( ( pxARPHeader->usHardwareType == ipARP_HARDWARE_TYPE_ETHERNET ) &&
178             ( pxARPHeader->usProtocolType == ipARP_PROTOCOL_TYPE ) &&
179             ( pxARPHeader->ucHardwareAddressLength == ipMAC_ADDRESS_LENGTH_BYTES ) &&
180             ( pxARPHeader->ucProtocolAddressLength == ipIP_ADDRESS_LENGTH_BYTES ) )
181         {
182             /* The field ucSenderProtocolAddress is badly aligned, copy byte-by-byte. */
183 
184             /*
185              * Use helper variables for memcpy() to remain
186              * compliant with MISRA Rule 21.15.  These should be
187              * optimized away.
188              */
189             pvCopySource = pxARPHeader->ucSenderProtocolAddress;
190             pvCopyDest = &ulSenderProtocolAddress;
191             ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulSenderProtocolAddress ) );
192             /* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
193             ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
194 
195             if( uxARPClashCounter != 0U )
196             {
197                 /* Has the timeout been reached? */
198                 if( xTaskCheckForTimeOut( &xARPClashTimeOut, &uxARPClashTimeoutPeriod ) == pdTRUE )
199                 {
200                     /* We have waited long enough, reset the counter. */
201                     uxARPClashCounter = 0;
202                 }
203             }
204 
205             /* Check whether the lowest bit of the highest byte is 1 to check for
206              * multicast address or even a broadcast address (FF:FF:FF:FF:FF:FF). */
207             if( ( pxARPHeader->xSenderHardwareAddress.ucBytes[ 0 ] & 0x01U ) == 0x01U )
208             {
209                 /* Senders address is a multicast OR broadcast address which is not
210                  * allowed for an ARP packet. Drop the packet. See RFC 1812 section
211                  * 3.3.2. */
212                 iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
213             }
214             else if( ( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) ) &&
215                      ( ( FreeRTOS_ntohl( ulSenderProtocolAddress ) ) < ipLAST_LOOPBACK_IPv4 ) )
216             {
217                 /* The local loopback addresses must never appear outside a host. See RFC 1122
218                  * section 3.2.1.3. */
219                 iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
220             }
221             /* Check whether there is a clash with another device for this IP address. */
222             else if( ( pxTargetEndPoint != NULL ) && ( ulSenderProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) )
223             {
224                 if( uxARPClashCounter < arpIP_CLASH_MAX_RETRIES )
225                 {
226                     /* Increment the counter. */
227                     uxARPClashCounter++;
228 
229                     /* Send out a defensive ARP request. */
230                     FreeRTOS_OutputARPRequest( pxTargetEndPoint->ipv4_settings.ulIPAddress );
231 
232                     /* Since an ARP Request for this IP was just sent, do not send a gratuitous
233                      * ARP for arpGRATUITOUS_ARP_PERIOD. */
234                     xLastGratuitousARPTime = xTaskGetTickCount();
235 
236                     /* Note the time at which this request was sent. */
237                     vTaskSetTimeOutState( &xARPClashTimeOut );
238 
239                     /* Reset the time-out period to the given value. */
240                     uxARPClashTimeoutPeriod = pdMS_TO_TICKS( arpIP_CLASH_RESET_TIMEOUT_MS );
241                 }
242 
243                 /* Process received ARP frame to see if there is a clash. */
244                 #if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
245                     {
246                         NetworkEndPoint_t * pxSourceEndPoint = FreeRTOS_FindEndPointOnIP_IPv4( ulSenderProtocolAddress, 2 );
247 
248                         if( ( pxSourceEndPoint != NULL ) && ( pxSourceEndPoint->ipv4_settings.ulIPAddress == ulSenderProtocolAddress ) )
249                         {
250                             xARPHadIPClash = pdTRUE;
251                             /* Remember the MAC-address of the other device which has the same IP-address. */
252                             ( void ) memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
253                         }
254                     }
255                 #endif /* ipconfigARP_USE_CLASH_DETECTION */
256             }
257             else
258             {
259                 traceARP_PACKET_RECEIVED();
260 
261                 /* Some extra logging while still testing. */
262                 #if ( ipconfigHAS_PRINTF != 0 )
263                     if( pxARPHeader->usOperation == ( uint16_t ) ipARP_REPLY )
264                     {
265                         FreeRTOS_printf( ( "ipARP_REPLY from %xip to %xip end-point %xip\n",
266                                            ( unsigned ) FreeRTOS_ntohl( ulSenderProtocolAddress ),
267                                            ( unsigned ) FreeRTOS_ntohl( ulTargetProtocolAddress ),
268                                            ( unsigned ) FreeRTOS_ntohl( ( pxTargetEndPoint != NULL ) ? pxTargetEndPoint->ipv4_settings.ulIPAddress : 0U ) ) );
269                     }
270                 #endif /* ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
271 
272                 #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
273                     if( ( pxARPHeader->usOperation == ( uint16_t ) ipARP_REQUEST ) &&
274                         ( ulSenderProtocolAddress != ulTargetProtocolAddress ) &&
275                         ( pxTargetEndPoint != NULL ) )
276                     {
277                         FreeRTOS_debug_printf( ( "ipARP_REQUEST from %xip to %xip end-point %xip\n",
278                                                  ( unsigned ) FreeRTOS_ntohl( ulSenderProtocolAddress ),
279                                                  ( unsigned ) FreeRTOS_ntohl( ulTargetProtocolAddress ),
280                                                  ( unsigned ) ( FreeRTOS_ntohl( ( pxTargetEndPoint != NULL ) ? pxTargetEndPoint->ipv4_settings.ulIPAddress : 0U ) ) ) );
281                     }
282                 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
283 
284                 /* ulTargetProtocolAddress won't be used unless logging is enabled. */
285                 ( void ) ulTargetProtocolAddress;
286 
287                 /* Don't do anything if the local IP address is zero because
288                  * that means a DHCP request has not completed. */
289                 if( ( pxTargetEndPoint != NULL ) && ( pxTargetEndPoint->bits.bEndPointUp != pdFALSE_UNSIGNED ) )
290                 {
291                     switch( pxARPHeader->usOperation )
292                     {
293                         case ipARP_REQUEST:
294 
295                             if( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress )
296                             {
297                                 if( memcmp( ( void * ) pxTargetEndPoint->xMACAddress.ucBytes,
298                                             ( pxARPHeader->xSenderHardwareAddress.ucBytes ),
299                                             ipMAC_ADDRESS_LENGTH_BYTES ) != 0 )
300                                 {
301                                     vARPProcessPacketRequest( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress );
302                                     eReturn = eReturnEthernetFrame;
303                                 }
304                             }
305                             /* Check if its a Gratuitous ARP request and verify if it belongs to same subnet mask. */
306                             else if( ( ulSenderProtocolAddress == ulTargetProtocolAddress ) &&
307                                      ( ( ulSenderProtocolAddress & pxTargetEndPoint->ipv4_settings.ulNetMask ) == ( pxTargetEndPoint->ipv4_settings.ulNetMask & pxTargetEndPoint->ipv4_settings.ulIPAddress ) ) )
308                             {
309                                 const MACAddress_t xGARPTargetAddress = { { 0, 0, 0, 0, 0, 0 } };
310 
311                                 /* Make sure target MAC address is either ff:ff:ff:ff:ff:ff or 00:00:00:00:00:00 and senders MAC
312                                  * address is not matching with the endpoint MAC address. */
313                                 if( ( ( memcmp( ( const void * ) pxARPHeader->xTargetHardwareAddress.ucBytes, xBroadcastMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ||
314                                       ( ( memcmp( ( const void * ) pxARPHeader->xTargetHardwareAddress.ucBytes, xGARPTargetAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) ) ) &&
315                                     ( memcmp( ( void * ) pxTargetEndPoint->xMACAddress.ucBytes, ( pxARPHeader->xSenderHardwareAddress.ucBytes ), ipMAC_ADDRESS_LENGTH_BYTES ) != 0 ) )
316                                 {
317                                     MACAddress_t xHardwareAddress;
318                                     NetworkEndPoint_t * pxCachedEndPoint;
319 
320                                     pxCachedEndPoint = NULL;
321 
322                                     /* The request is a Gratuitous ARP message.
323                                      * Refresh the entry if it already exists. */
324                                     /* Determine the ARP cache status for the requested IP address. */
325                                     if( eARPGetCacheEntry( &( ulSenderProtocolAddress ), &( xHardwareAddress ), &( pxCachedEndPoint ) ) == eARPCacheHit )
326                                     {
327                                         /* Check if the endpoint matches with the one present in the ARP cache */
328                                         if( pxCachedEndPoint == pxTargetEndPoint )
329                                         {
330                                             vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
331                                         }
332                                     }
333                                 }
334                             }
335                             else
336                             {
337                                 /* do nothing, coverity happy */
338                             }
339 
340                             break;
341 
342                         case ipARP_REPLY:
343                             vARPProcessPacketReply( pxARPFrame, pxTargetEndPoint, ulSenderProtocolAddress );
344                             break;
345 
346                         default:
347                             /* Invalid. */
348                             break;
349                     }
350                 }
351             }
352         }
353         else
354         {
355             iptraceDROPPED_INVALID_ARP_PACKET( pxARPHeader );
356         }
357 
358         return eReturn;
359     }
360 /*-----------------------------------------------------------*/
361 
362 /**
363  * @brief Process an ARP request packets.
364  *
365  * @param[in] pxARPFrame the complete ARP-frame.
366  * @param[in] pxTargetEndPoint the end-point that handles the peer's address.
367  * @param[in] ulSenderProtocolAddress the IP-address of the sender.
368  *
369  */
vARPProcessPacketRequest(ARPPacket_t * pxARPFrame,NetworkEndPoint_t * pxTargetEndPoint,uint32_t ulSenderProtocolAddress)370     static void vARPProcessPacketRequest( ARPPacket_t * pxARPFrame,
371                                           NetworkEndPoint_t * pxTargetEndPoint,
372                                           uint32_t ulSenderProtocolAddress )
373     {
374         ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader );
375 /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
376         const void * pvCopySource;
377         void * pvCopyDest;
378 
379 
380         /* The packet contained an ARP request.  Was it for the IP
381          * address of one of the end-points? */
382         /* It has been confirmed that pxTargetEndPoint is not NULL. */
383         iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
384 
385         /* The request is for the address of this node.  Add the
386          * entry into the ARP cache, or refresh the entry if it
387          * already exists. */
388         vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
389 
390         /* Generate a reply payload in the same buffer. */
391         pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
392 
393         /* A double IP address cannot be detected here, it is taken care in the Process ARP Packets path */
394 
395         /*
396          * Use helper variables for memcpy() to remain
397          * compliant with MISRA Rule 21.15.  These should be
398          * optimized away.
399          */
400         pvCopySource = pxARPHeader->xSenderHardwareAddress.ucBytes;
401         pvCopyDest = pxARPHeader->xTargetHardwareAddress.ucBytes;
402         ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
403         pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
404 
405         /*
406          * Use helper variables for memcpy() to remain
407          * compliant with MISRA Rule 21.15.  These should be
408          * optimized away.
409          */
410         pvCopySource = pxTargetEndPoint->xMACAddress.ucBytes;
411         pvCopyDest = pxARPHeader->xSenderHardwareAddress.ucBytes;
412         ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
413         pvCopySource = &( pxTargetEndPoint->ipv4_settings.ulIPAddress );
414         pvCopyDest = pxARPHeader->ucSenderProtocolAddress;
415         ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
416     }
417 /*-----------------------------------------------------------*/
418 
419 /**
420  * @brief A device has sent an ARP reply, process it.
421  * @param[in] pxARPFrame The ARP packet received.
422  * @param[in] pxTargetEndPoint The end-point on which it is received.
423  * @param[in] ulSenderProtocolAddress The IPv4 address involved.
424  */
vARPProcessPacketReply(const ARPPacket_t * pxARPFrame,NetworkEndPoint_t * pxTargetEndPoint,uint32_t ulSenderProtocolAddress)425     static void vARPProcessPacketReply( const ARPPacket_t * pxARPFrame,
426                                         NetworkEndPoint_t * pxTargetEndPoint,
427                                         uint32_t ulSenderProtocolAddress )
428     {
429         const ARPHeader_t * pxARPHeader = &( pxARPFrame->xARPHeader );
430         uint32_t ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
431 
432         /* If the packet is meant for this device or if the entry already exists. */
433         if( ( ulTargetProtocolAddress == pxTargetEndPoint->ipv4_settings.ulIPAddress ) ||
434             ( xIsIPInARPCache( ulSenderProtocolAddress ) == pdTRUE ) )
435         {
436             iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
437             vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress, pxTargetEndPoint );
438         }
439 
440         if( ( pxARPWaitingNetworkBuffer != NULL ) &&
441             ( uxIPHeaderSizePacket( pxARPWaitingNetworkBuffer ) == ipSIZE_OF_IPv4_HEADER ) )
442         {
443             /* MISRA Ref 11.3.1 [Misaligned access] */
444 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
445             /* coverity[misra_c_2012_rule_11_3_violation] */
446             const IPPacket_t * pxARPWaitingIPPacket = ( ( IPPacket_t * ) pxARPWaitingNetworkBuffer->pucEthernetBuffer );
447             const IPHeader_t * pxARPWaitingIPHeader = &( pxARPWaitingIPPacket->xIPHeader );
448 
449             if( ulSenderProtocolAddress == pxARPWaitingIPHeader->ulSourceIPAddress )
450             {
451                 IPStackEvent_t xEventMessage;
452                 const TickType_t xDontBlock = ( TickType_t ) 0;
453 
454                 xEventMessage.eEventType = eNetworkRxEvent;
455                 xEventMessage.pvData = ( void * ) pxARPWaitingNetworkBuffer;
456 
457                 if( xSendEventStructToIPTask( &xEventMessage, xDontBlock ) != pdPASS )
458                 {
459                     /* Failed to send the message, so release the network buffer. */
460                     vReleaseNetworkBufferAndDescriptor( pxARPWaitingNetworkBuffer );
461                 }
462 
463                 /* Clear the buffer. */
464                 pxARPWaitingNetworkBuffer = NULL;
465 
466                 /* Found an ARP resolution, disable ARP resolution timer. */
467                 vIPSetARPResolutionTimerEnableState( pdFALSE );
468 
469                 iptrace_DELAYED_ARP_REQUEST_REPLIED();
470             }
471         }
472     }
473 /*-----------------------------------------------------------*/
474 
475 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
476 
477 /**
478  * @brief Check whether an IP address is in the ARP cache.
479  *
480  * @param[in] ulAddressToLookup The 32-bit representation of an IP address to
481  *                    check for.
482  *
483  * @return When the IP-address is found: pdTRUE, else pdFALSE.
484  */
xIsIPInARPCache(uint32_t ulAddressToLookup)485 BaseType_t xIsIPInARPCache( uint32_t ulAddressToLookup )
486 {
487     BaseType_t x, xReturn = pdFALSE;
488 
489     /* Loop through each entry in the ARP cache. */
490     for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
491     {
492         /* Does this row in the ARP cache table hold an entry for the IP address
493          * being queried? */
494         if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
495         {
496             xReturn = pdTRUE;
497 
498             /* A matching valid entry was found. */
499             if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
500             {
501                 /* This entry is waiting an ARP reply, so is not valid. */
502                 xReturn = pdFALSE;
503             }
504 
505             break;
506         }
507     }
508 
509     return xReturn;
510 }
511 
512 /**
513  * @brief Check whether a packet needs ARP resolution if it is on local subnet. If required send an ARP request.
514  *
515  * @param[in] pxNetworkBuffer The network buffer with the packet to be checked.
516  *
517  * @return pdTRUE if the packet needs ARP resolution, pdFALSE otherwise.
518  */
xCheckRequiresARPResolution(const NetworkBufferDescriptor_t * pxNetworkBuffer)519 BaseType_t xCheckRequiresARPResolution( const NetworkBufferDescriptor_t * pxNetworkBuffer )
520 {
521     BaseType_t xNeedsARPResolution = pdFALSE;
522 
523     switch( uxIPHeaderSizePacket( pxNetworkBuffer ) )
524     {
525         #if ( ipconfigUSE_IPv4 != 0 )
526             case ipSIZE_OF_IPv4_HEADER:
527                {
528                    /* MISRA Ref 11.3.1 [Misaligned access] */
529                    /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
530                    /* coverity[misra_c_2012_rule_11_3_violation] */
531                    const IPPacket_t * pxIPPacket = ( ( const IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
532                    const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
533                    const IPV4Parameters_t * pxIPv4Settings = &( pxNetworkBuffer->pxEndPoint->ipv4_settings );
534 
535                    if( ( pxIPHeader->ulSourceIPAddress & pxIPv4Settings->ulNetMask ) == ( pxIPv4Settings->ulIPAddress & pxIPv4Settings->ulNetMask ) )
536                    {
537                        /* If the IP is on the same subnet and we do not have an ARP entry already,
538                         * then we should send out ARP for finding the MAC address. */
539                        if( xIsIPInARPCache( pxIPHeader->ulSourceIPAddress ) == pdFALSE )
540                        {
541                            FreeRTOS_OutputARPRequest( pxIPHeader->ulSourceIPAddress );
542 
543                            /* This packet needs resolution since this is on the same subnet
544                             * but not in the ARP cache. */
545                            xNeedsARPResolution = pdTRUE;
546                        }
547                    }
548 
549                    break;
550                }
551         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
552 
553         #if ( ipconfigUSE_IPv6 != 0 )
554             case ipSIZE_OF_IPv6_HEADER:
555                {
556                    /* MISRA Ref 11.3.1 [Misaligned access] */
557                    /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
558                    /* coverity[misra_c_2012_rule_11_3_violation] */
559                    IPPacket_IPv6_t * pxIPPacket = ( ( IPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
560                    IPHeader_IPv6_t * pxIPHeader = &( pxIPPacket->xIPHeader );
561                    IPv6_Address_t * pxIPAddress = &( pxIPHeader->xSourceAddress );
562                    uint8_t ucNextHeader = pxIPHeader->ucNextHeader;
563 
564                    if( ( ucNextHeader == ipPROTOCOL_TCP ) ||
565                        ( ucNextHeader == ipPROTOCOL_UDP ) )
566                    {
567                        IPv6_Type_t eType = xIPv6_GetIPType( ( const IPv6_Address_t * ) pxIPAddress );
568                        FreeRTOS_printf( ( "xCheckRequiresARPResolution: %pip type %s\n", ( void * ) pxIPAddress->ucBytes, ( eType == eIPv6_Global ) ? "Global" : ( eType == eIPv6_LinkLocal ) ? "LinkLocal" : "other" ) );
569 
570                        if( eType == eIPv6_LinkLocal )
571                        {
572                            MACAddress_t xMACAddress;
573                            NetworkEndPoint_t * pxEndPoint;
574                            eARPLookupResult_t eResult;
575                            char pcName[ 80 ];
576 
577                            ( void ) memset( &( pcName ), 0, sizeof( pcName ) );
578                            eResult = eNDGetCacheEntry( pxIPAddress, &xMACAddress, &pxEndPoint );
579                            FreeRTOS_printf( ( "xCheckRequiresARPResolution: eResult %s with EP %s\n", ( eResult == eARPCacheMiss ) ? "Miss" : ( eResult == eARPCacheHit ) ? "Hit" : "Error", pcEndpointName( pxEndPoint, pcName, sizeof pcName ) ) );
580 
581                            if( eResult == eARPCacheMiss )
582                            {
583                                NetworkBufferDescriptor_t * pxTempBuffer;
584                                size_t uxNeededSize;
585 
586                                uxNeededSize = ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER + sizeof( ICMPRouterSolicitation_IPv6_t );
587                                pxTempBuffer = pxGetNetworkBufferWithDescriptor( BUFFER_FROM_WHERE_CALL( 199 ) uxNeededSize, 0U );
588 
589                                if( pxTempBuffer != NULL )
590                                {
591                                    pxTempBuffer->pxEndPoint = pxNetworkBuffer->pxEndPoint;
592                                    pxTempBuffer->pxInterface = pxNetworkBuffer->pxInterface;
593                                    vNDSendNeighbourSolicitation( pxTempBuffer, pxIPAddress );
594                                }
595 
596                                xNeedsARPResolution = pdTRUE;
597                            }
598                        }
599                    }
600 
601                    break;
602                }
603         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
604 
605         default:
606             /* Shouldn't reach here */
607             /* MISRA 16.4 Compliance */
608             break;
609     }
610 
611     return xNeedsARPResolution;
612 }
613 
614 #if ( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
615 
616 /**
617  * @brief Remove an ARP cache entry that matches with .pxMACAddress.
618  *
619  * @param[in] pxMACAddress Pointer to the MAC address whose entry shall
620  *                          be removed.
621  * @return When the entry was found and remove: the IP-address, otherwise zero.
622  */
ulARPRemoveCacheEntryByMac(const MACAddress_t * pxMACAddress)623     uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
624     {
625         BaseType_t x;
626         uint32_t lResult = 0;
627 
628         configASSERT( pxMACAddress != NULL );
629 
630         /* For each entry in the ARP cache table. */
631         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
632         {
633             if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
634             {
635                 lResult = xARPCache[ x ].ulIPAddress;
636                 ( void ) memset( &xARPCache[ x ], 0, sizeof( xARPCache[ x ] ) );
637                 break;
638             }
639         }
640 
641         return lResult;
642     }
643 
644 #endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
645 /*-----------------------------------------------------------*/
646 
647 /**
648  * @brief Look for an IP-MAC couple in ARP cache and reset the 'age' field. If no match
649  *        is found then no action will be taken.
650  *
651  * @param[in] pxMACAddress Pointer to the MAC address whose entry needs to be updated.
652  * @param[in] ulIPAddress the IP address whose corresponding entry needs to be updated.
653  */
vARPRefreshCacheEntryAge(const MACAddress_t * pxMACAddress,const uint32_t ulIPAddress)654 void vARPRefreshCacheEntryAge( const MACAddress_t * pxMACAddress,
655                                const uint32_t ulIPAddress )
656 {
657     BaseType_t x;
658 
659     if( pxMACAddress != NULL )
660     {
661         /* Loop through each entry in the ARP cache. */
662         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
663         {
664             /* Does this line in the cache table hold an entry for the IP
665              * address being queried? */
666             if( xARPCache[ x ].ulIPAddress == ulIPAddress )
667             {
668                 /* Does this cache entry have the same MAC address? */
669                 if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
670                 {
671                     /* The IP address and the MAC matched, update this entry age. */
672                     xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
673                     break;
674                 }
675             }
676         }
677     }
678 }
679 /*-----------------------------------------------------------*/
680 
681 /**
682  * @brief Add/update the ARP cache entry MAC-address to IP-address mapping.
683  *
684  * @param[in] pxMACAddress Pointer to the MAC address whose mapping is being
685  *                          updated.
686  * @param[in] ulIPAddress 32-bit representation of the IP-address whose mapping
687  *                         is being updated.
688  * @param[in] pxEndPoint The end-point stored in the table.
689  */
vARPRefreshCacheEntry(const MACAddress_t * pxMACAddress,const uint32_t ulIPAddress,struct xNetworkEndPoint * pxEndPoint)690 void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
691                             const uint32_t ulIPAddress,
692                             struct xNetworkEndPoint * pxEndPoint )
693 {
694     #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
695         /* Only process the IP address if it is on the local network. */
696         BaseType_t xAddressIsLocal = ( FreeRTOS_FindEndPointOnNetMask( ulIPAddress, 2 ) != NULL ) ? 1 : 0; /* ARP remote address. */
697 
698         /* Only process the IP address if it matches with one of the end-points. */
699         if( xAddressIsLocal != 0 )
700     #else
701 
702         /* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
703          * a different netmask will also be stored.  After when replying to a UDP
704          * message from a different netmask, the IP address can be looped up and a
705          * reply sent.  This option is useful for systems with multiple gateways,
706          * the reply will surely arrive.  If ipconfigARP_STORES_REMOTE_ADDRESSES is
707          * zero the the gateway address is the only option. */
708 
709         if( pdTRUE )
710     #endif
711     {
712         CacheLocation_t xLocation;
713         BaseType_t xReady;
714 
715         xReady = prvFindCacheEntry( pxMACAddress, ulIPAddress, pxEndPoint, &( xLocation ) );
716 
717         if( xReady == pdFALSE )
718         {
719             if( xLocation.xMacEntry >= 0 )
720             {
721                 xLocation.xUseEntry = xLocation.xMacEntry;
722 
723                 if( xLocation.xIpEntry >= 0 )
724                 {
725                     /* Both the MAC address as well as the IP address were found in
726                      * different locations: clear the entry which matches the
727                      * IP-address */
728                     ( void ) memset( &( xARPCache[ xLocation.xIpEntry ] ), 0, sizeof( ARPCacheRow_t ) );
729                 }
730             }
731             else if( xLocation.xIpEntry >= 0 )
732             {
733                 /* An entry containing the IP-address was found, but it had a different MAC address */
734                 xLocation.xUseEntry = xLocation.xIpEntry;
735             }
736             else
737             {
738                 /* No matching entry found. */
739             }
740 
741             /* If the entry was not found, we use the oldest entry and set the IPaddress */
742             xARPCache[ xLocation.xUseEntry ].ulIPAddress = ulIPAddress;
743 
744             if( pxMACAddress != NULL )
745             {
746                 ( void ) memcpy( xARPCache[ xLocation.xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
747 
748                 iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ( *pxMACAddress ) );
749                 /* And this entry does not need immediate attention */
750                 xARPCache[ xLocation.xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
751                 xARPCache[ xLocation.xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
752                 xARPCache[ xLocation.xUseEntry ].pxEndPoint = pxEndPoint;
753             }
754             else if( xLocation.xIpEntry < 0 )
755             {
756                 xARPCache[ xLocation.xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
757                 xARPCache[ xLocation.xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
758             }
759             else
760             {
761                 /* Nothing will be stored. */
762             }
763         }
764     }
765 }
766 /*-----------------------------------------------------------*/
767 
768 /**
769  * @brief The results of an ARP look-up shall be stored in the ARP cache.
770  *        This helper function looks up the location.
771  * @param[in] pxMACAddress The MAC-address belonging to the IP-address.
772  * @param[in] ulIPAddress The IP-address of the entry.
773  * @param[in] pxEndPoint The end-point that will stored in the table.
774  * @param[out] pxLocation The results of this search are written in this struct.
775  */
prvFindCacheEntry(const MACAddress_t * pxMACAddress,const uint32_t ulIPAddress,struct xNetworkEndPoint * pxEndPoint,CacheLocation_t * pxLocation)776 static BaseType_t prvFindCacheEntry( const MACAddress_t * pxMACAddress,
777                                      const uint32_t ulIPAddress,
778                                      struct xNetworkEndPoint * pxEndPoint,
779                                      CacheLocation_t * pxLocation )
780 {
781     BaseType_t x = 0;
782     uint8_t ucMinAgeFound = 0U;
783     BaseType_t xReturn = pdFALSE;
784 
785     #if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
786         BaseType_t xAddressIsLocal = ( FreeRTOS_FindEndPointOnNetMask( ulIPAddress, 2 ) != NULL ) ? 1 : 0; /* ARP remote address. */
787     #endif
788 
789     /* Start with the maximum possible number. */
790     ucMinAgeFound--;
791 
792     pxLocation->xIpEntry = -1;
793     pxLocation->xMacEntry = -1;
794     pxLocation->xUseEntry = 0;
795 
796     /* For each entry in the ARP cache table. */
797     for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
798     {
799         BaseType_t xMatchingMAC = pdFALSE;
800 
801         if( pxMACAddress != NULL )
802         {
803             if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
804             {
805                 xMatchingMAC = pdTRUE;
806             }
807         }
808 
809         /* Does this line in the cache table hold an entry for the IP
810          * address being queried? */
811         if( xARPCache[ x ].ulIPAddress == ulIPAddress )
812         {
813             if( pxMACAddress == NULL )
814             {
815                 /* In case the parameter pxMACAddress is NULL, an entry will be reserved to
816                  * indicate that there is an outstanding ARP request, This entry will have
817                  * "ucValid == pdFALSE". */
818                 pxLocation->xIpEntry = x;
819                 break;
820             }
821 
822             /* See if the MAC-address also matches. */
823             if( xMatchingMAC != pdFALSE )
824             {
825                 /* This function will be called for each received packet
826                  * This is by far the most common path. */
827                 xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
828                 xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
829                 xARPCache[ x ].pxEndPoint = pxEndPoint;
830                 /* Indicate to the caller that the entry is updated. */
831                 xReturn = pdTRUE;
832                 break;
833             }
834 
835             /* Found an entry containing ulIPAddress, but the MAC address
836              * doesn't match.  Might be an entry with ucValid=pdFALSE, waiting
837              * for an ARP reply.  Still want to see if there is match with the
838              * given MAC address.ucBytes.  If found, either of the two entries
839              * must be cleared. */
840             pxLocation->xIpEntry = x;
841         }
842         else if( xMatchingMAC != pdFALSE )
843         {
844             /* Found an entry with the given MAC-address, but the IP-address
845              * is different.  Continue looping to find a possible match with
846              * ulIPAddress. */
847             #if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
848                 {
849                     /* If ARP stores the MAC address of IP addresses outside the
850                      * network, than the MAC address of the gateway should not be
851                      * overwritten. */
852                     BaseType_t xOtherIsLocal = ( FreeRTOS_FindEndPointOnNetMask( xARPCache[ x ].ulIPAddress, 3 ) != NULL ) ? 1 : 0; /* ARP remote address. */
853 
854                     if( xAddressIsLocal == xOtherIsLocal )
855                     {
856                         pxLocation->xMacEntry = x;
857                     }
858                 }
859             #else /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
860                 {
861                     pxLocation->xMacEntry = x;
862                 }
863             #endif /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
864         }
865 
866         /* _HT_
867          * Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
868         else if( xARPCache[ x ].ucAge < ucMinAgeFound )
869         {
870             /* As the table is traversed, remember the table row that
871              * contains the oldest entry (the lowest age count, as ages are
872              * decremented to zero) so the row can be re-used if this function
873              * needs to add an entry that does not already exist. */
874             ucMinAgeFound = xARPCache[ x ].ucAge;
875             pxLocation->xUseEntry = x;
876         }
877         else
878         {
879             /* Nothing happens to this cache entry for now. */
880         }
881     } /* for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ ) */
882 
883     return xReturn;
884 }
885 /*-----------------------------------------------------------*/
886 
887 #if ( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
888 
889 /**
890  * @brief Retrieve an entry from the cache table
891  *
892  * @param[in] pxMACAddress The MAC-address of the entry of interest.
893  * @param[out] pulIPAddress set to the IP-address found, or unchanged when not found.
894  *
895  * @return Either eARPCacheMiss or eARPCacheHit.
896  */
eARPGetCacheEntryByMac(const MACAddress_t * const pxMACAddress,uint32_t * pulIPAddress,struct xNetworkInterface ** ppxInterface)897     eARPLookupResult_t eARPGetCacheEntryByMac( const MACAddress_t * const pxMACAddress,
898                                                uint32_t * pulIPAddress,
899                                                struct xNetworkInterface ** ppxInterface )
900     {
901         BaseType_t x;
902         eARPLookupResult_t eReturn = eARPCacheMiss;
903 
904         configASSERT( pxMACAddress != NULL );
905         configASSERT( pulIPAddress != NULL );
906 
907         if( ppxInterface != NULL )
908         {
909             *( ppxInterface ) = NULL;
910         }
911 
912         /* Loop through each entry in the ARP cache. */
913         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
914         {
915             /* Does this row in the ARP cache table hold an entry for the MAC
916              * address being searched? */
917             if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
918             {
919                 *pulIPAddress = xARPCache[ x ].ulIPAddress;
920 
921                 if( ( ppxInterface != NULL ) &&
922                     ( xARPCache[ x ].pxEndPoint != NULL ) )
923                 {
924                     *( ppxInterface ) = xARPCache[ x ].pxEndPoint->pxNetworkInterface;
925                 }
926 
927                 eReturn = eARPCacheHit;
928                 break;
929             }
930         }
931 
932         return eReturn;
933     }
934 #endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
935 
936 /*-----------------------------------------------------------*/
937 
938 #if ( ipconfigUSE_IPv4 != 0 )
939 
940 /**
941  * @brief Look for ulIPAddress in the ARP cache.
942  *
943  * @param[in,out] pulIPAddress Pointer to the IP-address to be queried to the ARP cache.
944  * @param[in,out] pxMACAddress Pointer to a MACAddress_t variable where the MAC address
945  *                          will be stored, if found.
946  * @param[out] ppxEndPoint Pointer to the end-point of the gateway will be stored.
947  *
948  * @return If the IP address exists, copy the associated MAC address into pxMACAddress,
949  *         refresh the ARP cache entry's age, and return eARPCacheHit. If the IP
950  *         address does not exist in the ARP cache return eARPCacheMiss. If the packet
951  *         cannot be sent for any reason (maybe DHCP is still in process, or the
952  *         addressing needs a gateway but there isn't a gateway defined) then return
953  *         eCantSendPacket.
954  */
eARPGetCacheEntry(uint32_t * pulIPAddress,MACAddress_t * const pxMACAddress,struct xNetworkEndPoint ** ppxEndPoint)955     eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress,
956                                           MACAddress_t * const pxMACAddress,
957                                           struct xNetworkEndPoint ** ppxEndPoint )
958     {
959         eARPLookupResult_t eReturn;
960         uint32_t ulAddressToLookup;
961         NetworkEndPoint_t * pxEndPoint = NULL;
962 
963         configASSERT( pxMACAddress != NULL );
964         configASSERT( pulIPAddress != NULL );
965         configASSERT( ppxEndPoint != NULL );
966 
967         *( ppxEndPoint ) = NULL;
968         ulAddressToLookup = *pulIPAddress;
969         pxEndPoint = FreeRTOS_FindEndPointOnIP_IPv4( ulAddressToLookup, 0 );
970 
971         if( xIsIPv4Multicast( ulAddressToLookup ) != 0 )
972         {
973             /* Get the lowest 23 bits of the IP-address. */
974             vSetMultiCastIPv4MacAddress( ulAddressToLookup, pxMACAddress );
975 
976             eReturn = eCantSendPacket;
977             pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
978 
979             for( ;
980                  pxEndPoint != NULL;
981                  pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) )
982             {
983                 if( pxEndPoint->bits.bIPv6 == 0U ) /*NULL End Point is checked in the for loop, no need for an extra check */
984                 {
985                     /* For multi-cast, use the first IPv4 end-point. */
986                     *( ppxEndPoint ) = pxEndPoint;
987                     eReturn = eARPCacheHit;
988                     break;
989                 }
990             }
991         }
992         else if( ( FreeRTOS_htonl( ulAddressToLookup ) & 0xffU ) == 0xffU ) /* Is this a broadcast address like x.x.x.255 ? */
993         {
994             /* This is a broadcast so it uses the broadcast MAC address. */
995             ( void ) memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
996             pxEndPoint = FreeRTOS_FindEndPointOnNetMask( ulAddressToLookup, 4 );
997 
998             if( pxEndPoint != NULL )
999             {
1000                 *( ppxEndPoint ) = pxEndPoint;
1001             }
1002 
1003             eReturn = eARPCacheHit;
1004         }
1005         else
1006         {
1007             eReturn = eARPGetCacheEntryGateWay( pulIPAddress, pxMACAddress, ppxEndPoint );
1008         }
1009 
1010         return eReturn;
1011     }
1012 /*-----------------------------------------------------------*/
1013 
1014 /**
1015  * @brief The IPv4 address is apparently a web-address. Find a gateway..
1016  * @param[in] pulIPAddress The target IP-address. It may be replaced with the IP
1017  *                          address of a gateway.
1018  * @param[in] pxMACAddress In case the MAC-address is found in cache, it will be
1019  *                          stored to the buffer provided.
1020  * @param[out] ppxEndPoint The end-point of the gateway will be copy to the pointee.
1021  */
eARPGetCacheEntryGateWay(uint32_t * pulIPAddress,MACAddress_t * const pxMACAddress,struct xNetworkEndPoint ** ppxEndPoint)1022     static eARPLookupResult_t eARPGetCacheEntryGateWay( uint32_t * pulIPAddress,
1023                                                         MACAddress_t * const pxMACAddress,
1024                                                         struct xNetworkEndPoint ** ppxEndPoint )
1025     {
1026         eARPLookupResult_t eReturn = eARPCacheMiss;
1027         uint32_t ulAddressToLookup = *( pulIPAddress );
1028         NetworkEndPoint_t * pxEndPoint;
1029         uint32_t ulOrginal = *pulIPAddress;
1030 
1031         /* It is assumed that devices with the same netmask are on the same
1032          * LAN and don't need a gateway. */
1033         pxEndPoint = FreeRTOS_FindEndPointOnNetMask( ulAddressToLookup, 4 );
1034 
1035         if( pxEndPoint == NULL )
1036         {
1037             /* No matching end-point is found, look for a gateway. */
1038             #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
1039                 eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress, ppxEndPoint );
1040 
1041                 if( eReturn == eARPCacheHit )
1042                 {
1043                     /* The stack is configured to store 'remote IP addresses', i.e. addresses
1044                      * belonging to a different the netmask.  prvCacheLookup() returned a hit, so
1045                      * the MAC address is known. */
1046                 }
1047                 else
1048             #endif
1049             {
1050                 /* The IP address is off the local network, so look up the
1051                  * hardware address of the router, if any. */
1052                 *( ppxEndPoint ) = FreeRTOS_FindGateWay( ( BaseType_t ) ipTYPE_IPv4 );
1053 
1054                 if( *( ppxEndPoint ) != NULL )
1055                 {
1056                     /* 'ipv4_settings' can be accessed safely, because 'ipTYPE_IPv4' was provided. */
1057                     ulAddressToLookup = ( *ppxEndPoint )->ipv4_settings.ulGatewayAddress;
1058                 }
1059                 else
1060                 {
1061                     ulAddressToLookup = *pulIPAddress;
1062                 }
1063             }
1064         }
1065         else
1066         {
1067             /* The IP address is on the local network, so lookup the requested
1068              * IP address directly. */
1069             ulAddressToLookup = *pulIPAddress;
1070             *ppxEndPoint = pxEndPoint;
1071         }
1072 
1073         #if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
1074             if( eReturn == eARPCacheMiss )
1075         #endif
1076         {
1077             if( ulAddressToLookup == 0U )
1078             {
1079                 /* The address is not on the local network, and there is not a
1080                  * router. */
1081                 eReturn = eCantSendPacket;
1082             }
1083             else
1084             {
1085                 eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress, ppxEndPoint );
1086 
1087                 if( ( eReturn != eARPCacheHit ) || ( ulOrginal != ulAddressToLookup ) )
1088                 {
1089                     FreeRTOS_debug_printf( ( "ARP %xip %s using %xip\n",
1090                                              ( unsigned ) FreeRTOS_ntohl( ulOrginal ),
1091                                              ( eReturn == eARPCacheHit ) ? "hit" : "miss",
1092                                              ( unsigned ) FreeRTOS_ntohl( ulAddressToLookup ) ) );
1093                 }
1094 
1095                 /* It might be that the ARP has to go to the gateway. */
1096                 *pulIPAddress = ulAddressToLookup;
1097             }
1098         }
1099 
1100         return eReturn;
1101     }
1102 /*-----------------------------------------------------------*/
1103 
1104 /**
1105  * @brief Lookup an IP address in the ARP cache.
1106  *
1107  * @param[in] ulAddressToLookup The 32-bit representation of an IP address to
1108  *                               lookup.
1109  * @param[out] pxMACAddress A pointer to MACAddress_t variable where, if there
1110  *                          is an ARP cache hit, the MAC address corresponding to
1111  *                          the IP address will be stored.
1112  * @param[in,out] ppxEndPoint a pointer to the end-point will be stored.
1113  *
1114  * @return When the IP-address is found: eARPCacheHit, when not found: eARPCacheMiss,
1115  *         and when waiting for a ARP reply: eCantSendPacket.
1116  */
prvCacheLookup(uint32_t ulAddressToLookup,MACAddress_t * const pxMACAddress,NetworkEndPoint_t ** ppxEndPoint)1117     static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
1118                                               MACAddress_t * const pxMACAddress,
1119                                               NetworkEndPoint_t ** ppxEndPoint )
1120     {
1121         BaseType_t x;
1122         eARPLookupResult_t eReturn = eARPCacheMiss;
1123 
1124         /* Loop through each entry in the ARP cache. */
1125         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
1126         {
1127             /* Does this row in the ARP cache table hold an entry for the IP address
1128              * being queried? */
1129             if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
1130             {
1131                 /* A matching valid entry was found. */
1132                 if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
1133                 {
1134                     /* This entry is waiting an ARP reply, so is not valid. */
1135                     eReturn = eCantSendPacket;
1136                 }
1137                 else
1138                 {
1139                     /* A valid entry was found. */
1140                     ( void ) memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
1141                     /* ppxEndPoint != NULL was tested in the only caller eARPGetCacheEntry(). */
1142                     *( ppxEndPoint ) = xARPCache[ x ].pxEndPoint;
1143                     eReturn = eARPCacheHit;
1144                 }
1145 
1146                 break;
1147             }
1148         }
1149 
1150         return eReturn;
1151     }
1152 /*-----------------------------------------------------------*/
1153 
1154 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1155 
1156 /**
1157  * @brief A call to this function will update (or 'Age') the ARP cache entries.
1158  *        The function will also try to prevent a removal of entry by sending
1159  *        an ARP query. It will also check whether we are waiting on an ARP
1160  *        reply - if we are, then an ARP request will be re-sent.
1161  *        In case an ARP entry has 'Aged' to 0, it will be removed from the ARP
1162  *        cache.
1163  */
vARPAgeCache(void)1164 void vARPAgeCache( void )
1165 {
1166     BaseType_t x;
1167     TickType_t xTimeNow;
1168 
1169     /* Loop through each entry in the ARP cache. */
1170     for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
1171     {
1172         /* If the entry is valid (its age is greater than zero). */
1173         if( xARPCache[ x ].ucAge > 0U )
1174         {
1175             /* Decrement the age value of the entry in this ARP cache table row.
1176              * When the age reaches zero it is no longer considered valid. */
1177             ( xARPCache[ x ].ucAge )--;
1178 
1179             /* If the entry is not yet valid, then it is waiting an ARP
1180              * reply, and the ARP request should be retransmitted. */
1181             if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
1182             {
1183                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
1184             }
1185             else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
1186             {
1187                 /* This entry will get removed soon.  See if the MAC address is
1188                  * still valid to prevent this happening. */
1189                 iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
1190                 FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
1191             }
1192             else
1193             {
1194                 /* The age has just ticked down, with nothing to do. */
1195             }
1196 
1197             if( xARPCache[ x ].ucAge == 0U )
1198             {
1199                 /* The entry is no longer valid.  Wipe it out. */
1200                 iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
1201                 xARPCache[ x ].ulIPAddress = 0U;
1202             }
1203         }
1204     }
1205 
1206     xTimeNow = xTaskGetTickCount();
1207 
1208     if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
1209     {
1210         NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
1211 
1212         while( pxEndPoint != NULL )
1213         {
1214             if( ( pxEndPoint->bits.bEndPointUp != pdFALSE_UNSIGNED ) && ( pxEndPoint->ipv4_settings.ulIPAddress != 0U ) )
1215             {
1216                 /* Case default is never toggled because IPv6 flag can be TRUE or FALSE */
1217                 switch( pxEndPoint->bits.bIPv6 ) /* LCOV_EXCL_BR_LINE */
1218                 {
1219                     #if ( ipconfigUSE_IPv4 != 0 )
1220                         case pdFALSE_UNSIGNED:
1221                             FreeRTOS_OutputARPRequest( pxEndPoint->ipv4_settings.ulIPAddress );
1222                             break;
1223                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1224 
1225                     #if ( ipconfigUSE_IPv6 != 0 )
1226                         case pdTRUE_UNSIGNED:
1227                             FreeRTOS_OutputAdvertiseIPv6( pxEndPoint );
1228                             break;
1229                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1230 
1231                     default: /* LCOV_EXCL_LINE */
1232                         /* Shouldn't reach here */
1233                         /* MISRA 16.4 Compliance */
1234                         break; /* LCOV_EXCL_LINE */
1235                 }
1236             }
1237 
1238             pxEndPoint = pxEndPoint->pxNext;
1239         }
1240 
1241         xLastGratuitousARPTime = xTimeNow;
1242     }
1243 }
1244 /*-----------------------------------------------------------*/
1245 
1246 /**
1247  * @brief Send a Gratuitous ARP packet to allow this node to announce the IP-MAC
1248  *        mapping to the entire network.
1249  */
vARPSendGratuitous(void)1250 void vARPSendGratuitous( void )
1251 {
1252     /* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
1253      * time vARPAgeCache() is called. */
1254     xLastGratuitousARPTime = ( TickType_t ) 0;
1255 
1256     /* Let the IP-task call vARPAgeCache(). */
1257     ( void ) xSendEventToIPTask( eARPTimerEvent );
1258 }
1259 
1260 /*-----------------------------------------------------------*/
1261 
1262 /**
1263  * @brief Create and send an ARP request packet.
1264  *
1265  * @param[in] ulIPAddress A 32-bit representation of the IP-address whose
1266  *                         physical (MAC) address is required.
1267  */
FreeRTOS_OutputARPRequest(uint32_t ulIPAddress)1268 void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
1269 {
1270     NetworkBufferDescriptor_t * pxNetworkBuffer;
1271     NetworkEndPoint_t * pxEndPoint;
1272 
1273     /* Send an ARP request to every end-point which has the type IPv4,
1274      * and which already has an IP-address assigned. */
1275     for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
1276          pxEndPoint != NULL;
1277          pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) )
1278     {
1279         if( ( pxEndPoint->bits.bIPv6 == pdFALSE_UNSIGNED ) &&
1280             ( pxEndPoint->ipv4_settings.ulIPAddress != 0U ) )
1281         {
1282             /* This is called from the context of the IP event task, so a block time
1283              * must not be used. */
1284             pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0U );
1285 
1286             if( pxNetworkBuffer != NULL )
1287             {
1288                 pxNetworkBuffer->xIPAddress.ulIP_IPv4 = ulIPAddress;
1289                 pxNetworkBuffer->pxEndPoint = pxEndPoint;
1290                 pxNetworkBuffer->pxInterface = pxEndPoint->pxNetworkInterface;
1291                 vARPGenerateRequestPacket( pxNetworkBuffer );
1292 
1293                 #if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
1294                     {
1295                         if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
1296                         {
1297                             BaseType_t xIndex;
1298 
1299                             for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
1300                             {
1301                                 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
1302                             }
1303 
1304                             pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
1305                         }
1306                     }
1307                 #endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
1308 
1309                 if( xIsCallingFromIPTask() != pdFALSE )
1310                 {
1311                     iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
1312 
1313                     /* Only the IP-task is allowed to call this function directly. */
1314                     if( pxEndPoint->pxNetworkInterface != NULL )
1315                     {
1316                         ( void ) pxEndPoint->pxNetworkInterface->pfOutput( pxEndPoint->pxNetworkInterface, pxNetworkBuffer, pdTRUE );
1317                     }
1318                 }
1319                 else
1320                 {
1321                     IPStackEvent_t xSendEvent;
1322 
1323                     /* Send a message to the IP-task to send this ARP packet. */
1324                     xSendEvent.eEventType = eNetworkTxEvent;
1325                     xSendEvent.pvData = pxNetworkBuffer;
1326 
1327                     if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
1328                     {
1329                         /* Failed to send the message, so release the network buffer. */
1330                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1331                     }
1332                 }
1333             }
1334         }
1335     }
1336 }
1337 /*-----------------------------------------------------------*/
1338 #if ( ipconfigUSE_IPv4 != 0 )
1339 
1340 /**
1341  * @brief  Wait for address resolution: look-up the IP-address in the ARP-cache, and if
1342  *         needed send an ARP request, and wait for a reply.  This function is useful when
1343  *         called before FreeRTOS_sendto().
1344  *
1345  * @param[in] ulIPAddress The IP-address to look-up.
1346  * @param[in] uxTicksToWait The maximum number of clock ticks to wait for a reply.
1347  *
1348  * @return Zero when successful.
1349  */
xARPWaitResolution(uint32_t ulIPAddress,TickType_t uxTicksToWait)1350     BaseType_t xARPWaitResolution( uint32_t ulIPAddress,
1351                                    TickType_t uxTicksToWait )
1352     {
1353         BaseType_t xResult = -pdFREERTOS_ERRNO_EADDRNOTAVAIL;
1354         TimeOut_t xTimeOut;
1355         MACAddress_t xMACAddress;
1356         eARPLookupResult_t xLookupResult;
1357         NetworkEndPoint_t * pxEndPoint;
1358         size_t uxSendCount = ipconfigMAX_ARP_RETRANSMISSIONS;
1359         uint32_t ulIPAddressCopy = ulIPAddress;
1360 
1361         /* The IP-task is not supposed to call this function. */
1362         configASSERT( xIsCallingFromIPTask() == pdFALSE );
1363 
1364         xLookupResult = eARPGetCacheEntry( &( ulIPAddressCopy ), &( xMACAddress ), &( pxEndPoint ) );
1365 
1366         if( xLookupResult == eARPCacheMiss )
1367         {
1368             const TickType_t uxSleepTime = pdMS_TO_TICKS( 250U );
1369 
1370             /* We might use ipconfigMAX_ARP_RETRANSMISSIONS here. */
1371             vTaskSetTimeOutState( &xTimeOut );
1372 
1373             while( uxSendCount > 0U )
1374             {
1375                 FreeRTOS_OutputARPRequest( ulIPAddressCopy );
1376 
1377                 vTaskDelay( uxSleepTime );
1378 
1379                 xLookupResult = eARPGetCacheEntry( &( ulIPAddressCopy ), &( xMACAddress ), &( pxEndPoint ) );
1380 
1381                 if( ( xTaskCheckForTimeOut( &( xTimeOut ), &( uxTicksToWait ) ) == pdTRUE ) ||
1382                     ( xLookupResult != eARPCacheMiss ) )
1383                 {
1384                     break;
1385                 }
1386 
1387                 /* Decrement the count. */
1388                 uxSendCount--;
1389             }
1390         }
1391 
1392         if( xLookupResult == eARPCacheHit )
1393         {
1394             xResult = 0;
1395         }
1396 
1397         return xResult;
1398     }
1399 /*-----------------------------------------------------------*/
1400 
1401 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1402 
1403 /**
1404  * @brief Generate an ARP request packet by copying various constant details to
1405  *        the buffer.
1406  *
1407  * @param[in,out] pxNetworkBuffer Pointer to the buffer which has to be filled with
1408  *                             the ARP request packet details.
1409  */
vARPGenerateRequestPacket(NetworkBufferDescriptor_t * const pxNetworkBuffer)1410 void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
1411 {
1412 /* Part of the Ethernet and ARP headers are always constant when sending an IPv4
1413  * ARP packet.  This array defines the constant parts, allowing this part of the
1414  * packet to be filled in using a simple memcpy() instead of individual writes. */
1415     static const uint8_t xDefaultPartARPPacketHeader[] =
1416     {
1417         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
1418         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
1419         0x08, 0x06,                         /* Ethernet frame type (ipARP_FRAME_TYPE). */
1420         0x00, 0x01,                         /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
1421         0x08, 0x00,                         /* usProtocolType. */
1422         ipMAC_ADDRESS_LENGTH_BYTES,         /* ucHardwareAddressLength. */
1423         ipIP_ADDRESS_LENGTH_BYTES,          /* ucProtocolAddressLength. */
1424         0x00, 0x01,                         /* usOperation (ipARP_REQUEST). */
1425         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
1426         0x00, 0x00, 0x00, 0x00,             /* ulSenderProtocolAddress. */
1427         0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* xTargetHardwareAddress. */
1428     };
1429 
1430     ARPPacket_t * pxARPPacket;
1431 
1432 /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
1433     const void * pvCopySource;
1434     void * pvCopyDest;
1435 
1436     /* Buffer allocation ensures that buffers always have space
1437      * for an ARP packet. See buffer allocation implementations 1
1438      * and 2 under portable/BufferManagement. */
1439     configASSERT( pxNetworkBuffer != NULL );
1440     configASSERT( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) );
1441     configASSERT( pxNetworkBuffer->pxEndPoint != NULL );
1442 
1443     /* MISRA Ref 11.3.1 [Misaligned access] */
1444 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1445     /* coverity[misra_c_2012_rule_11_3_violation] */
1446     pxARPPacket = ( ( ARPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
1447 
1448     /* memcpy the const part of the header information into the correct
1449      * location in the packet.  This copies:
1450      *  xEthernetHeader.ulDestinationAddress
1451      *  xEthernetHeader.usFrameType;
1452      *  xARPHeader.usHardwareType;
1453      *  xARPHeader.usProtocolType;
1454      *  xARPHeader.ucHardwareAddressLength;
1455      *  xARPHeader.ucProtocolAddressLength;
1456      *  xARPHeader.usOperation;
1457      *  xARPHeader.xTargetHardwareAddress;
1458      */
1459 
1460     /*
1461      * Use helper variables for memcpy() to remain
1462      * compliant with MISRA Rule 21.15.  These should be
1463      * optimized away.
1464      */
1465     pvCopySource = xDefaultPartARPPacketHeader;
1466     pvCopyDest = pxARPPacket;
1467     ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartARPPacketHeader ) );
1468 
1469     pvCopySource = pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes;
1470     pvCopyDest = pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes;
1471     ( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
1472 
1473     pvCopySource = pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes;
1474     pvCopyDest = pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes;
1475     ( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
1476 
1477     pvCopySource = &( pxNetworkBuffer->pxEndPoint->ipv4_settings.ulIPAddress );
1478     pvCopyDest = pxARPPacket->xARPHeader.ucSenderProtocolAddress;
1479     ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
1480     pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->xIPAddress.ulIP_IPv4;
1481 
1482     pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
1483 
1484     iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->xIPAddress.ulIP_IPv4 );
1485 }
1486 /*-----------------------------------------------------------*/
1487 
1488 /**
1489  * @brief A call to this function will clear the ARP cache.
1490  * @param[in] pxEndPoint only clean entries with this end-point, or when NULL,
1491  *                        clear the entire ARP cache.
1492  */
FreeRTOS_ClearARP(const struct xNetworkEndPoint * pxEndPoint)1493 void FreeRTOS_ClearARP( const struct xNetworkEndPoint * pxEndPoint )
1494 {
1495     if( pxEndPoint != NULL )
1496     {
1497         BaseType_t x;
1498 
1499         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
1500         {
1501             if( xARPCache[ x ].pxEndPoint == pxEndPoint )
1502             {
1503                 ( void ) memset( &( xARPCache[ x ] ), 0, sizeof( ARPCacheRow_t ) );
1504             }
1505         }
1506     }
1507     else
1508     {
1509         ( void ) memset( xARPCache, 0, sizeof( xARPCache ) );
1510     }
1511 }
1512 /*-----------------------------------------------------------*/
1513 
1514 #if 1
1515 
1516 /**
1517  * @brief  This function will check if the target IP-address belongs to this device.
1518  *         If so, the packet will be passed to the IP-stack, who will answer it.
1519  *         The function is to be called within the function xNetworkInterfaceOutput().
1520  *
1521  * @param[in] pxDescriptor The network buffer which is to be checked for loop-back.
1522  * @param[in] bReleaseAfterSend pdTRUE: Driver is allowed to transfer ownership of descriptor.
1523  *                              pdFALSE: Driver is not allowed to take ownership of descriptor,
1524  *                                       make a copy of it.
1525  *
1526  * @return pdTRUE/pdFALSE: There is/isn't a loopback address in the packet.
1527  */
xCheckLoopback(NetworkBufferDescriptor_t * const pxDescriptor,BaseType_t bReleaseAfterSend)1528     BaseType_t xCheckLoopback( NetworkBufferDescriptor_t * const pxDescriptor,
1529                                BaseType_t bReleaseAfterSend )
1530     {
1531         BaseType_t xResult = pdFALSE;
1532         NetworkBufferDescriptor_t * pxUseDescriptor = pxDescriptor;
1533 
1534         const IPPacket_t * pxIPPacket;
1535 
1536         if( ( pxUseDescriptor == NULL ) || ( pxUseDescriptor->xDataLength < sizeof( IPPacket_t ) ) )
1537         {
1538             /* The packet is too small to parse. */
1539         }
1540         else
1541         {
1542             /* MISRA Ref 11.3.1 [Misaligned access] */
1543             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1544             /* coverity[misra_c_2012_rule_11_3_violation] */
1545             pxIPPacket = ( ( IPPacket_t * ) pxUseDescriptor->pucEthernetBuffer );
1546 
1547             if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
1548             {
1549                 NetworkEndPoint_t * pxEndPoint;
1550 
1551                 pxEndPoint = FreeRTOS_FindEndPointOnMAC( &( pxIPPacket->xEthernetHeader.xDestinationAddress ), NULL );
1552 
1553                 if( ( pxEndPoint != NULL ) &&
1554                     ( memcmp( pxIPPacket->xEthernetHeader.xDestinationAddress.ucBytes, pxEndPoint->xMACAddress.ucBytes, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 ) )
1555                 {
1556                     xResult = pdTRUE;
1557 
1558                     if( bReleaseAfterSend == pdFALSE )
1559                     {
1560                         /* Driver is not allowed to transfer the ownership
1561                          * of descriptor,  so make a copy of it */
1562                         pxUseDescriptor =
1563                             pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, pxDescriptor->xDataLength );
1564                     }
1565 
1566                     if( pxUseDescriptor != NULL )
1567                     {
1568                         IPStackEvent_t xRxEvent;
1569 
1570                         pxUseDescriptor->pxInterface = pxEndPoint->pxNetworkInterface;
1571                         pxUseDescriptor->pxEndPoint = pxEndPoint;
1572 
1573                         xRxEvent.eEventType = eNetworkRxEvent;
1574                         xRxEvent.pvData = pxUseDescriptor;
1575 
1576                         if( xSendEventStructToIPTask( &xRxEvent, 0U ) != pdTRUE )
1577                         {
1578                             vReleaseNetworkBufferAndDescriptor( pxUseDescriptor );
1579                             iptraceETHERNET_RX_EVENT_LOST();
1580                             FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
1581                         }
1582                     }
1583                 }
1584             }
1585         }
1586 
1587         return xResult;
1588     }
1589 
1590 #endif /* 0 */
1591 /*-----------------------------------------------------------*/
1592 
1593 #if ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
1594 
FreeRTOS_PrintARPCache(void)1595     void FreeRTOS_PrintARPCache( void )
1596     {
1597         BaseType_t x, xCount = 0;
1598 
1599         /* Loop through each entry in the ARP cache. */
1600         for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
1601         {
1602             if( ( xARPCache[ x ].ulIPAddress != 0U ) && ( xARPCache[ x ].ucAge > ( uint8_t ) 0U ) )
1603             {
1604                 /* See if the MAC-address also matches, and we're all happy */
1605                 FreeRTOS_printf( ( "ARP %2d: %3u - %16xip : %02x:%02x:%02x : %02x:%02x:%02x\n",
1606                                    ( int ) x,
1607                                    xARPCache[ x ].ucAge,
1608                                    ( unsigned ) FreeRTOS_ntohl( xARPCache[ x ].ulIPAddress ),
1609                                    xARPCache[ x ].xMACAddress.ucBytes[ 0 ],
1610                                    xARPCache[ x ].xMACAddress.ucBytes[ 1 ],
1611                                    xARPCache[ x ].xMACAddress.ucBytes[ 2 ],
1612                                    xARPCache[ x ].xMACAddress.ucBytes[ 3 ],
1613                                    xARPCache[ x ].xMACAddress.ucBytes[ 4 ],
1614                                    xARPCache[ x ].xMACAddress.ucBytes[ 5 ] ) );
1615                 xCount++;
1616             }
1617         }
1618 
1619         FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
1620     }
1621 #endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */
1622