xref: /FreeRTOS-Plus-TCP-v3.1.0/source/FreeRTOS_IP_Utils.c (revision 37bdfe577f3b728058de714e2e747d3c78803f26)
1 /*
2  * FreeRTOS+TCP V3.1.0
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_IP_Utils.c
30  * @brief Implements the basic functionality for the FreeRTOS+TCP network stack.
31  */
32 
33 /* Standard includes. */
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "queue.h"
42 #include "semphr.h"
43 
44 /* FreeRTOS+TCP includes. */
45 #include "FreeRTOS_IP.h"
46 #include "FreeRTOS_IP_Utils.h"
47 #include "FreeRTOS_IP_Timers.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_ARP.h"
51 #include "FreeRTOS_UDP_IP.h"
52 #include "FreeRTOS_DHCP.h"
53 #include "NetworkInterface.h"
54 #include "NetworkBufferManagement.h"
55 #include "FreeRTOS_DNS.h"
56 
57 /* Used to ensure the structure packing is having the desired effect.  The
58  * 'volatile' is used to prevent compiler warnings about comparing a constant with
59  * a constant. */
60 #ifndef _lint
61     #define ipEXPECTED_EthernetHeader_t_SIZE    ( ( size_t ) 14 ) /**< Ethernet Header size in bytes. */
62     #define ipEXPECTED_ARPHeader_t_SIZE         ( ( size_t ) 28 ) /**< ARP header size in bytes. */
63     #define ipEXPECTED_IPHeader_t_SIZE          ( ( size_t ) 20 ) /**< IP header size in bytes. */
64     #define ipEXPECTED_IGMPHeader_t_SIZE        ( ( size_t ) 8 )  /**< IGMP header size in bytes. */
65     #define ipEXPECTED_ICMPHeader_t_SIZE        ( ( size_t ) 8 )  /**< ICMP header size in bytes. */
66     #define ipEXPECTED_UDPHeader_t_SIZE         ( ( size_t ) 8 )  /**< UDP header size in bytes. */
67     #define ipEXPECTED_TCPHeader_t_SIZE         ( ( size_t ) 20 ) /**< TCP header size in bytes. */
68 #endif
69 
70 /** @brief Time delay between repeated attempts to initialise the network hardware. */
71 #ifndef ipINITIALISATION_RETRY_DELAY
72     #define ipINITIALISATION_RETRY_DELAY    ( pdMS_TO_TICKS( 3000U ) )
73 #endif
74 
75 #if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
76     /* used for unit testing */
77 
78 /* MISRA Ref 8.9.1 [File scoped variables] */
79 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
80 /* coverity[misra_c_2012_rule_8_9_violation] */
81 /* coverity[single_use] */
82     static BaseType_t xCallEventHook = pdFALSE;
83 #endif
84 
85 #if ( ipconfigHAS_PRINTF != 0 )
86     /** @brief Last value of minimum buffer count. */
87     static UBaseType_t uxLastMinBufferCount = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
88 
89 /** @brief Last value of minimum size. Used in printing resource stats. */
90     static size_t uxMinLastSize = 0u;
91 #endif
92 
93 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) && ( ipconfigHAS_PRINTF != 0 )
94     static UBaseType_t uxLastMinQueueSpace = 0;
95 #endif
96 
97 /**
98  * Used in checksum calculation.
99  */
100 typedef union _xUnion32
101 {
102     uint32_t u32;      /**< The 32-bit member of the union. */
103     uint16_t u16[ 2 ]; /**< The array of 2 16-bit members of the union. */
104     uint8_t u8[ 4 ];   /**< The array of 4 8-bit members of the union. */
105 } xUnion32;
106 
107 /**
108  * Used in checksum calculation.
109  */
110 typedef union _xUnionPtr
111 {
112     const uint32_t * u32ptr; /**< The pointer member to a 32-bit variable. */
113     const uint16_t * u16ptr; /**< The pointer member to a 16-bit variable. */
114     const uint8_t * u8ptr;   /**< The pointer member to an 8-bit variable. */
115 } xUnionPtr;
116 
117 /*
118  * Returns the network buffer descriptor that owns a given packet buffer.
119  */
120 static NetworkBufferDescriptor_t * prvPacketBuffer_to_NetworkBuffer( const void * pvBuffer,
121                                                                      size_t uxOffset );
122 
123 #if ( ipconfigUSE_DHCP != 0 )
124 
125 /**
126  * @brief Create a DHCP event.
127  *
128  * @return pdPASS or pdFAIL, depending on whether xSendEventStructToIPTask()
129  *         succeeded.
130  */
xSendDHCPEvent(void)131     BaseType_t xSendDHCPEvent( void )
132     {
133         IPStackEvent_t xEventMessage;
134         const TickType_t uxDontBlock = 0U;
135         uintptr_t uxOption = ( uintptr_t ) eGetDHCPState();
136 
137         xEventMessage.eEventType = eDHCPEvent;
138 
139         /* MISRA Ref 11.6.1 [DHCP events and conversion to void] */
140         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-116 */
141         /* coverity[misra_c_2012_rule_11_6_violation] */
142         xEventMessage.pvData = ( void * ) uxOption;
143 
144         return xSendEventStructToIPTask( &xEventMessage, uxDontBlock );
145     }
146 /*-----------------------------------------------------------*/
147 #endif /* ( ipconfigUSE_DHCP != 0 ) */
148 
149 /**
150  * @brief Set multicast MAC address.
151  *
152  * @param[in] ulIPAddress: IP address.
153  * @param[out] pxMACAddress: Pointer to MAC address.
154  */
vSetMultiCastIPv4MacAddress(uint32_t ulIPAddress,MACAddress_t * pxMACAddress)155 void vSetMultiCastIPv4MacAddress( uint32_t ulIPAddress,
156                                   MACAddress_t * pxMACAddress )
157 {
158     uint32_t ulIP = FreeRTOS_ntohl( ulIPAddress );
159 
160     pxMACAddress->ucBytes[ 0 ] = ( uint8_t ) 0x01U;
161     pxMACAddress->ucBytes[ 1 ] = ( uint8_t ) 0x00U;
162     pxMACAddress->ucBytes[ 2 ] = ( uint8_t ) 0x5EU;
163     pxMACAddress->ucBytes[ 3 ] = ( uint8_t ) ( ( ulIP >> 16 ) & 0x7fU ); /* Use 7 bits. */
164     pxMACAddress->ucBytes[ 4 ] = ( uint8_t ) ( ( ulIP >> 8 ) & 0xffU );  /* Use 8 bits. */
165     pxMACAddress->ucBytes[ 5 ] = ( uint8_t ) ( ( ulIP ) & 0xffU );       /* Use 8 bits. */
166 }
167 /*-----------------------------------------------------------*/
168 
169 
170 /**
171  * @brief Duplicate the given network buffer descriptor with a modified length.
172  *
173  * @param[in] pxNetworkBuffer: The network buffer to be duplicated.
174  * @param[in] uxNewLength: The length for the new buffer.
175  *
176  * @return If properly duplicated, then the duplicate network buffer or else, NULL.
177  */
pxDuplicateNetworkBufferWithDescriptor(const NetworkBufferDescriptor_t * const pxNetworkBuffer,size_t uxNewLength)178 NetworkBufferDescriptor_t * pxDuplicateNetworkBufferWithDescriptor( const NetworkBufferDescriptor_t * const pxNetworkBuffer,
179                                                                     size_t uxNewLength )
180 {
181     NetworkBufferDescriptor_t * pxNewBuffer;
182     size_t uxLengthToCopy = uxNewLength;
183 
184     /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.
185      * The transmit routine wants to have ownership of the network buffer
186      * descriptor, because it will pass the buffer straight to DMA. */
187     pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );
188 
189     if( pxNewBuffer != NULL )
190     {
191         /* Get the minimum of both values to copy the data. */
192         if( uxLengthToCopy > pxNetworkBuffer->xDataLength )
193         {
194             uxLengthToCopy = pxNetworkBuffer->xDataLength;
195         }
196 
197         /* Set the actual packet size in case a bigger buffer than requested
198          * was returned. */
199         pxNewBuffer->xDataLength = uxNewLength;
200 
201         /* Copy the original packet information. */
202         pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;
203         pxNewBuffer->usPort = pxNetworkBuffer->usPort;
204         pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;
205         ( void ) memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, uxLengthToCopy );
206     }
207 
208     return pxNewBuffer;
209 }
210 /*-----------------------------------------------------------*/
211 
212 /**
213  * @brief Get the network buffer descriptor from the packet buffer.
214  *
215  * @param[in] pvBuffer: The pointer to packet buffer.
216  * @param[in] uxOffset: Additional offset (such as the packet length of UDP packet etc.).
217  *
218  * @return The network buffer descriptor if the alignment is correct. Else a NULL is returned.
219  */
prvPacketBuffer_to_NetworkBuffer(const void * pvBuffer,size_t uxOffset)220 static NetworkBufferDescriptor_t * prvPacketBuffer_to_NetworkBuffer( const void * pvBuffer,
221                                                                      size_t uxOffset )
222 {
223     uintptr_t uxBuffer;
224     NetworkBufferDescriptor_t * pxResult;
225 
226     if( pvBuffer == NULL )
227     {
228         pxResult = NULL;
229     }
230     else
231     {
232         /* Obtain the network buffer from the zero copy pointer. */
233 
234         /* MISRA Ref 11.6.2 [Pointer arithmetic and hidden pointer] */
235         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-116 */
236         /* coverity[misra_c_2012_rule_11_6_violation] */
237         uxBuffer = ( uintptr_t ) pvBuffer;
238 
239         /* The input here is a pointer to a packet buffer plus some offset.  Subtract
240          * this offset, and also the size of the header in the network buffer, usually
241          * 8 + 2 bytes. */
242         uxBuffer -= ( uxOffset + ipBUFFER_PADDING );
243 
244         /* Here a pointer was placed to the network descriptor.  As a
245          * pointer is dereferenced, make sure it is well aligned. */
246         if( ( uxBuffer & ( ( ( uintptr_t ) sizeof( uxBuffer ) ) - 1U ) ) == ( uintptr_t ) 0U )
247         {
248             /* MISRA Ref 11.4.2 [Validation of pointer alignment] */
249             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
250             /* coverity[misra_c_2012_rule_11_4_violation] */
251             pxResult = *( ( NetworkBufferDescriptor_t ** ) uxBuffer );
252         }
253         else
254         {
255             pxResult = NULL;
256         }
257     }
258 
259     return pxResult;
260 }
261 /*-----------------------------------------------------------*/
262 
263 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
264 
265 /**
266  * @brief Get the network buffer from the packet buffer.
267  *
268  * @param[in] pvBuffer: Pointer to the packet buffer.
269  *
270  * @return The network buffer if the alignment is correct. Else a NULL is returned.
271  */
pxPacketBuffer_to_NetworkBuffer(const void * pvBuffer)272     NetworkBufferDescriptor_t * pxPacketBuffer_to_NetworkBuffer( const void * pvBuffer )
273     {
274         return prvPacketBuffer_to_NetworkBuffer( pvBuffer, 0U );
275     }
276 
277 #endif /* ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
278 /*-----------------------------------------------------------*/
279 
280 /**
281  * @brief Get the network buffer from the UDP Payload buffer.
282  *
283  * @param[in] pvBuffer: Pointer to the UDP payload buffer.
284  *
285  * @return The network buffer if the alignment is correct. Else a NULL is returned.
286  */
pxUDPPayloadBuffer_to_NetworkBuffer(const void * pvBuffer)287 NetworkBufferDescriptor_t * pxUDPPayloadBuffer_to_NetworkBuffer( const void * pvBuffer )
288 {
289     return prvPacketBuffer_to_NetworkBuffer( pvBuffer, sizeof( UDPPacket_t ) );
290 }
291 /*-----------------------------------------------------------*/
292 
293 /**
294  * @brief Function to check whether the current context belongs to
295  *        the IP-task.
296  *
297  * @return If the current context belongs to the IP-task, then pdTRUE is
298  *         returned. Else pdFALSE is returned.
299  *
300  * @note Very important: the IP-task is not allowed to call its own API's,
301  *        because it would easily get into a dead-lock.
302  */
xIsCallingFromIPTask(void)303 BaseType_t xIsCallingFromIPTask( void )
304 {
305     BaseType_t xReturn;
306     const struct tskTaskControlBlock * const xCurrentHandle = xTaskGetCurrentTaskHandle();
307     const struct tskTaskControlBlock * const xCurrentIPTaskHandle = FreeRTOS_GetIPTaskHandle();
308 
309     if( xCurrentHandle == xCurrentIPTaskHandle )
310     {
311         xReturn = pdTRUE;
312     }
313     else
314     {
315         xReturn = pdFALSE;
316     }
317 
318     return xReturn;
319 }
320 /*-----------------------------------------------------------*/
321 
322 /**
323  * @brief Process a 'Network down' event and complete required processing.
324  */
325 /* MISRA Ref 8.9.1 [File scoped variables] */
326 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
327 /* coverity[misra_c_2012_rule_8_9_violation] */
328 /* coverity[single_use] */
prvProcessNetworkDownEvent(void)329 void prvProcessNetworkDownEvent( void )
330 {
331     /* Stop the ARP timer while there is no network. */
332     vIPSetARPTimerEnableState( pdFALSE );
333 
334     #if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
335         {
336             /* The first network down event is generated by the IP stack itself to
337              * initialise the network hardware, so do not call the network down event
338              * the first time through. */
339             if( xCallEventHook == pdTRUE )
340             {
341                 vApplicationIPNetworkEventHook( eNetworkDown );
342             }
343 
344             xCallEventHook = pdTRUE;
345         }
346     #endif /* if ipconfigUSE_NETWORK_EVENT_HOOK == 1 */
347 
348     /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122,
349      * treat network down as a "delivery problem" and flush the ARP cache for this
350      * interface. */
351     FreeRTOS_ClearARP();
352 
353     /* The network has been disconnected (or is being initialised for the first
354      * time).  Perform whatever hardware processing is necessary to bring it up
355      * again, or wait for it to be available again.  This is hardware dependent. */
356     if( xNetworkInterfaceInitialise() != pdPASS )
357     {
358         /* Ideally the network interface initialisation function will only
359          * return when the network is available.  In case this is not the case,
360          * wait a while before retrying the initialisation. */
361         vTaskDelay( ipINITIALISATION_RETRY_DELAY );
362         FreeRTOS_NetworkDown();
363     }
364     else
365     {
366         /* Set remaining time to 0 so it will become active immediately. */
367         #if ipconfigUSE_DHCP == 1
368             {
369                 /* The network is not up until DHCP has completed. */
370                 vDHCPProcess( pdTRUE, eInitialWait );
371             }
372         #else
373             {
374                 /* Perform any necessary 'network up' processing. */
375                 vIPNetworkUpCalls();
376             }
377         #endif
378     }
379 }
380 /*-----------------------------------------------------------*/
381 
382 /**
383  * @brief Check the values of configuration options and assert on it. Also verify that the IP-task
384  *        has not already been initialized.
385  */
vPreCheckConfigs(void)386 void vPreCheckConfigs( void )
387 {
388     /* This function should only be called once. */
389     configASSERT( xIPIsNetworkTaskReady() == pdFALSE );
390     configASSERT( xNetworkEventQueue == NULL );
391     configASSERT( FreeRTOS_GetIPTaskHandle() == NULL );
392 
393     #if ( configASSERT_DEFINED == 1 )
394         {
395             volatile size_t uxSize = sizeof( uintptr_t );
396 
397             if( uxSize == 8U )
398             {
399                 /* This is a 64-bit platform, make sure there is enough space in
400                  * pucEthernetBuffer to store a pointer. */
401                 configASSERT( ipconfigBUFFER_PADDING >= 14 );
402                 /* But it must have this strange alignment: */
403                 configASSERT( ( ( ( ipconfigBUFFER_PADDING ) + 2 ) % 4 ) == 0 );
404             }
405 
406             /* LCOV_EXCL_BR_START */
407             uxSize = ipconfigNETWORK_MTU;
408             /* Check if MTU is big enough. */
409             configASSERT( uxSize >= ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + ipconfigTCP_MSS ) );
410 
411             uxSize = sizeof( EthernetHeader_t );
412             /* Check structure packing is correct. */
413             configASSERT( uxSize == ipEXPECTED_EthernetHeader_t_SIZE );
414 
415             uxSize = sizeof( ARPHeader_t );
416             configASSERT( uxSize == ipEXPECTED_ARPHeader_t_SIZE );
417 
418             uxSize = sizeof( IPHeader_t );
419             configASSERT( uxSize == ipEXPECTED_IPHeader_t_SIZE );
420 
421             uxSize = sizeof( ICMPHeader_t );
422             configASSERT( uxSize == ipEXPECTED_ICMPHeader_t_SIZE );
423 
424             uxSize = sizeof( UDPHeader_t );
425             configASSERT( uxSize == ipEXPECTED_UDPHeader_t_SIZE );
426             /* LCOV_EXCL_BR_STOP */
427         }
428     #endif /* if ( configASSERT_DEFINED == 1 ) */
429 }
430 
431 /**
432  * @brief Generate or check the protocol checksum of the data sent in the first parameter.
433  *        At the same time, the length of the packet and the length of the different layers
434  *        will be checked.
435  *
436  * @param[in] pucEthernetBuffer: The Ethernet buffer for which the checksum is to be calculated
437  *                               or checked.
438  * @param[in] uxBufferLength: the total number of bytes received, or the number of bytes written
439  *                            in the packet buffer.
440  * @param[in] xOutgoingPacket: Whether this is an outgoing packet or not.
441  *
442  * @return When xOutgoingPacket is false: the error code can be either: ipINVALID_LENGTH,
443  *         ipUNHANDLED_PROTOCOL, ipWRONG_CRC, or ipCORRECT_CRC.
444  *         When xOutgoingPacket is true: either ipINVALID_LENGTH, ipUNHANDLED_PROTOCOL,
445  *         or ipCORRECT_CRC.
446  */
usGenerateProtocolChecksum(uint8_t * pucEthernetBuffer,size_t uxBufferLength,BaseType_t xOutgoingPacket)447 uint16_t usGenerateProtocolChecksum( uint8_t * pucEthernetBuffer,
448                                      size_t uxBufferLength,
449                                      BaseType_t xOutgoingPacket )
450 {
451     uint32_t ulLength;
452     uint16_t usChecksum;           /* The checksum as calculated. */
453     uint16_t usChecksumFound = 0U; /* The checksum as found in the incoming packet. */
454     const IPPacket_t * pxIPPacket;
455     UBaseType_t uxIPHeaderLength;
456     ProtocolPacket_t * pxProtPack;
457     uint8_t ucProtocol;
458 
459     #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
460         const char * pcType;
461     #endif
462     uint16_t usLength;
463     uint16_t ucVersionHeaderLength;
464     DEBUG_DECLARE_TRACE_VARIABLE( BaseType_t, xLocation, 0 );
465 
466     /* Introduce a do-while loop to allow use of break statements.
467      * Note: MISRA prohibits use of 'goto', thus replaced with breaks. */
468     do
469     {
470         /* Check for minimum packet size. */
471         if( uxBufferLength < sizeof( IPPacket_t ) )
472         {
473             usChecksum = ipINVALID_LENGTH;
474             DEBUG_SET_TRACE_VARIABLE( xLocation, 1 );
475             break;
476         }
477 
478         /* Parse the packet length. */
479 
480         /* MISRA Ref 11.3.1 [Misaligned access] */
481         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
482         /* coverity[misra_c_2012_rule_11_3_violation] */
483         pxIPPacket = ( ( const IPPacket_t * ) pucEthernetBuffer );
484 
485         /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header
486          * Length field contains the length of the internet header in 32-bit words. */
487         ucVersionHeaderLength = pxIPPacket->xIPHeader.ucVersionHeaderLength;
488         ucVersionHeaderLength = ( ucVersionHeaderLength & ( uint8_t ) 0x0FU ) << 2;
489         uxIPHeaderLength = ( UBaseType_t ) ucVersionHeaderLength;
490 
491         /* Check for minimum packet size. */
492         if( uxBufferLength < ( sizeof( IPPacket_t ) + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) ) )
493         {
494             usChecksum = ipINVALID_LENGTH;
495             DEBUG_SET_TRACE_VARIABLE( xLocation, 2 );
496             break;
497         }
498 
499         usLength = pxIPPacket->xIPHeader.usLength;
500         usLength = FreeRTOS_ntohs( usLength );
501 
502         if( usLength < uxIPHeaderLength )
503         {
504             usChecksum = ipINVALID_LENGTH;
505             DEBUG_SET_TRACE_VARIABLE( xLocation, 3 );
506             break;
507         }
508 
509         if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + ( size_t ) usLength ) )
510         {
511             usChecksum = ipINVALID_LENGTH;
512             DEBUG_SET_TRACE_VARIABLE( xLocation, 4 );
513             break;
514         }
515 
516         /* Identify the next protocol. */
517         ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
518 
519         /* N.B., if this IP packet header includes Options, then the following
520          * assignment results in a pointer into the protocol packet with the Ethernet
521          * and IP headers incorrectly aligned. However, either way, the "third"
522          * protocol (Layer 3 or 4) header will be aligned, which is the convenience
523          * of this calculation. */
524 
525         /* MISRA Ref 11.3.1 [Misaligned access] */
526         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
527         /* coverity[misra_c_2012_rule_11_3_violation] */
528         pxProtPack = ( ( ProtocolPacket_t * ) &( pucEthernetBuffer[ uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ] ) );
529 
530         /* Switch on the Layer 3/4 protocol. */
531         if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
532         {
533             if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) )
534             {
535                 usChecksum = ipINVALID_LENGTH;
536                 DEBUG_SET_TRACE_VARIABLE( xLocation, 5 );
537                 break;
538             }
539 
540             if( xOutgoingPacket != pdFALSE )
541             {
542                 /* Clear the UDP checksum field before calculating it. */
543                 pxProtPack->xUDPPacket.xUDPHeader.usChecksum = 0U;
544             }
545             else
546             {
547                 usChecksumFound = pxProtPack->xUDPPacket.xUDPHeader.usChecksum;
548             }
549 
550             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
551                 {
552                     pcType = "UDP";
553                 }
554             #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
555         }
556         else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
557         {
558             if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) )
559             {
560                 usChecksum = ipINVALID_LENGTH;
561                 DEBUG_SET_TRACE_VARIABLE( xLocation, 6 );
562                 break;
563             }
564 
565             if( xOutgoingPacket != pdFALSE )
566             {
567                 /* Clear the TCP checksum field before calculating it. */
568                 pxProtPack->xTCPPacket.xTCPHeader.usChecksum = 0U;
569             }
570             else
571             {
572                 usChecksumFound = pxProtPack->xTCPPacket.xTCPHeader.usChecksum;
573             }
574 
575             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
576                 {
577                     pcType = "TCP";
578                 }
579             #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
580         }
581         else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
582                  ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
583         {
584             if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) )
585             {
586                 usChecksum = ipINVALID_LENGTH;
587                 DEBUG_SET_TRACE_VARIABLE( xLocation, 7 );
588                 break;
589             }
590 
591             if( xOutgoingPacket != pdFALSE )
592             {
593                 /* Clear the ICMP/IGMP checksum field before calculating it. */
594                 pxProtPack->xICMPPacket.xICMPHeader.usChecksum = 0U;
595             }
596             else
597             {
598                 usChecksumFound = pxProtPack->xICMPPacket.xICMPHeader.usChecksum;
599             }
600 
601             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
602                 {
603                     if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
604                     {
605                         pcType = "ICMP";
606                     }
607                     else
608                     {
609                         pcType = "IGMP";
610                     }
611                 }
612             #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
613         }
614         else
615         {
616             /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
617             usChecksum = ipUNHANDLED_PROTOCOL;
618             DEBUG_SET_TRACE_VARIABLE( xLocation, 8 );
619             break;
620         }
621 
622         /* The protocol and checksum field have been identified. Check the direction
623          * of the packet. */
624         if( xOutgoingPacket != pdFALSE )
625         {
626             /* This is an outgoing packet. The CRC-field has been cleared. */
627         }
628         else if( ( usChecksumFound == 0U ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
629         {
630             #if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 )
631                 {
632                     /* Sender hasn't set the checksum, drop the packet because
633                      * ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS is not set. */
634                     usChecksum = ipWRONG_CRC;
635                     #if ( ipconfigHAS_PRINTF != 0 )
636                         {
637                             static BaseType_t xCount = 0;
638 
639                             /* Exclude this from branch coverage as this is only used for debugging. */
640                             if( xCount < 5 ) /* LCOV_EXCL_BR_LINE */
641                             {
642                                 FreeRTOS_printf( ( "usGenerateProtocolChecksum: UDP packet from %xip without CRC dropped\n",
643                                                    FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ) ) );
644                                 xCount++;
645                             }
646                         }
647                     #endif /* ( ipconfigHAS_PRINTF != 0 ) */
648                 }
649             #else /* if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
650                 {
651                     /* Sender hasn't set the checksum, no use to calculate it. */
652                     usChecksum = ipCORRECT_CRC;
653                 }
654             #endif /* if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
655             DEBUG_SET_TRACE_VARIABLE( xLocation, 9 );
656             break;
657         }
658         else
659         {
660             /* Other incoming packet than UDP. */
661         }
662 
663         usLength = pxIPPacket->xIPHeader.usLength;
664         usLength = FreeRTOS_ntohs( usLength );
665         ulLength = ( uint32_t ) usLength;
666         ulLength -= ( ( uint16_t ) uxIPHeaderLength ); /* normally minus 20 */
667 
668         if( ( ulLength < ( ( uint32_t ) sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ) ||
669             ( ulLength > ( ( uint32_t ) ipconfigNETWORK_MTU - ( uint32_t ) uxIPHeaderLength ) ) )
670         {
671             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
672                 {
673                     FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );
674                 }
675             #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
676 
677             /* Again, in a 16-bit return value there is no space to indicate an
678              * error.  For incoming packets, 0x1234 will cause dropping of the packet.
679              * For outgoing packets, there is a serious problem with the
680              * format/length */
681             usChecksum = ipINVALID_LENGTH;
682             DEBUG_SET_TRACE_VARIABLE( xLocation, 10 );
683             break;
684         }
685 
686         if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )
687         {
688             /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */
689             usChecksum = ( uint16_t )
690                          ( ~usGenerateChecksum( 0U,
691                                                 ( const uint8_t * ) &( pxProtPack->xICMPPacket.xICMPHeader ), ( size_t ) ulLength ) );
692         }
693         else
694         {
695             /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length
696              * fields */
697             usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );
698 
699             /* And then continue at the IPv4 source and destination addresses. */
700             usChecksum = ( uint16_t )
701                          ( ~usGenerateChecksum( usChecksum,
702                                                 ( const uint8_t * ) &( pxIPPacket->xIPHeader.ulSourceIPAddress ),
703                                                 ( size_t ) ( ( 2U * ( size_t ) ipSIZE_OF_IPv4_ADDRESS ) + ulLength ) ) );
704             /* Sum TCP header and data. */
705         }
706 
707         if( xOutgoingPacket == pdFALSE )
708         {
709             /* This is in incoming packet. If the CRC is correct, it should be zero. */
710             if( usChecksum == 0U )
711             {
712                 usChecksum = ( uint16_t ) ipCORRECT_CRC;
713             }
714             else
715             {
716                 usChecksum = ( uint16_t ) ipWRONG_CRC;
717             }
718         }
719         else
720         {
721             if( ( usChecksum == 0U ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
722             {
723                 /* In case of UDP, a calculated checksum of 0x0000 is transmitted
724                  * as 0xffff. A value of zero would mean that the checksum is not used. */
725                 usChecksum = ( uint16_t ) 0xffffu;
726             }
727         }
728 
729         usChecksum = FreeRTOS_htons( usChecksum );
730 
731         if( xOutgoingPacket != pdFALSE )
732         {
733             switch( ucProtocol )
734             {
735                 case ipPROTOCOL_UDP:
736                     pxProtPack->xUDPPacket.xUDPHeader.usChecksum = usChecksum;
737                     break;
738 
739                 case ipPROTOCOL_TCP:
740                     pxProtPack->xTCPPacket.xTCPHeader.usChecksum = usChecksum;
741                     break;
742 
743                 case ipPROTOCOL_ICMP:
744                     pxProtPack->xICMPPacket.xICMPHeader.usChecksum = usChecksum;
745                     break;
746 
747                 default: /*  ipPROTOCOL_IGMP */
748                     pxProtPack->xICMPPacket.xICMPHeader.usChecksum = usChecksum;
749                     break;
750             }
751 
752             usChecksum = ( uint16_t ) ipCORRECT_CRC;
753         }
754 
755         #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
756             else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )
757             {
758                 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",
759                                          pcType,
760                                          FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),
761                                          FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),
762                                          FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),
763                                          FreeRTOS_ntohs( usChecksumFound ) ) );
764             }
765             else
766             {
767                 /* Nothing. */
768             }
769         #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
770     } while( ipFALSE_BOOL );
771 
772     if( ( usChecksum == ipUNHANDLED_PROTOCOL ) ||
773         ( usChecksum == ipINVALID_LENGTH ) )
774     {
775         /* NOP if ipconfigHAS_PRINTF != 0 */
776         FreeRTOS_printf( ( "CRC error: %04x location %ld\n", usChecksum, xLocation ) );
777     }
778 
779     return usChecksum;
780 }
781 /*-----------------------------------------------------------*/
782 
783 /**
784  * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).
785  * The checksum algorithm is described as:
786  *   "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the
787  *   header.  For purposes of computing the checksum, the value of the checksum field is zero."
788  *
789  * In a nutshell, that means that each 16-bit 'word' must be summed, after which
790  * the number of 'carries' (overflows) is added to the result. If that addition
791  * produces an overflow, that 'carry' must also be added to the final result. The final checksum
792  * should be the bitwise 'not' (ones-complement) of the result if the packet is
793  * meant to be transmitted, but this method simply returns the raw value, probably
794  * because when a packet is received, the checksum is verified by checking that
795  * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.
796  *
797  * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.
798  * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit
799  * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,
800  * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.
801  * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.
802  * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found
803  * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue
804  * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:
805  *   union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];
806  *
807  * Arguments:
808  *   ulSum: This argument provides a value to initialise the progressive summation
809  *   of the header's values to. It is often 0, but protocols like TCP or UDP
810  *   can have pseudo-header fields which need to be included in the checksum.
811  *   pucNextData: This argument contains the address of the first byte which this
812  *   method should process. The method's memory iterator is initialised to this value.
813  *   uxDataLengthBytes: This argument contains the number of bytes that this method
814  *   should process.
815  */
816 
817 /**
818  * @brief Calculates the 16-bit checksum of an array of bytes
819  *
820  * @param[in] usSum: The initial sum, obtained from earlier data.
821  * @param[in] pucNextData: The actual data.
822  * @param[in] uxByteCount: The number of bytes.
823  *
824  * @return The 16-bit one's complement of the one's complement sum of all 16-bit
825  *         words in the header
826  */
usGenerateChecksum(uint16_t usSum,const uint8_t * pucNextData,size_t uxByteCount)827 uint16_t usGenerateChecksum( uint16_t usSum,
828                              const uint8_t * pucNextData,
829                              size_t uxByteCount )
830 {
831 /* MISRA/PC-lint doesn't like the use of unions. Here, they are a great
832  * aid though to optimise the calculations. */
833     xUnion32 xSum2;
834     xUnion32 xSum;
835     xUnion32 xTerm;
836     xUnionPtr xSource;
837     uintptr_t uxAlignBits;
838     uint32_t ulCarry = 0U;
839     uint16_t usTemp;
840     size_t uxDataLengthBytes = uxByteCount;
841     size_t uxSize;
842     uintptr_t ulX;
843 
844     /* Small MCUs often spend up to 30% of the time doing checksum calculations
845     * This function is optimised for 32-bit CPUs; Each time it will try to fetch
846     * 32-bits, sums it with an accumulator and counts the number of carries. */
847 
848     /* Swap the input (little endian platform only). */
849     usTemp = FreeRTOS_ntohs( usSum );
850     xSum.u32 = ( uint32_t ) usTemp;
851     xTerm.u32 = 0U;
852 
853     xSource.u8ptr = pucNextData;
854 
855     /* MISRA Ref 11.4.3 [Casting pointer to int for verification] */
856     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
857     /* coverity[misra_c_2012_rule_11_4_violation] */
858     uxAlignBits = ( ( ( uintptr_t ) pucNextData ) & 0x03U );
859 
860     /*
861      * If pucNextData is non-aligned then the checksum is starting at an
862      * odd position and we need to make sure the usSum value now in xSum is
863      * as if it had been "aligned" in the same way.
864      */
865     if( ( uxAlignBits & 1U ) != 0U )
866     {
867         xSum.u32 = ( ( xSum.u32 & 0xffU ) << 8 ) | ( ( xSum.u32 & 0xff00U ) >> 8 );
868     }
869 
870     /* If byte (8-bit) aligned... */
871     if( ( ( uxAlignBits & 1U ) != 0U ) && ( uxDataLengthBytes >= ( size_t ) 1U ) )
872     {
873         xTerm.u8[ 1 ] = *( xSource.u8ptr );
874         xSource.u8ptr++;
875         uxDataLengthBytes--;
876         /* Now xSource is word (16-bit) aligned. */
877     }
878 
879     /* If half-word (16-bit) aligned... */
880     if( ( ( uxAlignBits == 1U ) || ( uxAlignBits == 2U ) ) && ( uxDataLengthBytes >= 2U ) )
881     {
882         xSum.u32 += *( xSource.u16ptr );
883         xSource.u16ptr++;
884         uxDataLengthBytes -= 2U;
885         /* Now xSource is word (32-bit) aligned. */
886     }
887 
888     /* Word (32-bit) aligned, do the most part. */
889 
890     uxSize = ( size_t ) ( ( uxDataLengthBytes / 4U ) * 4U );
891 
892     if( uxSize >= ( 3U * sizeof( uint32_t ) ) )
893     {
894         uxSize -= ( 3U * sizeof( uint32_t ) );
895     }
896     else
897     {
898         uxSize = 0U;
899     }
900 
901     /* In this loop, four 32-bit additions will be done, in total 16 bytes.
902      * Indexing with constants (0,1,2,3) gives faster code than using
903      * post-increments. */
904     for( ulX = 0U; ulX < uxSize; ulX += 4U * sizeof( uint32_t ) )
905     {
906         /* Use a secondary Sum2, just to see if the addition produced an
907          * overflow. */
908         xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];
909 
910         if( xSum2.u32 < xSum.u32 )
911         {
912             ulCarry++;
913         }
914 
915         /* Now add the secondary sum to the major sum, and remember if there was
916          * a carry. */
917         xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];
918 
919         if( xSum2.u32 > xSum.u32 )
920         {
921             ulCarry++;
922         }
923 
924         /* And do the same trick once again for indexes 2 and 3 */
925         xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];
926 
927         if( xSum2.u32 < xSum.u32 )
928         {
929             ulCarry++;
930         }
931 
932         xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];
933 
934         if( xSum2.u32 > xSum.u32 )
935         {
936             ulCarry++;
937         }
938 
939         /* And finally advance the pointer 4 * 4 = 16 bytes. */
940         xSource.u32ptr = &( xSource.u32ptr[ 4 ] );
941     }
942 
943     /* Now add all carries. */
944     xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;
945 
946     uxDataLengthBytes %= 16U;
947 
948     /* Half-word aligned. */
949     uxSize = ( ( uxDataLengthBytes & ~( ( size_t ) 1U ) ) );
950 
951     for( ulX = 0U; ulX < uxSize; ulX += 1U * sizeof( uint16_t ) )
952     {
953         /* At least one more short. */
954         xSum.u32 += xSource.u16ptr[ 0 ];
955         xSource.u16ptr = &xSource.u16ptr[ 1 ];
956     }
957 
958     if( ( uxDataLengthBytes & ( size_t ) 1U ) != 0U ) /* Maybe one more ? */
959     {
960         xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];
961     }
962 
963     /* MISRA Ref 2.2.1 [Unions and dead code] */
964     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-22 */
965     /* coverity[misra_c_2012_rule_2_2_violation] */
966     /* coverity[assigned_value] */
967     xSum.u32 += xTerm.u32;
968 
969     /* Now add all carries again. */
970 
971     /* Assigning value from "xTerm.u32" to "xSum.u32" here, but that stored value is overwritten before it can be used. */
972     /* MISRA Ref 2.2.1 [Unions and dead code] */
973     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-22 */
974     /* coverity[misra_c_2012_rule_2_2_violation] */
975     /* coverity[value_overwrite] */
976     xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
977 
978     /* MISRA Ref 2.2.1 [Unions and dead code] */
979     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-22 */
980     /* coverity[misra_c_2012_rule_2_2_violation] */
981     /* coverity[value_overwrite] */
982     xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
983 
984     if( ( uxAlignBits & 1U ) != 0U )
985     {
986         /* Quite unlikely, but pucNextData might be non-aligned, which would
987         * mean that a checksum is calculated starting at an odd position. */
988         xSum.u32 = ( ( xSum.u32 & 0xffU ) << 8 ) | ( ( xSum.u32 & 0xff00U ) >> 8 );
989     }
990 
991     /* swap the output (little endian platform only). */
992     return FreeRTOS_htons( ( ( uint16_t ) xSum.u32 ) );
993 }
994 /*-----------------------------------------------------------*/
995 
996 #if ( ipconfigHAS_PRINTF != 0 )
997 
998     #ifndef ipMONITOR_MAX_HEAP
999 
1000 /* As long as the heap has more space than e.g. 1 MB, there
1001  * will be no messages. */
1002         #define ipMONITOR_MAX_HEAP    ( 1024U * 1024U )
1003     #endif /* ipMONITOR_MAX_HEAP */
1004 
1005     #ifndef ipMONITOR_PERCENTAGE_90
1006         /* Make this number lower to get less logging messages. */
1007         #define ipMONITOR_PERCENTAGE_90    ( 90U )
1008     #endif
1009 
1010     #define ipMONITOR_PERCENTAGE_100       ( 100U )
1011 
1012 /**
1013  * @brief A function that monitors a three resources: the heap, the space in the message
1014  *        queue of the IP-task, the number of available network buffer descriptors.
1015  */
vPrintResourceStats(void)1016     void vPrintResourceStats( void )
1017     {
1018         UBaseType_t uxCurrentBufferCount;
1019         size_t uxMinSize;
1020 
1021         /* When setting up and testing a project with FreeRTOS+TCP, it is
1022          * can be helpful to monitor a few resources: the number of network
1023          * buffers and the amount of available heap.
1024          * This function will issue some logging when a minimum value has
1025          * changed. */
1026         uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers();
1027 
1028         if( uxLastMinBufferCount > uxCurrentBufferCount )
1029         {
1030             /* The logging produced below may be helpful
1031              * while tuning +TCP: see how many buffers are in use. */
1032             uxLastMinBufferCount = uxCurrentBufferCount;
1033             FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
1034                                uxGetNumberOfFreeNetworkBuffers(),
1035                                uxCurrentBufferCount ) );
1036         }
1037 
1038         uxMinSize = xPortGetMinimumEverFreeHeapSize();
1039 
1040         if( uxMinLastSize == 0U )
1041         {
1042             /* Probably the first time this function is called. */
1043             uxMinLastSize = uxMinSize;
1044         }
1045         else if( uxMinSize >= ipMONITOR_MAX_HEAP )
1046         {
1047             /* There is more than enough heap space. No need for logging. */
1048         }
1049         /* Write logging if there is a 10% decrease since the last time logging was written. */
1050         else if( ( uxMinLastSize * ipMONITOR_PERCENTAGE_90 ) > ( uxMinSize * ipMONITOR_PERCENTAGE_100 ) )
1051         {
1052             uxMinLastSize = uxMinSize;
1053             FreeRTOS_printf( ( "Heap: current %lu lowest %lu\n", xPortGetFreeHeapSize(), uxMinSize ) );
1054         }
1055         else
1056         {
1057             /* Nothing to log. */
1058         }
1059 
1060         #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1061             {
1062                 UBaseType_t uxCurrentCount = 0u;
1063 
1064                 uxCurrentCount = uxGetMinimumIPQueueSpace();
1065 
1066                 if( uxLastMinQueueSpace != uxCurrentCount )
1067                 {
1068                     /* The logging produced below may be helpful
1069                      * while tuning +TCP: see how many buffers are in use. */
1070                     uxLastMinQueueSpace = uxCurrentCount;
1071                     FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
1072                 }
1073             }
1074         #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
1075     }
1076 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
1077 /*-----------------------------------------------------------*/
1078 
1079 /**
1080  * @brief Utility function: Convert error number to a human readable
1081  *        string. Declaration in FreeRTOS_errno_TCP.h.
1082  *
1083  * @param[in] xErrnum: The error number.
1084  * @param[in] pcBuffer: Buffer big enough to be filled with the human readable message.
1085  * @param[in] uxLength: Maximum length of the buffer.
1086  *
1087  * @return The buffer filled with human readable error string.
1088  */
FreeRTOS_strerror_r(BaseType_t xErrnum,char * pcBuffer,size_t uxLength)1089 const char * FreeRTOS_strerror_r( BaseType_t xErrnum,
1090                                   char * pcBuffer,
1091                                   size_t uxLength )
1092 {
1093     const char * pcName;
1094 
1095     switch( xErrnum )
1096     {
1097         case pdFREERTOS_ERRNO_EADDRINUSE:
1098             pcName = "EADDRINUSE";
1099             break;
1100 
1101         case pdFREERTOS_ERRNO_ENOMEM:
1102             pcName = "ENOMEM";
1103             break;
1104 
1105         case pdFREERTOS_ERRNO_EADDRNOTAVAIL:
1106             pcName = "EADDRNOTAVAIL";
1107             break;
1108 
1109         case pdFREERTOS_ERRNO_ENOPROTOOPT:
1110             pcName = "ENOPROTOOPT";
1111             break;
1112 
1113         case pdFREERTOS_ERRNO_EBADF:
1114             pcName = "EBADF";
1115             break;
1116 
1117         case pdFREERTOS_ERRNO_ENOSPC:
1118             pcName = "ENOSPC";
1119             break;
1120 
1121         case pdFREERTOS_ERRNO_ECANCELED:
1122             pcName = "ECANCELED";
1123             break;
1124 
1125         case pdFREERTOS_ERRNO_ENOTCONN:
1126             pcName = "ENOTCONN";
1127             break;
1128 
1129         case pdFREERTOS_ERRNO_EINPROGRESS:
1130             pcName = "EINPROGRESS";
1131             break;
1132 
1133         case pdFREERTOS_ERRNO_EOPNOTSUPP:
1134             pcName = "EOPNOTSUPP";
1135             break;
1136 
1137         case pdFREERTOS_ERRNO_EINTR:
1138             pcName = "EINTR";
1139             break;
1140 
1141         case pdFREERTOS_ERRNO_ETIMEDOUT:
1142             pcName = "ETIMEDOUT";
1143             break;
1144 
1145         case pdFREERTOS_ERRNO_EINVAL:
1146             pcName = "EINVAL";
1147             break;
1148 
1149         case pdFREERTOS_ERRNO_EWOULDBLOCK:
1150             pcName = "EWOULDBLOCK";
1151             break; /* same as EAGAIN */
1152 
1153         case pdFREERTOS_ERRNO_EISCONN:
1154             pcName = "EISCONN";
1155             break;
1156 
1157         default:
1158             /* MISRA Ref 21.6.1 [snprintf and logging] */
1159             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */
1160             /* coverity[misra_c_2012_rule_21_6_violation] */
1161             ( void ) snprintf( pcBuffer, uxLength, "Errno %d", ( int ) xErrnum );
1162             pcName = NULL;
1163             break;
1164     }
1165 
1166     if( pcName != NULL )
1167     {
1168         /* MISRA Ref 21.6.1 [snprintf and logging] */
1169         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */
1170         /* coverity[misra_c_2012_rule_21_6_violation] */
1171         ( void ) snprintf( pcBuffer, uxLength, "%s", pcName );
1172     }
1173 
1174     if( uxLength > 0U )
1175     {
1176         pcBuffer[ uxLength - 1U ] = '\0';
1177     }
1178 
1179     return pcBuffer;
1180 }
1181 /*-----------------------------------------------------------*/
1182 
1183 /**
1184  * @brief Get the highest value of two int32's.
1185  * @param[in] a: the first value.
1186  * @param[in] b: the second value.
1187  * @return The highest of the two values.
1188  */
FreeRTOS_max_int32(int32_t a,int32_t b)1189 int32_t FreeRTOS_max_int32( int32_t a,
1190                             int32_t b )
1191 {
1192     return ( a >= b ) ? a : b;
1193 }
1194 /*-----------------------------------------------------------*/
1195 
1196 /**
1197  * @brief Get the highest value of two uint32_t's.
1198  * @param[in] a: the first value.
1199  * @param[in] b: the second value.
1200  * @return The highest of the two values.
1201  */
FreeRTOS_max_uint32(uint32_t a,uint32_t b)1202 uint32_t FreeRTOS_max_uint32( uint32_t a,
1203                               uint32_t b )
1204 {
1205     return ( a >= b ) ? a : b;
1206 }
1207 /*-----------------------------------------------------------*/
1208 
1209 /**
1210  * @brief Get the highest value of two size_t's.
1211  * @param[in] a: the first value.
1212  * @param[in] b: the second value.
1213  * @return The highest of the two values.
1214  */
FreeRTOS_max_size_t(size_t a,size_t b)1215 size_t FreeRTOS_max_size_t( size_t a,
1216                             size_t b )
1217 {
1218     return ( a >= b ) ? a : b;
1219 }
1220 /*-----------------------------------------------------------*/
1221 
1222 /**
1223  * @brief Get the lowest value of two int32_t's.
1224  * @param[in] a: the first value.
1225  * @param[in] b: the second value.
1226  * @return The lowest of the two values.
1227  */
FreeRTOS_min_int32(int32_t a,int32_t b)1228 int32_t FreeRTOS_min_int32( int32_t a,
1229                             int32_t b )
1230 {
1231     return ( a <= b ) ? a : b;
1232 }
1233 /*-----------------------------------------------------------*/
1234 
1235 /**
1236  * @brief Get the lowest value of two uint32_t's.
1237  * @param[in] a: the first value.
1238  * @param[in] b: the second value.
1239  * @return The lowest of the two values.
1240  */
FreeRTOS_min_uint32(uint32_t a,uint32_t b)1241 uint32_t FreeRTOS_min_uint32( uint32_t a,
1242                               uint32_t b )
1243 {
1244     return ( a <= b ) ? a : b;
1245 }
1246 /*-----------------------------------------------------------*/
1247 
1248 /**
1249  * @brief Get the lowest value of two size_t's.
1250  * @param[in] a: the first value.
1251  * @param[in] b: the second value.
1252  * @return The lowest of the two values.
1253  */
FreeRTOS_min_size_t(size_t a,size_t b)1254 size_t FreeRTOS_min_size_t( size_t a,
1255                             size_t b )
1256 {
1257     return ( a <= b ) ? a : b;
1258 }
1259 /*-----------------------------------------------------------*/
1260 
1261 /**
1262  * @brief Round-up a number to a multiple of 'd'.
1263  * @param[in] a: the first value.
1264  * @param[in] d: the second value.
1265  * @return A multiple of d.
1266  */
FreeRTOS_round_up(uint32_t a,uint32_t d)1267 uint32_t FreeRTOS_round_up( uint32_t a,
1268                             uint32_t d )
1269 {
1270     uint32_t ulResult = a;
1271 
1272     configASSERT( d != 0U );
1273 
1274     if( d != 0U )
1275     {
1276         ulResult = d * ( ( a + d - 1U ) / d );
1277     }
1278 
1279     return ulResult;
1280 }
1281 /*-----------------------------------------------------------*/
1282 
1283 /**
1284  * @brief Round-down a number to a multiple of 'd'.
1285  * @param[in] a: the first value.
1286  * @param[in] d: the second value.
1287  * @return A multiple of d.
1288  */
FreeRTOS_round_down(uint32_t a,uint32_t d)1289 uint32_t FreeRTOS_round_down( uint32_t a,
1290                               uint32_t d )
1291 {
1292     uint32_t ulResult = 0;
1293 
1294     configASSERT( d != 0U );
1295 
1296     if( d != 0U )
1297     {
1298         ulResult = d * ( a / d );
1299     }
1300 
1301     return ulResult;
1302 }
1303 /*-----------------------------------------------------------*/
1304 
1305 /**
1306  * @brief Convert character array (of size 4) to equivalent 32-bit value.
1307  * @param[in] pucPtr: The character array.
1308  * @return 32-bit equivalent value extracted from the character array.
1309  *
1310  * @note Going by MISRA rules, these utility functions should not be defined
1311  *        if they are not being used anywhere. But their use depends on the
1312  *        application and hence these functions are defined unconditionally.
1313  */
ulChar2u32(const uint8_t * pucPtr)1314 uint32_t ulChar2u32( const uint8_t * pucPtr )
1315 {
1316     return ( ( ( uint32_t ) pucPtr[ 0 ] ) << 24 ) |
1317            ( ( ( uint32_t ) pucPtr[ 1 ] ) << 16 ) |
1318            ( ( ( uint32_t ) pucPtr[ 2 ] ) << 8 ) |
1319            ( ( ( uint32_t ) pucPtr[ 3 ] ) );
1320 }
1321 /*-----------------------------------------------------------*/
1322 
1323 /**
1324  * @brief Convert character array (of size 2) to equivalent 16-bit value.
1325  * @param[in] pucPtr: The character array.
1326  * @return 16-bit equivalent value extracted from the character array.
1327  *
1328  * @note Going by MISRA rules, these utility functions should not be defined
1329  *        if they are not being used anywhere. But their use depends on the
1330  *        application and hence these functions are defined unconditionally.
1331  */
usChar2u16(const uint8_t * pucPtr)1332 uint16_t usChar2u16( const uint8_t * pucPtr )
1333 {
1334     return ( uint16_t )
1335            ( ( ( ( uint32_t ) pucPtr[ 0 ] ) << 8 ) |
1336              ( ( ( uint32_t ) pucPtr[ 1 ] ) ) );
1337 }
1338 /*-----------------------------------------------------------*/
1339