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