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