xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_IP_Utils.c (revision f5ecc5f201ba569467d090b79b19c5e0baead322)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_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 #include "FreeRTOS_Routing.h"
57 #include "FreeRTOS_ND.h"
58 /*-----------------------------------------------------------*/
59 
60 /* Used to ensure the structure packing is having the desired effect.  The
61  * 'volatile' is used to prevent compiler warnings about comparing a constant with
62  * a constant. */
63 #ifndef _lint
64     #define ipEXPECTED_EthernetHeader_t_SIZE    ( ( size_t ) 14 ) /**< Ethernet Header size in bytes. */
65     #define ipEXPECTED_ARPHeader_t_SIZE         ( ( size_t ) 28 ) /**< ARP header size in bytes. */
66     #define ipEXPECTED_IPHeader_t_SIZE          ( ( size_t ) 20 ) /**< IP header size in bytes. */
67     #define ipEXPECTED_IGMPHeader_t_SIZE        ( ( size_t ) 8 )  /**< IGMP header size in bytes. */
68     #define ipEXPECTED_ICMPHeader_t_SIZE        ( ( size_t ) 8 )  /**< ICMP header size in bytes. */
69     #define ipEXPECTED_UDPHeader_t_SIZE         ( ( size_t ) 8 )  /**< UDP header size in bytes. */
70     #define ipEXPECTED_TCPHeader_t_SIZE         ( ( size_t ) 20 ) /**< TCP header size in bytes. */
71 #endif
72 
73 /** @brief Time delay between repeated attempts to initialise the network hardware. */
74 #ifndef ipINITIALISATION_RETRY_DELAY
75     #define ipINITIALISATION_RETRY_DELAY    ( pdMS_TO_TICKS( 3000U ) )
76 #endif
77 
78 /** @brief The minimum value of TCP offset value. */
79 #define FREERTOS_MINIMUM_TCP_OFFSET    ( 5U )
80 
81 #if ( ipconfigHAS_PRINTF != 0 )
82     /** @brief Last value of minimum buffer count. */
83     static UBaseType_t uxLastMinBufferCount = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
84 
85 /** @brief Last value of minimum size. Used in printing resource stats. */
86     static size_t uxMinLastSize = 0u;
87 #endif
88 
89 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) && ( ipconfigHAS_PRINTF != 0 )
90     static UBaseType_t uxLastMinQueueSpace = 0;
91 #endif
92 
93 /**
94  * Used in checksum calculation.
95  */
96 typedef union xUnion32
97 {
98     uint32_t u32;      /**< The 32-bit member of the union. */
99     uint16_t u16[ 2 ]; /**< The array of 2 16-bit members of the union. */
100     uint8_t u8[ 4 ];   /**< The array of 4 8-bit members of the union. */
101 } xUnion32_t;
102 
103 /**
104  * Used in checksum calculation.
105  */
106 typedef union xUnionPtr
107 {
108     const uint32_t * u32ptr; /**< The pointer member to a 32-bit variable. */
109     const uint16_t * u16ptr; /**< The pointer member to a 16-bit variable. */
110     const uint8_t * u8ptr;   /**< The pointer member to an 8-bit variable. */
111 } xUnionPtr_t;
112 
113 /*
114  * Returns the network buffer descriptor that owns a given packet buffer.
115  */
116 static NetworkBufferDescriptor_t * prvPacketBuffer_to_NetworkBuffer( const void * pvBuffer,
117                                                                      size_t uxOffset );
118 
119 static uintptr_t void_ptr_to_uintptr( const void * pvPointer );
120 
121 static BaseType_t prvChecksumProtocolChecks( size_t uxBufferLength,
122                                              struct xPacketSummary * pxSet );
123 
124 static BaseType_t prvChecksumProtocolMTUCheck( struct xPacketSummary * pxSet );
125 
126 static void prvChecksumProtocolCalculate( BaseType_t xOutgoingPacket,
127                                           const uint8_t * pucEthernetBuffer,
128                                           struct xPacketSummary * pxSet );
129 
130 static void prvChecksumProtocolSetChecksum( BaseType_t xOutgoingPacket,
131                                             const uint8_t * pucEthernetBuffer,
132                                             size_t uxBufferLength,
133                                             const struct xPacketSummary * pxSet );
134 
135 static void prvSetChecksumInPacket( const struct xPacketSummary * pxSet,
136                                     uint16_t usChecksum );
137 
138 static uint16_t prvGetChecksumFromPacket( const struct xPacketSummary * pxSet );
139 
140 /**
141  * @brief Set checksum in the packet
142  *
143  * @param pxSet Pointer to the packet summary that describes the packet,
144  *                  to which the checksum will be set.
145  *
146  * @param usChecksum Checksum value to be set.
147  */
prvSetChecksumInPacket(const struct xPacketSummary * pxSet,uint16_t usChecksum)148 static void prvSetChecksumInPacket( const struct xPacketSummary * pxSet,
149                                     uint16_t usChecksum )
150 {
151     if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
152     {
153         pxSet->pxProtocolHeaders->xUDPHeader.usChecksum = usChecksum;
154     }
155     else if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
156     {
157         pxSet->pxProtocolHeaders->xTCPHeader.usChecksum = usChecksum;
158     }
159     else if( ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
160              ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
161     {
162         pxSet->pxProtocolHeaders->xICMPHeader.usChecksum = usChecksum;
163     }
164     else if( ( pxSet->xIsIPv6 != pdFALSE ) && ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP_IPv6 ) )
165     {
166         pxSet->pxProtocolHeaders->xICMPHeaderIPv6.usChecksum = usChecksum;
167     }
168     else
169     {
170         /* Unhandled protocol. */
171     }
172 }
173 
174 /**
175  * @brief Get checksum from the packet summary
176  *
177  * @param pxSet Pointer to the packet summary that describes the packet,
178  *                  from which the checksum will be retrieved.
179  *
180  * @return Checksum value that is retrieved from pxSet.
181  */
prvGetChecksumFromPacket(const struct xPacketSummary * pxSet)182 static uint16_t prvGetChecksumFromPacket( const struct xPacketSummary * pxSet )
183 {
184     uint16_t usChecksum;
185 
186     if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
187     {
188         usChecksum = pxSet->pxProtocolHeaders->xUDPHeader.usChecksum;
189     }
190     else if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
191     {
192         usChecksum = pxSet->pxProtocolHeaders->xTCPHeader.usChecksum;
193     }
194     else if( ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
195              ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
196     {
197         usChecksum = pxSet->pxProtocolHeaders->xICMPHeader.usChecksum;
198     }
199     else if( ( pxSet->xIsIPv6 != pdFALSE ) && ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP_IPv6 ) )
200     {
201         usChecksum = pxSet->pxProtocolHeaders->xICMPHeaderIPv6.usChecksum;
202     }
203     else
204     {
205         /* Unhandled protocol. */
206         usChecksum = ipUNHANDLED_PROTOCOL;
207     }
208 
209     return usChecksum;
210 }
211 
212 #if ( ipconfigUSE_DHCPv6 == 1 ) || ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_RA == 1 )
213 
214 /**
215  * @brief Create a DHCP event.
216  *
217  * @return pdPASS or pdFAIL, depending on whether xSendEventStructToIPTask()
218  *         succeeded.
219  * @param pxEndPoint The end-point that needs DHCP.
220  */
xSendDHCPEvent(struct xNetworkEndPoint * pxEndPoint)221     BaseType_t xSendDHCPEvent( struct xNetworkEndPoint * pxEndPoint )
222     {
223         IPStackEvent_t xEventMessage;
224         const TickType_t uxDontBlock = 0U;
225 
226         #if ( ipconfigUSE_DHCPv6 == 1 ) || ( ipconfigUSE_DHCP == 1 )
227             eDHCPState_t uxOption = eGetDHCPState( pxEndPoint );
228         #endif
229 
230         xEventMessage.eEventType = eDHCPEvent;
231 
232         /* MISRA Ref 11.6.1 [DHCP events and conversion to void] */
233         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-116 */
234         /* coverity[misra_c_2012_rule_11_6_violation] */
235         xEventMessage.pvData = ( void * ) pxEndPoint;
236         #if ( ipconfigUSE_DHCPv6 == 1 ) || ( ipconfigUSE_DHCP == 1 )
237             {
238                 pxEndPoint->xDHCPData.eExpectedState = uxOption;
239             }
240         #endif
241 
242         return xSendEventStructToIPTask( &xEventMessage, uxDontBlock );
243     }
244 #endif /* if ( ipconfigUSE_DHCPv6 == 1 ) || ( ipconfigUSE_DHCP == 1 ) */
245 /*-----------------------------------------------------------*/
246 
247 /**
248  * @brief Duplicate the given network buffer descriptor with a modified length.
249  *
250  * @param[in] pxNetworkBuffer The network buffer to be duplicated.
251  * @param[in] uxNewLength The length for the new buffer.
252  *
253  * @return If properly duplicated, then the duplicate network buffer or else, NULL.
254  */
pxDuplicateNetworkBufferWithDescriptor(const NetworkBufferDescriptor_t * const pxNetworkBuffer,size_t uxNewLength)255 NetworkBufferDescriptor_t * pxDuplicateNetworkBufferWithDescriptor( const NetworkBufferDescriptor_t * const pxNetworkBuffer,
256                                                                     size_t uxNewLength )
257 {
258     NetworkBufferDescriptor_t * pxNewBuffer;
259     size_t uxLengthToCopy = uxNewLength;
260 
261     /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.
262      * The transmit routine wants to have ownership of the network buffer
263      * descriptor, because it will pass the buffer straight to DMA. */
264     pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );
265 
266     if( pxNewBuffer != NULL )
267     {
268         configASSERT( pxNewBuffer->pucEthernetBuffer != NULL );
269 
270         /* Get the minimum of both values to copy the data. */
271         if( uxLengthToCopy > pxNetworkBuffer->xDataLength )
272         {
273             uxLengthToCopy = pxNetworkBuffer->xDataLength;
274         }
275 
276         /* Set the actual packet size in case a bigger buffer than requested
277          * was returned. */
278         pxNewBuffer->xDataLength = uxNewLength;
279 
280         /* Copy the original packet information. */
281         pxNewBuffer->xIPAddress.ulIP_IPv4 = pxNetworkBuffer->xIPAddress.ulIP_IPv4;
282         pxNewBuffer->usPort = pxNetworkBuffer->usPort;
283         pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;
284         pxNewBuffer->pxInterface = pxNetworkBuffer->pxInterface;
285         pxNewBuffer->pxEndPoint = pxNetworkBuffer->pxEndPoint;
286         ( void ) memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, uxLengthToCopy );
287 
288         #if ( ipconfigUSE_IPv6 != 0 )
289             if( uxIPHeaderSizePacket( pxNewBuffer ) == ipSIZE_OF_IPv6_HEADER )
290             {
291                 ( void ) memcpy( pxNewBuffer->xIPAddress.xIP_IPv6.ucBytes, pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
292             }
293         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
294     }
295 
296     return pxNewBuffer;
297 }
298 /*-----------------------------------------------------------*/
299 
300 /**
301  * @brief Get the network buffer descriptor from the packet buffer.
302  *
303  * @param[in] pvBuffer The pointer to packet buffer.
304  * @param[in] uxOffset Additional offset (such as the packet length of UDP packet etc.).
305  *
306  * @return The network buffer descriptor if the alignment is correct. Else a NULL is returned.
307  */
prvPacketBuffer_to_NetworkBuffer(const void * pvBuffer,size_t uxOffset)308 static NetworkBufferDescriptor_t * prvPacketBuffer_to_NetworkBuffer( const void * pvBuffer,
309                                                                      size_t uxOffset )
310 {
311     uintptr_t uxBuffer;
312     NetworkBufferDescriptor_t * pxResult;
313 
314     if( pvBuffer == NULL )
315     {
316         pxResult = NULL;
317     }
318     else
319     {
320         /* Obtain the network buffer from the zero copy pointer. */
321 
322         /* MISRA Ref 11.6.2 [Pointer arithmetic and hidden pointer] */
323         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-116 */
324         /* coverity[misra_c_2012_rule_11_6_violation] */
325         uxBuffer = void_ptr_to_uintptr( pvBuffer );
326 
327         /* The input here is a pointer to a packet buffer plus some offset.  Subtract
328          * this offset, and also the size of the header in the network buffer, usually
329          * 8 + 2 bytes. */
330         uxBuffer -= ( uxOffset + ipBUFFER_PADDING );
331 
332         /* Here a pointer was placed to the network descriptor.  As a
333          * pointer is dereferenced, make sure it is well aligned. */
334         if( ( uxBuffer & ( ( ( uintptr_t ) sizeof( uxBuffer ) ) - 1U ) ) == ( uintptr_t ) 0U )
335         {
336             /* MISRA Ref 11.4.2 [Validation of pointer alignment] */
337             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
338             /* coverity[misra_c_2012_rule_11_4_violation] */
339             pxResult = *( ( NetworkBufferDescriptor_t ** ) uxBuffer );
340         }
341         else
342         {
343             pxResult = NULL;
344         }
345     }
346 
347     return pxResult;
348 }
349 /*-----------------------------------------------------------*/
350 
351 /**
352  * @brief uintptr_t is an unsigned integer type that is capable of storing a data pointer.
353  *        Therefore it is safe to convert from a void pointer to a uintptr_t, using a union.
354  */
355 union uIntPtr
356 {
357     uintptr_t uxPtr;    /**< THe numeric value. */
358     const void * pvPtr; /**< THe void pointer. */
359 };
360 
361 /**
362  * @brief Helper function: cast a pointer to a numeric value 'uintptr_t',
363  *        using a union as defined here above.
364  * @param[in] pvPointer A void pointer to be converted.
365  * @return The value of the void pointer as an unsigned number.
366  */
void_ptr_to_uintptr(const void * pvPointer)367 static uintptr_t void_ptr_to_uintptr( const void * pvPointer )
368 {
369     /* The type 'uintptr_t' has the same size as a pointer.
370      * Therefore, it is safe to use a union to convert it. */
371     union uIntPtr intPtr;
372 
373     intPtr.pvPtr = pvPointer;
374     return intPtr.uxPtr;
375 }
376 /*-----------------------------------------------------------*/
377 
378 /** @brief Get and check the specific lengths depending on the protocol ( TCP/UDP/ICMP/IGMP ).
379  * @param[in] uxBufferLength The number of bytes to be sent or received.
380  * @param[in] pxSet A struct describing this packet.
381  *
382  * @return Non-zero in case of an error.
383  */
prvChecksumProtocolChecks(size_t uxBufferLength,struct xPacketSummary * pxSet)384 static BaseType_t prvChecksumProtocolChecks( size_t uxBufferLength,
385                                              struct xPacketSummary * pxSet )
386 {
387     BaseType_t xReturn = 0;
388 
389     /* Both in case of IPv4, as well as IPv6, it has been confirmed that the packet
390      * is long enough to contain the promised data. */
391 
392     /* Switch on the Layer 3/4 protocol. */
393     if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
394     {
395         if( ( pxSet->usProtocolBytes < ipSIZE_OF_UDP_HEADER ) ||
396             ( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + pxSet->uxIPHeaderLength + ipSIZE_OF_UDP_HEADER ) ) )
397         {
398             pxSet->usChecksum = ipINVALID_LENGTH;
399             xReturn = 7;
400         }
401 
402         if( xReturn == 0 )
403         {
404             pxSet->uxProtocolHeaderLength = sizeof( pxSet->pxProtocolHeaders->xUDPHeader );
405             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
406                 {
407                     pxSet->pcType = "UDP";
408                 }
409             #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
410         }
411     }
412     else if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
413     {
414         if( ( pxSet->usProtocolBytes < ipSIZE_OF_TCP_HEADER ) ||
415             ( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + pxSet->uxIPHeaderLength + ipSIZE_OF_TCP_HEADER ) ) )
416         {
417             pxSet->usChecksum = ipINVALID_LENGTH;
418             xReturn = 8;
419         }
420 
421         if( xReturn == 0 )
422         {
423             uint8_t ucLength = pxSet->pxProtocolHeaders->xTCPHeader.ucTCPOffset >> 4U;
424             size_t uxOptionsLength;
425 
426             if( ucLength < FREERTOS_MINIMUM_TCP_OFFSET )
427             {
428                 pxSet->usChecksum = ipINVALID_LENGTH;
429                 xReturn = 9;
430             }
431             else
432             {
433                 uxOptionsLength = ( ( ( size_t ) ucLength - 5U ) << 2U );
434 
435                 pxSet->uxProtocolHeaderLength = ipSIZE_OF_TCP_HEADER + uxOptionsLength;
436                 #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
437                     {
438                         pxSet->pcType = "TCP";
439                     }
440                 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
441             }
442         }
443     }
444     else if( ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
445              ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
446     {
447         if( ( pxSet->usProtocolBytes < ipSIZE_OF_ICMPv4_HEADER ) ||
448             ( uxBufferLength < ( ipSIZE_OF_ETH_HEADER + pxSet->uxIPHeaderLength + ipSIZE_OF_ICMPv4_HEADER ) ) )
449         {
450             pxSet->usChecksum = ipINVALID_LENGTH;
451             xReturn = 10;
452         }
453 
454         if( xReturn == 0 )
455         {
456             pxSet->uxProtocolHeaderLength = sizeof( pxSet->pxProtocolHeaders->xICMPHeader );
457 
458             #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
459                 {
460                     if( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
461                     {
462                         pxSet->pcType = "ICMP";
463                     }
464                     else
465                     {
466                         pxSet->pcType = "IGMP";
467                     }
468                 }
469             #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
470         }
471     }
472     else if( ( pxSet->xIsIPv6 != pdFALSE ) && ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP_IPv6 ) )
473     {
474         #if ( ipconfigUSE_IPv6 != 0 )
475             xReturn = prvChecksumICMPv6Checks( uxBufferLength, pxSet );
476         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
477     }
478     else
479     {
480         /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
481         pxSet->usChecksum = ipUNHANDLED_PROTOCOL;
482         xReturn = 11;
483     }
484 
485     return xReturn;
486 }
487 /*-----------------------------------------------------------*/
488 
489 /** @brief See if the packet doesn't get bigger than the value of MTU.
490  * @param[in] pxSet A struct describing this packet.
491  *
492  * @return Non-zero in case of an error.
493  */
prvChecksumProtocolMTUCheck(struct xPacketSummary * pxSet)494 static BaseType_t prvChecksumProtocolMTUCheck( struct xPacketSummary * pxSet )
495 {
496     BaseType_t xReturn = 0;
497 
498     /* Here, 'pxSet->usProtocolBytes' contains the size of the protocol data
499      * ( headers and payload ). */
500 
501     /* The Ethernet header is excluded from the MTU. */
502     uint32_t ulMaxLength = ipconfigNETWORK_MTU;
503 
504     ulMaxLength -= ( uint32_t ) pxSet->uxIPHeaderLength;
505 
506     if( ( pxSet->usProtocolBytes < ( uint16_t ) pxSet->uxProtocolHeaderLength ) ||
507         ( pxSet->usProtocolBytes > ulMaxLength ) )
508     {
509         #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
510             {
511                 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %u\n", pxSet->pcType, pxSet->usProtocolBytes ) );
512             }
513         #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
514 
515         /* Again, in a 16-bit return value there is no space to indicate an
516          * error.  For incoming packets, 0x1234 will cause dropping of the packet.
517          * For outgoing packets, there is a serious problem with the
518          * format/length */
519         pxSet->usChecksum = ipINVALID_LENGTH;
520         xReturn = 13;
521     }
522 
523     return xReturn;
524 }
525 /*-----------------------------------------------------------*/
526 
527 /** @brief Do the actual checksum calculations, both the pseudo header, and the payload.
528  * @param[in] xOutgoingPacket pdTRUE when the packet is to be sent.
529  * @param[in] pucEthernetBuffer The buffer containing the packet.
530  * @param[in] pxSet A struct describing this packet.
531  */
prvChecksumProtocolCalculate(BaseType_t xOutgoingPacket,const uint8_t * pucEthernetBuffer,struct xPacketSummary * pxSet)532 static void prvChecksumProtocolCalculate( BaseType_t xOutgoingPacket,
533                                           const uint8_t * pucEthernetBuffer,
534                                           struct xPacketSummary * pxSet )
535 {
536     #if ( ipconfigUSE_IPv6 != 0 )
537         if( pxSet->xIsIPv6 != pdFALSE )
538         {
539             uint32_t pulHeader[ 2 ];
540 
541             /* IPv6 has a 40-byte pseudo header:
542              * 0..15 Source IPv6 address
543              * 16..31 Target IPv6 address
544              * 32..35 Length of payload
545              * 36..38 three zero's
546              * 39 Next Header, i.e. the protocol type. */
547 
548             pulHeader[ 0 ] = ( uint32_t ) pxSet->usProtocolBytes;
549             pulHeader[ 0 ] = FreeRTOS_htonl( pulHeader[ 0 ] );
550             pulHeader[ 1 ] = ( uint32_t ) pxSet->ucProtocol;
551             pulHeader[ 1 ] = FreeRTOS_htonl( pulHeader[ 1 ] );
552 
553             pxSet->usChecksum = usGenerateChecksum( 0U,
554                                                     &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + offsetof( IPHeader_IPv6_t, xSourceAddress ) ] ),
555                                                     ( size_t ) ( 2U * sizeof( pxSet->pxIPPacket_IPv6->xSourceAddress ) ) );
556 
557             pxSet->usChecksum = usGenerateChecksum( pxSet->usChecksum,
558                                                     ( const uint8_t * ) pulHeader,
559                                                     ( size_t ) ( sizeof( pulHeader ) ) );
560         }
561     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
562 
563     if( ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) || ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
564     {
565         /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */
566         pxSet->usChecksum = ( uint16_t )
567                             ( ~usGenerateChecksum( 0U, &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + pxSet->uxIPHeaderLength ] ), ( size_t ) pxSet->usProtocolBytes ) );
568     }
569 
570     else if( ( pxSet->xIsIPv6 != pdFALSE ) && ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP_IPv6 ) )
571     {
572         #if ( ipconfigUSE_IPv6 != 0 )
573             pxSet->usChecksum = ( uint16_t )
574                                 ( ~usGenerateChecksum( pxSet->usChecksum,
575                                                        ( uint8_t * ) &( pxSet->pxProtocolHeaders->xTCPHeader ),
576                                                        ( size_t ) pxSet->usProtocolBytes ) );
577         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
578     }
579     else
580     {
581         /* Default case is impossible to reach because it's checked before calling this function. */
582         switch( pxSet->xIsIPv6 ) /* LCOV_EXCL_BR_LINE */
583         {
584             #if ( ipconfigUSE_IPv6 != 0 )
585                 case pdTRUE:
586                     /* The CRC of the IPv6 pseudo-header has already been calculated. */
587                     pxSet->usChecksum = ( uint16_t )
588                                         ( ~usGenerateChecksum( pxSet->usChecksum,
589                                                                ( uint8_t * ) &( pxSet->pxProtocolHeaders->xUDPHeader.usSourcePort ),
590                                                                ( size_t ) ( pxSet->usProtocolBytes ) ) );
591                     break;
592             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
593 
594             #if ( ipconfigUSE_IPv4 != 0 )
595                 case pdFALSE:
596                    {
597                        /* The IPv4 pseudo header contains 2 IP-addresses, totalling 8 bytes. */
598                        uint32_t ulByteCount = pxSet->usProtocolBytes;
599                        ulByteCount += 2U * ipSIZE_OF_IPv4_ADDRESS;
600 
601                        /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length
602                         * fields */
603                        pxSet->usChecksum = ( uint16_t ) ( pxSet->usProtocolBytes + ( ( uint16_t ) pxSet->ucProtocol ) );
604 
605                        /* And then continue at the IPv4 source and destination addresses. */
606                        pxSet->usChecksum = ( uint16_t )
607                                            ( ~usGenerateChecksum( pxSet->usChecksum,
608                                                                   ( const uint8_t * ) &( pxSet->pxIPPacket->xIPHeader.ulSourceIPAddress ),
609                                                                   ulByteCount ) );
610                    }
611                    break;
612             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
613 
614             /* Default case is impossible to reach because it's checked before calling this function. */
615             default: /* LCOV_EXCL_LINE */
616                 /* Shouldn't reach here */
617                 /* MISRA 16.4 Compliance */
618                 break; /* LCOV_EXCL_LINE */
619         }
620 
621         /* Sum TCP header and data. */
622     }
623 
624     if( xOutgoingPacket == pdFALSE )
625     {
626         /* This is in incoming packet. If the CRC is correct, it should be zero. */
627         if( pxSet->usChecksum == 0U )
628         {
629             pxSet->usChecksum = ( uint16_t ) ipCORRECT_CRC;
630         }
631         else
632         {
633             pxSet->usChecksum = ( uint16_t ) ipWRONG_CRC;
634         }
635     }
636     else
637     {
638         if( ( pxSet->usChecksum == 0U ) && ( pxSet->ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
639         {
640             /* In case of UDP, a calculated checksum of 0x0000 is transmitted
641              * as 0xffff. A value of zero would mean that the checksum is not used. */
642             pxSet->usChecksum = ( uint16_t ) 0xffffu;
643         }
644     }
645 
646     pxSet->usChecksum = FreeRTOS_htons( pxSet->usChecksum );
647 }
648 /*-----------------------------------------------------------*/
649 
650 /** @brief For outgoing packets, set the checksum in the packet,
651  *        for incoming packets: show logging in case an error occurred.
652  * @param[in] xOutgoingPacket Non-zero if this is an outgoing packet.
653  * @param[in] pucEthernetBuffer The buffer containing the packet.
654  * @param[in] uxBufferLength the total number of bytes received, or the number of bytes written
655  * @param[in] pxSet A struct describing this packet.
656  */
prvChecksumProtocolSetChecksum(BaseType_t xOutgoingPacket,const uint8_t * pucEthernetBuffer,size_t uxBufferLength,const struct xPacketSummary * pxSet)657 static void prvChecksumProtocolSetChecksum( BaseType_t xOutgoingPacket,
658                                             const uint8_t * pucEthernetBuffer,
659                                             size_t uxBufferLength,
660                                             const struct xPacketSummary * pxSet )
661 {
662     if( xOutgoingPacket != pdFALSE )
663     {
664         prvSetChecksumInPacket( pxSet, pxSet->usChecksum );
665     }
666 
667     #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
668         else if( pxSet->usChecksum != ipCORRECT_CRC )
669         {
670             uint16_t usGot;
671             usGot = prvGetChecksumFromPacket( pxSet );
672             FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len %d ID %04X: from %xip to %xip cal %04X got %04X\n",
673                                      pxSet->pcType,
674                                      pxSet->usProtocolBytes,
675                                      FreeRTOS_ntohs( pxSet->pxIPPacket->xIPHeader.usIdentification ),
676                                      ( unsigned ) FreeRTOS_ntohl( pxSet->pxIPPacket->xIPHeader.ulSourceIPAddress ),
677                                      ( unsigned ) FreeRTOS_ntohl( pxSet->pxIPPacket->xIPHeader.ulDestinationIPAddress ),
678                                      FreeRTOS_ntohs( pxSet->usChecksum ),
679                                      FreeRTOS_ntohs( usGot ) ) );
680         }
681         else
682         {
683             /* This is an incoming packet and it doesn't need debug logging. */
684         }
685     #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
686 
687     /* Mention parameters that are not used by the function. */
688     ( void ) uxBufferLength;
689     ( void ) pucEthernetBuffer;
690 }
691 /*-----------------------------------------------------------*/
692 
693 #if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
694 
695 /**
696  * @brief Get the network buffer from the packet buffer.
697  *
698  * @param[in] pvBuffer Pointer to the packet buffer.
699  *
700  * @return The network buffer if the alignment is correct. Else a NULL is returned.
701  */
pxPacketBuffer_to_NetworkBuffer(const void * pvBuffer)702     NetworkBufferDescriptor_t * pxPacketBuffer_to_NetworkBuffer( const void * pvBuffer )
703     {
704         return prvPacketBuffer_to_NetworkBuffer( pvBuffer, 0U );
705     }
706 
707 #endif /* ( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 ) */
708 /*-----------------------------------------------------------*/
709 
710 /**
711  * @brief Get the network buffer from the UDP Payload buffer.
712  *
713  * @param[in] pvBuffer Pointer to the UDP payload buffer.
714  *
715  * @return The network buffer if the alignment is correct. Else a NULL is returned.
716  */
pxUDPPayloadBuffer_to_NetworkBuffer(const void * pvBuffer)717 NetworkBufferDescriptor_t * pxUDPPayloadBuffer_to_NetworkBuffer( const void * pvBuffer )
718 {
719     NetworkBufferDescriptor_t * pxResult;
720 
721     if( pvBuffer == NULL )
722     {
723         pxResult = NULL;
724     }
725     else
726     {
727         size_t uxOffset;
728 
729         /* The input here is a pointer to a payload buffer.  Subtract
730          * the total size of a UDP/IP packet plus the size of the header in
731          * the network buffer, usually 8 + 2 bytes. */
732 
733         uintptr_t uxTypeOffset;
734         const uint8_t * pucIPType;
735         uint8_t ucIPType;
736 
737         /* When IPv6 is supported, find out the type of the packet.
738          * It is stored 48 bytes before the payload buffer as 0x40 or 0x60. */
739         uxTypeOffset = void_ptr_to_uintptr( pvBuffer );
740         uxTypeOffset -= ipUDP_PAYLOAD_IP_TYPE_OFFSET;
741         /* MISRA Ref 11.4.3 [Casting pointer to int for verification] */
742         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
743         /* coverity[misra_c_2012_rule_11_4_violation] */
744         pucIPType = ( const uint8_t * ) uxTypeOffset;
745 
746         /* For an IPv4 packet, pucIPType points to 6 bytes before the pucEthernetBuffer,
747          * for a IPv6 packet, pucIPType will point to the first byte of the IP-header: 'ucVersionTrafficClass'. */
748         ucIPType = pucIPType[ 0 ] & 0xf0U;
749 
750         /* To help the translation from a UDP payload pointer to a networkBuffer,
751          * a byte was stored at a certain negative offset (-48 bytes).
752          * It must have a value of either 0x4x or 0x6x. */
753         configASSERT( ( ucIPType == ipTYPE_IPv4 ) || ( ucIPType == ipTYPE_IPv6 ) );
754 
755         switch( ucIPType ) /* LCOV_EXCL_BR_LINE */
756         {
757             #if ( ipconfigUSE_IPv6 != 0 )
758                 case ipTYPE_IPv6:
759                     uxOffset = sizeof( UDPPacket_IPv6_t );
760                     break;
761             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
762 
763             #if ( ipconfigUSE_IPv4 != 0 )
764                 case ipTYPE_IPv4:
765                     uxOffset = sizeof( UDPPacket_t );
766                     break;
767             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
768 
769             default:
770                 FreeRTOS_debug_printf( ( "pxUDPPayloadBuffer_to_NetworkBuffer: Undefined ucIPType \n" ) );
771                 uxOffset = sizeof( UDPPacket_t );
772                 break;
773         }
774 
775         pxResult = prvPacketBuffer_to_NetworkBuffer( pvBuffer, uxOffset );
776     }
777 
778     return pxResult;
779 }
780 /*-----------------------------------------------------------*/
781 
782 /**
783  * @brief Function to check whether the current context belongs to
784  *        the IP-task.
785  *
786  * @return If the current context belongs to the IP-task, then pdTRUE is
787  *         returned. Else pdFALSE is returned.
788  *
789  * @note Very important: the IP-task is not allowed to call its own API's,
790  *        because it would easily get into a dead-lock.
791  */
xIsCallingFromIPTask(void)792 BaseType_t xIsCallingFromIPTask( void )
793 {
794     BaseType_t xReturn;
795     const struct tskTaskControlBlock * const xCurrentHandle = xTaskGetCurrentTaskHandle();
796     const struct tskTaskControlBlock * const xCurrentIPTaskHandle = FreeRTOS_GetIPTaskHandle();
797 
798     if( xCurrentHandle == xCurrentIPTaskHandle )
799     {
800         xReturn = pdTRUE;
801     }
802     else
803     {
804         xReturn = pdFALSE;
805     }
806 
807     return xReturn;
808 }
809 /*-----------------------------------------------------------*/
810 
811 /**
812  * @brief Process a 'Network down' event and complete required processing.
813  * @param pxInterface The interface that goes down.
814  */
815 /* MISRA Ref 8.9.1 [File scoped variables] */
816 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
817 /* coverity[misra_c_2012_rule_8_9_violation] */
818 /* coverity[single_use] */
prvProcessNetworkDownEvent(struct xNetworkInterface * pxInterface)819 void prvProcessNetworkDownEvent( struct xNetworkInterface * pxInterface )
820 {
821     NetworkEndPoint_t * pxEndPoint;
822 
823     configASSERT( pxInterface != NULL );
824     configASSERT( pxInterface->pfInitialise != NULL );
825     /* Stop the ARP timer while there is no network. */
826     vIPSetARPTimerEnableState( pdFALSE );
827 
828     /* The first network down event is generated by the IP stack itself to
829      * initialise the network hardware, so do not call the network down event
830      * the first time through. */
831 
832     for( pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
833          pxEndPoint != NULL;
834          pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ) )
835     {
836         /* The bit 'bEndPointUp' stays low until vIPNetworkUpCalls() is called. */
837         pxEndPoint->bits.bEndPointUp = pdFALSE_UNSIGNED;
838         #if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
839             {
840                 if( pxEndPoint->bits.bCallDownHook != pdFALSE_UNSIGNED )
841                 {
842                     #if defined( ipconfigIPv4_BACKWARD_COMPATIBLE ) && ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
843                         {
844                             vApplicationIPNetworkEventHook( eNetworkDown );
845                         }
846                     #else
847                         {
848                             vApplicationIPNetworkEventHook_Multi( eNetworkDown, pxEndPoint );
849                         }
850                     #endif
851                 }
852                 else
853                 {
854                     /* The next time NetworkEventHook will be called for this end-point. */
855                     pxEndPoint->bits.bCallDownHook = pdTRUE_UNSIGNED;
856                 }
857             }
858         #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
859 
860         /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122,
861          * treat network down as a "delivery problem" and flush the ARP cache for this
862          *  interface. */
863         FreeRTOS_ClearARP( pxEndPoint );
864     }
865 
866     /* The network has been disconnected (or is being initialised for the first
867      * time).  Perform whatever hardware processing is necessary to bring it up
868      * again, or wait for it to be available again.  This is hardware dependent. */
869 
870     if( pxInterface->pfInitialise( pxInterface ) == pdPASS )
871     {
872         pxInterface->bits.bInterfaceUp = pdTRUE_UNSIGNED;
873         /* Set remaining time to 0 so it will become active immediately. */
874 
875         /* The network is not up until DHCP has completed.
876          * Start it now for all associated end-points. */
877 
878         for( pxEndPoint = FreeRTOS_FirstEndPoint( pxInterface );
879              pxEndPoint != NULL;
880              pxEndPoint = FreeRTOS_NextEndPoint( pxInterface, pxEndPoint ) )
881         {
882             #if ( ipconfigUSE_DHCP == 1 )
883                 if( END_POINT_USES_DHCP( pxEndPoint ) )
884                 {
885                     #if ( ( ipconfigUSE_DHCPv6 != 0 ) && ( ipconfigUSE_IPv6 != 0 ) )
886                         if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
887                         {
888                             vDHCPv6Process( pdTRUE, pxEndPoint );
889                         }
890                         else
891                     #endif /* (( ipconfigUSE_DHCPv6 != 0 ) && ( ipconfigUSE_IPv6 != 0 )) */
892                     {
893                         /* Reset the DHCP process for this end-point. */
894                         vDHCPProcess( pdTRUE, pxEndPoint );
895                     }
896                 }
897                 else /* Yes this else ought to be here. */
898             #endif /* ( ipconfigUSE_DHCP == 1 ) */
899 
900             #if ( ( ipconfigUSE_RA != 0 ) && ( ipconfigUSE_IPv6 != 0 ) )
901                 if( END_POINT_USES_RA( pxEndPoint ) )
902                 {
903                     /* Reset the RA/SLAAC process for this end-point. */
904                     vRAProcess( pdTRUE, pxEndPoint );
905                 }
906                 else
907             #endif /* ( (ipconfigUSE_RA != 0) && ( ipconfigUSE_IPv6 != 0 )) */
908 
909             {
910                 switch( pxEndPoint->bits.bIPv6 ) /* LCOV_EXCL_BR_LINE */
911                 {
912                     #if ( ipconfigUSE_IPv4 != 0 )
913                         case pdFALSE_UNSIGNED:
914                             ( void ) memcpy( &( pxEndPoint->ipv4_settings ), &( pxEndPoint->ipv4_defaults ), sizeof( pxEndPoint->ipv4_settings ) );
915                             break;
916                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
917 
918                     #if ( ipconfigUSE_IPv6 != 0 )
919                         case pdTRUE_UNSIGNED:
920                             ( void ) memcpy( &( pxEndPoint->ipv6_settings ), &( pxEndPoint->ipv6_defaults ), sizeof( pxEndPoint->ipv6_settings ) );
921                             break;
922                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
923 
924                     default:
925                         /* MISRA 16.4 Compliance */
926                         break;
927                 }
928 
929                 *ipLOCAL_IP_ADDRESS_POINTER = pxEndPoint->ipv4_settings.ulIPAddress;
930 
931                 /* DHCP or Router Advertisement are not enabled for this end-point.
932                  * Perform any necessary 'network up' processing. */
933                 vIPNetworkUpCalls( pxEndPoint );
934             }
935         }
936     }
937     else
938     {
939         /* Nothing to do. When the 'xNetworkTimer' expires, all interfaces
940          * with bits.bInterfaceUp cleared will get a new 'eNetworkDownEvent' */
941     }
942 }
943 /*-----------------------------------------------------------*/
944 
945 /**
946  * @brief Check the values of configuration options and assert on it. Also verify that the IP-task
947  *        has not already been initialized.
948  */
vPreCheckConfigs(void)949 void vPreCheckConfigs( void )
950 {
951     /* This function should only be called once. */
952     configASSERT( xIPIsNetworkTaskReady() == pdFALSE );
953     configASSERT( xNetworkEventQueue == NULL );
954     configASSERT( FreeRTOS_GetIPTaskHandle() == NULL );
955 
956     #if ( configASSERT_DEFINED == 1 )
957         {
958             volatile size_t uxSize = sizeof( uintptr_t );
959 
960             if( uxSize == 8U )
961             {
962                 /* This is a 64-bit platform, make sure there is enough space in
963                  * pucEthernetBuffer to store a pointer and also make sure that the value of
964                  * ipconfigBUFFER_PADDING is such that (ipconfigBUFFER_PADDING + ipSIZE_OF_ETH_HEADER) is a
965                  * 32 bit (4 byte) aligned value, so that when incrementing the ethernet buffer with
966                  * (ipconfigBUFFER_PADDING + ipSIZE_OF_ETH_HEADER) bytes it lands in a 32 bit aligned address
967                  * which lets us efficiently access 32 bit values later in the packet. */
968                 configASSERT( ( ipconfigBUFFER_PADDING >= 14 ) && ( ( ( ( ipconfigBUFFER_PADDING ) + ( ipSIZE_OF_ETH_HEADER ) ) % 4 ) == 0 ) );
969             }
970 
971             /* LCOV_EXCL_BR_START */
972             uxSize = ipconfigNETWORK_MTU;
973             /* Check if MTU is big enough. */
974             configASSERT( uxSize >= ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER + ipconfigTCP_MSS ) );
975 
976             uxSize = sizeof( EthernetHeader_t );
977             /* Check structure packing is correct. */
978             configASSERT( uxSize == ipEXPECTED_EthernetHeader_t_SIZE );
979 
980             uxSize = sizeof( ARPHeader_t );
981             configASSERT( uxSize == ipEXPECTED_ARPHeader_t_SIZE );
982 
983             uxSize = sizeof( IPHeader_t );
984             configASSERT( uxSize == ipEXPECTED_IPHeader_t_SIZE );
985 
986             uxSize = sizeof( ICMPHeader_t );
987             configASSERT( uxSize == ipEXPECTED_ICMPHeader_t_SIZE );
988 
989             uxSize = sizeof( UDPHeader_t );
990             configASSERT( uxSize == ipEXPECTED_UDPHeader_t_SIZE );
991 
992             #if ipconfigUSE_TCP == 1
993                 {
994                     uxSize = sizeof( TCPHeader_t );
995                     configASSERT( uxSize == ( ipEXPECTED_TCPHeader_t_SIZE + ipSIZE_TCP_OPTIONS ) );
996                 }
997             #endif
998             /* LCOV_EXCL_BR_STOP */
999 
1000             /* ipIP_TYPE_OFFSET is used like so:
1001              * pxNetworkBuffer->pucEthernetBuffer[ 0 - ( BaseType_t ) ipIP_TYPE_OFFSET ] = IP-Version-Byte
1002              * It's value MUST be > 0. Otherwise, storing the IPv4 version byte
1003              * will overwrite the Ethernet header. */
1004             configASSERT( ipIP_TYPE_OFFSET > 0 );
1005         }
1006     #endif /* if ( configASSERT_DEFINED == 1 ) */
1007 }
1008 /*-----------------------------------------------------------*/
1009 
1010 /**
1011  * @brief Generate or check the protocol checksum of the data sent in the first parameter.
1012  *        At the same time, the length of the packet and the length of the different layers
1013  *        will be checked.
1014  *
1015  * @param[in] pucEthernetBuffer The Ethernet buffer for which the checksum is to be calculated
1016  *                               or checked.  'pucEthernetBuffer' is now non-const because the
1017  *                               function will set the checksum fields, in case 'xOutgoingPacket'
1018  *                               is pdTRUE.
1019  * @param[in] uxBufferLength the total number of bytes received, or the number of bytes written
1020  *                            in the packet buffer.
1021  * @param[in] xOutgoingPacket Whether this is an outgoing packet or not.
1022  *
1023  * @return When xOutgoingPacket is false: the error code can be either: ipINVALID_LENGTH,
1024  *         ipUNHANDLED_PROTOCOL, ipWRONG_CRC, or ipCORRECT_CRC.
1025  *         When xOutgoingPacket is true: either ipINVALID_LENGTH, ipUNHANDLED_PROTOCOL,
1026  *         or ipCORRECT_CRC.
1027  */
usGenerateProtocolChecksum(uint8_t * pucEthernetBuffer,size_t uxBufferLength,BaseType_t xOutgoingPacket)1028 uint16_t usGenerateProtocolChecksum( uint8_t * pucEthernetBuffer,
1029                                      size_t uxBufferLength,
1030                                      BaseType_t xOutgoingPacket )
1031 {
1032     struct xPacketSummary xSet;
1033 
1034     ( void ) memset( &( xSet ), 0, sizeof( xSet ) );
1035 
1036     DEBUG_DECLARE_TRACE_VARIABLE( BaseType_t, xLocation, 0 );
1037 
1038     #if ( ipconfigHAS_DEBUG_PRINTF != 0 )
1039         {
1040             xSet.pcType = "???";
1041         }
1042     #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
1043 
1044     configASSERT( ( ( ( IPPacket_t * ) pucEthernetBuffer )->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) ||
1045                   ( ( ( IPPacket_t * ) pucEthernetBuffer )->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE ) );
1046 
1047     /* Introduce a do-while loop to allow use of break statements.
1048      * Note: MISRA prohibits use of 'goto', thus replaced with breaks. */
1049     do
1050     {
1051         BaseType_t xResult = 0;
1052 
1053         /* Parse the packet length. */
1054         /* MISRA Ref 11.3.1 [Misaligned access] */
1055         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1056         /* coverity[misra_c_2012_rule_11_3_violation] */
1057         xSet.pxIPPacket = ( ( const IPPacket_t * ) pucEthernetBuffer );
1058 
1059         switch( xSet.pxIPPacket->xEthernetHeader.usFrameType ) /* LCOV_EXCL_BR_LINE */
1060         {
1061             #if ( ipconfigUSE_IPv4 != 0 )
1062                 case ipIPv4_FRAME_TYPE:
1063                     xResult = prvChecksumIPv4Checks( pucEthernetBuffer, uxBufferLength, &( xSet ) );
1064 
1065                     break;
1066             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1067 
1068             #if ( ipconfigUSE_IPv6 != 0 )
1069                 case ipIPv6_FRAME_TYPE:
1070                     /* MISRA Ref 11.3.1 [Misaligned access] */
1071                     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1072                     /* coverity[misra_c_2012_rule_11_3_violation] */
1073                     xSet.pxIPPacket_IPv6 = ( ( const IPHeader_IPv6_t * ) &( pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
1074 
1075                     xResult = prvChecksumIPv6Checks( pucEthernetBuffer, uxBufferLength, &( xSet ) );
1076                     break;
1077             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1078 
1079             default:
1080                 /* MISRA 16.4 Compliance */
1081                 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum: Undefined usFrameType %d\n", xSet.pxIPPacket->xEthernetHeader.usFrameType ) );
1082 
1083                 xSet.usChecksum = ipINVALID_LENGTH;
1084                 xResult = 1;
1085                 break;
1086         }
1087 
1088         if( xResult != 0 )
1089         {
1090             DEBUG_SET_TRACE_VARIABLE( xLocation, xResult );
1091             break;
1092         }
1093 
1094         {
1095             xResult = prvChecksumProtocolChecks( uxBufferLength, &( xSet ) );
1096 
1097             if( xResult != 0 )
1098             {
1099                 DEBUG_SET_TRACE_VARIABLE( xLocation, xResult );
1100                 break;
1101             }
1102         }
1103 
1104         /* The protocol and checksum field have been identified. Check the direction
1105          * of the packet. */
1106         if( xOutgoingPacket != pdFALSE )
1107         {
1108             /* This is an outgoing packet. Before calculating the checksum, set it
1109              * to zero. */
1110             prvSetChecksumInPacket( &( xSet ), 0 );
1111         }
1112         else if( ( prvGetChecksumFromPacket( &( xSet ) ) == 0U ) && ( xSet.ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
1113         {
1114             #if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 )
1115                 {
1116                     /* Sender hasn't set the checksum, drop the packet because
1117                      * ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS is not set. */
1118                     xSet.usChecksum = ipWRONG_CRC;
1119                 }
1120             #else /* if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
1121                 {
1122                     /* Sender hasn't set the checksum, no use to calculate it. */
1123                     xSet.usChecksum = ipCORRECT_CRC;
1124                 }
1125             #endif /* if ( ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS == 0 ) */
1126             DEBUG_SET_TRACE_VARIABLE( xLocation, 12 );
1127             break;
1128         }
1129         else
1130         {
1131             /* This is an incoming packet, not being an UDP packet without a checksum. */
1132         }
1133 
1134         xResult = prvChecksumProtocolMTUCheck( &( xSet ) );
1135 
1136         if( xResult != 0 )
1137         {
1138             DEBUG_SET_TRACE_VARIABLE( xLocation, xResult );
1139             break;
1140         }
1141 
1142         /* Do the actual calculations. */
1143         prvChecksumProtocolCalculate( xOutgoingPacket, pucEthernetBuffer, &( xSet ) );
1144 
1145         /* For outgoing packets, set the checksum in the packet,
1146          * for incoming packets: show logging in case an error occurred. */
1147         prvChecksumProtocolSetChecksum( xOutgoingPacket, pucEthernetBuffer, uxBufferLength, &( xSet ) );
1148 
1149         if( xOutgoingPacket != pdFALSE )
1150         {
1151             xSet.usChecksum = ( uint16_t ) ipCORRECT_CRC;
1152         }
1153     } while( ipFALSE_BOOL );
1154 
1155     #if ( ipconfigHAS_PRINTF == 1 )
1156         if( xLocation != 0 )
1157         {
1158             FreeRTOS_printf( ( "CRC error: %04x location %ld\n", xSet.usChecksum, xLocation ) );
1159         }
1160     #endif /* ( ipconfigHAS_PRINTF == 1 ) */
1161 
1162     return xSet.usChecksum;
1163 }
1164 /*-----------------------------------------------------------*/
1165 
1166 /**
1167  * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).
1168  * The checksum algorithm is described as:
1169  *   "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the
1170  *   header.  For purposes of computing the checksum, the value of the checksum field is zero."
1171  *
1172  * In a nutshell, that means that each 16-bit 'word' must be summed, after which
1173  * the number of 'carries' (overflows) is added to the result. If that addition
1174  * produces an overflow, that 'carry' must also be added to the final result. The final checksum
1175  * should be the bitwise 'not' (ones-complement) of the result if the packet is
1176  * meant to be transmitted, but this method simply returns the raw value, probably
1177  * because when a packet is received, the checksum is verified by checking that
1178  * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.
1179  *
1180  * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.
1181  * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit
1182  * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,
1183  * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.
1184  * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.
1185  * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found
1186  * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue
1187  * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:
1188  *   union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];
1189  *
1190  * Arguments:
1191  *   ulSum: This argument provides a value to initialise the progressive summation
1192  *   of the header's values to. It is often 0, but protocols like TCP or UDP
1193  *   can have pseudo-header fields which need to be included in the checksum.
1194  *   pucNextData: This argument contains the address of the first byte which this
1195  *   method should process. The method's memory iterator is initialised to this value.
1196  *   uxDataLengthBytes: This argument contains the number of bytes that this method
1197  *   should process.
1198  */
1199 
1200 /**
1201  * @brief Calculates the 16-bit checksum of an array of bytes
1202  *
1203  * @param[in] usSum The initial sum, obtained from earlier data.
1204  * @param[in] pucNextData The actual data.
1205  * @param[in] uxByteCount The number of bytes.
1206  *
1207  * @return The 16-bit one's complement of the one's complement sum of all 16-bit
1208  *         words in the header
1209  */
usGenerateChecksum(uint16_t usSum,const uint8_t * pucNextData,size_t uxByteCount)1210 uint16_t usGenerateChecksum( uint16_t usSum,
1211                              const uint8_t * pucNextData,
1212                              size_t uxByteCount )
1213 {
1214 /* MISRA/PC-lint doesn't like the use of unions. Here, they are a great
1215  * aid though to optimise the calculations. */
1216     xUnion32_t xSum2;
1217     xUnion32_t xSum;
1218     xUnion32_t xTerm;
1219     xUnionPtr_t xSource;
1220     uintptr_t uxAlignBits;
1221     uint32_t ulCarry = 0U;
1222     uint16_t usTemp;
1223     size_t uxDataLengthBytes = uxByteCount;
1224     size_t uxSize;
1225     uintptr_t ulX;
1226 
1227     /* Small MCUs often spend up to 30% of the time doing checksum calculations
1228     * This function is optimised for 32-bit CPUs; Each time it will try to fetch
1229     * 32-bits, sums it with an accumulator and counts the number of carries. */
1230 
1231     /* Swap the input (little endian platform only). */
1232     usTemp = FreeRTOS_ntohs( usSum );
1233     xSum.u32 = ( uint32_t ) usTemp;
1234     xTerm.u32 = 0U;
1235 
1236     xSource.u8ptr = pucNextData;
1237 
1238     /* MISRA Ref 11.4.3 [Casting pointer to int for verification] */
1239     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-114 */
1240     /* coverity[misra_c_2012_rule_11_4_violation] */
1241     uxAlignBits = ( ( ( uintptr_t ) pucNextData ) & 0x03U );
1242 
1243     /*
1244      * If pucNextData is non-aligned then the checksum is starting at an
1245      * odd position and we need to make sure the usSum value now in xSum is
1246      * as if it had been "aligned" in the same way.
1247      */
1248     if( ( uxAlignBits & 1U ) != 0U )
1249     {
1250         xSum.u32 = ( ( xSum.u32 & 0xffU ) << 8 ) | ( ( xSum.u32 & 0xff00U ) >> 8 );
1251     }
1252 
1253     /* If byte (8-bit) aligned... */
1254     if( ( ( uxAlignBits & 1U ) != 0U ) && ( uxDataLengthBytes >= ( size_t ) 1U ) )
1255     {
1256         xTerm.u8[ 1 ] = *( xSource.u8ptr );
1257         xSource.u8ptr++;
1258         uxDataLengthBytes--;
1259         /* Now xSource is word (16-bit) aligned. */
1260     }
1261 
1262     /* If half-word (16-bit) aligned... */
1263     if( ( ( uxAlignBits == 1U ) || ( uxAlignBits == 2U ) ) && ( uxDataLengthBytes >= 2U ) )
1264     {
1265         xSum.u32 += *( xSource.u16ptr );
1266         xSource.u16ptr++;
1267         uxDataLengthBytes -= 2U;
1268         /* Now xSource is word (32-bit) aligned. */
1269     }
1270 
1271     /* Word (32-bit) aligned, do the most part. */
1272 
1273     uxSize = ( size_t ) ( ( uxDataLengthBytes / 4U ) * 4U );
1274 
1275     if( uxSize >= ( 3U * sizeof( uint32_t ) ) )
1276     {
1277         uxSize -= ( 3U * sizeof( uint32_t ) );
1278     }
1279     else
1280     {
1281         uxSize = 0U;
1282     }
1283 
1284     /* In this loop, four 32-bit additions will be done, in total 16 bytes.
1285      * Indexing with constants (0,1,2,3) gives faster code than using
1286      * post-increments. */
1287     for( ulX = 0U; ulX < uxSize; ulX += 4U * sizeof( uint32_t ) )
1288     {
1289         /* Use a secondary Sum2, just to see if the addition produced an
1290          * overflow. */
1291         xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];
1292 
1293         if( xSum2.u32 < xSum.u32 )
1294         {
1295             ulCarry++;
1296         }
1297 
1298         /* Now add the secondary sum to the major sum, and remember if there was
1299          * a carry. */
1300         xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];
1301 
1302         if( xSum2.u32 > xSum.u32 )
1303         {
1304             ulCarry++;
1305         }
1306 
1307         /* And do the same trick once again for indexes 2 and 3 */
1308         xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];
1309 
1310         if( xSum2.u32 < xSum.u32 )
1311         {
1312             ulCarry++;
1313         }
1314 
1315         xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];
1316 
1317         if( xSum2.u32 > xSum.u32 )
1318         {
1319             ulCarry++;
1320         }
1321 
1322         /* And finally advance the pointer 4 * 4 = 16 bytes. */
1323         xSource.u32ptr = &( xSource.u32ptr[ 4 ] );
1324     }
1325 
1326     /* Now add all carries. */
1327     xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;
1328 
1329     uxDataLengthBytes %= 16U;
1330 
1331     /* Half-word aligned. */
1332     uxSize = ( ( uxDataLengthBytes & ~( ( size_t ) 1U ) ) );
1333 
1334     for( ulX = 0U; ulX < uxSize; ulX += 1U * sizeof( uint16_t ) )
1335     {
1336         /* At least one more short. */
1337         xSum.u32 += xSource.u16ptr[ 0 ];
1338         xSource.u16ptr = &xSource.u16ptr[ 1 ];
1339     }
1340 
1341     if( ( uxDataLengthBytes & ( size_t ) 1U ) != 0U ) /* Maybe one more ? */
1342     {
1343         xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];
1344     }
1345 
1346     /* MISRA Ref 2.2.1 [Unions and dead code] */
1347     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-22 */
1348     /* coverity[misra_c_2012_rule_2_2_violation] */
1349     /* coverity[assigned_value] */
1350     xSum.u32 += xTerm.u32;
1351 
1352     /* Now add all carries again. */
1353 
1354     /* Assigning value from "xTerm.u32" to "xSum.u32" here, but that stored value is overwritten before it can be used. */
1355     /* MISRA Ref 2.2.1 [Unions and dead code] */
1356     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-22 */
1357     /* coverity[misra_c_2012_rule_2_2_violation] */
1358     /* coverity[value_overwrite] */
1359     xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
1360 
1361     /* MISRA Ref 2.2.1 [Unions and dead code] */
1362     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-22 */
1363     /* coverity[misra_c_2012_rule_2_2_violation] */
1364     /* coverity[value_overwrite] */
1365     xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
1366 
1367     if( ( uxAlignBits & 1U ) != 0U )
1368     {
1369         /* Quite unlikely, but pucNextData might be non-aligned, which would
1370         * mean that a checksum is calculated starting at an odd position. */
1371         xSum.u32 = ( ( xSum.u32 & 0xffU ) << 8 ) | ( ( xSum.u32 & 0xff00U ) >> 8 );
1372     }
1373 
1374     /* swap the output (little endian platform only). */
1375     return FreeRTOS_htons( ( ( uint16_t ) xSum.u32 ) );
1376 }
1377 /*-----------------------------------------------------------*/
1378 
1379 #if ( ipconfigHAS_PRINTF != 0 )
1380 
1381     #ifndef ipMONITOR_MAX_HEAP
1382 
1383 /* As long as the heap has more space than e.g. 1 MB, there
1384  * will be no messages. */
1385         #define ipMONITOR_MAX_HEAP    ( 1024U * 1024U )
1386     #endif /* ipMONITOR_MAX_HEAP */
1387 
1388     #ifndef ipMONITOR_PERCENTAGE_90
1389         /* Make this number lower to get less logging messages. */
1390         #define ipMONITOR_PERCENTAGE_90    ( 90U )
1391     #endif
1392 
1393     #define ipMONITOR_PERCENTAGE_100       ( 100U )
1394 
1395 /**
1396  * @brief A function that monitors a three resources: the heap, the space in the message
1397  *        queue of the IP-task, the number of available network buffer descriptors.
1398  */
vPrintResourceStats(void)1399     void vPrintResourceStats( void )
1400     {
1401         UBaseType_t uxCurrentBufferCount;
1402         size_t uxMinSize;
1403 
1404         /* When setting up and testing a project with FreeRTOS+TCP, it is
1405          * can be helpful to monitor a few resources: the number of network
1406          * buffers and the amount of available heap.
1407          * This function will issue some logging when a minimum value has
1408          * changed. */
1409         uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers();
1410 
1411         if( uxLastMinBufferCount > uxCurrentBufferCount )
1412         {
1413             /* The logging produced below may be helpful
1414              * while tuning +TCP: see how many buffers are in use. */
1415             uxLastMinBufferCount = uxCurrentBufferCount;
1416             FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
1417                                uxGetNumberOfFreeNetworkBuffers(),
1418                                uxCurrentBufferCount ) );
1419         }
1420 
1421         uxMinSize = xPortGetMinimumEverFreeHeapSize();
1422 
1423         if( uxMinLastSize == 0U )
1424         {
1425             /* Probably the first time this function is called. */
1426             uxMinLastSize = uxMinSize;
1427         }
1428         else if( uxMinSize >= ipMONITOR_MAX_HEAP )
1429         {
1430             /* There is more than enough heap space. No need for logging. */
1431         }
1432         /* Write logging if there is a 10% decrease since the last time logging was written. */
1433         else if( ( uxMinLastSize * ipMONITOR_PERCENTAGE_90 ) > ( uxMinSize * ipMONITOR_PERCENTAGE_100 ) )
1434         {
1435             uxMinLastSize = uxMinSize;
1436             FreeRTOS_printf( ( "Heap: current %u lowest %u\n", ( unsigned ) xPortGetFreeHeapSize(), ( unsigned ) uxMinSize ) );
1437         }
1438         else
1439         {
1440             /* Nothing to log. */
1441         }
1442 
1443         #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
1444             {
1445                 UBaseType_t uxCurrentCount = 0u;
1446 
1447                 uxCurrentCount = uxGetMinimumIPQueueSpace();
1448 
1449                 if( uxLastMinQueueSpace != uxCurrentCount )
1450                 {
1451                     /* The logging produced below may be helpful
1452                      * while tuning +TCP: see how many buffers are in use. */
1453                     uxLastMinQueueSpace = uxCurrentCount;
1454                     FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
1455                 }
1456             }
1457         #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
1458     }
1459 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
1460 /*-----------------------------------------------------------*/
1461 
1462 /**
1463  * @brief Utility function: Convert error number to a human readable
1464  *        string. Declaration in FreeRTOS_errno_TCP.h.
1465  *
1466  * @param[in] xErrnum The error number.
1467  * @param[in] pcBuffer Buffer big enough to be filled with the human readable message.
1468  * @param[in] uxLength Maximum length of the buffer.
1469  *
1470  * @return The buffer filled with human readable error string.
1471  */
1472 
FreeRTOS_strerror_r(BaseType_t xErrnum,char * pcBuffer,size_t uxLength)1473 const char * FreeRTOS_strerror_r( BaseType_t xErrnum,
1474                                   char * pcBuffer,
1475                                   size_t uxLength )
1476 {
1477     const char * pcName;
1478     BaseType_t xErrnumPositive = xErrnum;
1479 
1480     if( xErrnumPositive < 0 )
1481     {
1482         xErrnumPositive = -xErrnumPositive;
1483     }
1484 
1485     switch( xErrnumPositive )
1486     {
1487         case pdFREERTOS_ERRNO_EADDRINUSE:
1488             pcName = "EADDRINUSE";
1489             break;
1490 
1491         case pdFREERTOS_ERRNO_ENOMEM:
1492             pcName = "ENOMEM";
1493             break;
1494 
1495         case pdFREERTOS_ERRNO_EADDRNOTAVAIL:
1496             pcName = "EADDRNOTAVAIL";
1497             break;
1498 
1499         case pdFREERTOS_ERRNO_ENOPROTOOPT:
1500             pcName = "ENOPROTOOPT";
1501             break;
1502 
1503         case pdFREERTOS_ERRNO_EBADF:
1504             pcName = "EBADF";
1505             break;
1506 
1507         case pdFREERTOS_ERRNO_ENOSPC:
1508             pcName = "ENOSPC";
1509             break;
1510 
1511         case pdFREERTOS_ERRNO_ECANCELED:
1512             pcName = "ECANCELED";
1513             break;
1514 
1515         case pdFREERTOS_ERRNO_ENOTCONN:
1516             pcName = "ENOTCONN";
1517             break;
1518 
1519         case pdFREERTOS_ERRNO_EINPROGRESS:
1520             pcName = "EINPROGRESS";
1521             break;
1522 
1523         case pdFREERTOS_ERRNO_EOPNOTSUPP:
1524             pcName = "EOPNOTSUPP";
1525             break;
1526 
1527         case pdFREERTOS_ERRNO_EINTR:
1528             pcName = "EINTR";
1529             break;
1530 
1531         case pdFREERTOS_ERRNO_ETIMEDOUT:
1532             pcName = "ETIMEDOUT";
1533             break;
1534 
1535         case pdFREERTOS_ERRNO_EINVAL:
1536             pcName = "EINVAL";
1537             break;
1538 
1539         case pdFREERTOS_ERRNO_EWOULDBLOCK:
1540             pcName = "EWOULDBLOCK";
1541             break; /* same as EAGAIN */
1542 
1543         case pdFREERTOS_ERRNO_EISCONN:
1544             pcName = "EISCONN";
1545             break;
1546 
1547         default:
1548             /* MISRA Ref 21.6.1 [snprintf and logging] */
1549             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */
1550             /* coverity[misra_c_2012_rule_21_6_violation] */
1551             ( void ) snprintf( pcBuffer, uxLength, "Errno 0x%lx", xErrnum );
1552             pcName = NULL;
1553             break;
1554     }
1555 
1556     if( pcName != NULL )
1557     {
1558         /* MISRA Ref 21.6.1 [snprintf and logging] */
1559         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-216 */
1560         /* coverity[misra_c_2012_rule_21_6_violation] */
1561         ( void ) snprintf( pcBuffer, uxLength, "%s", pcName );
1562     }
1563 
1564     if( uxLength > 0U )
1565     {
1566         pcBuffer[ uxLength - 1U ] = '\0';
1567     }
1568 
1569     return pcBuffer;
1570 }
1571 /*-----------------------------------------------------------*/
1572 
1573 /**
1574  * @brief Get the highest value of two int32's.
1575  * @param[in] a the first value.
1576  * @param[in] b the second value.
1577  * @return The highest of the two values.
1578  */
FreeRTOS_max_int32(int32_t a,int32_t b)1579 int32_t FreeRTOS_max_int32( int32_t a,
1580                             int32_t b )
1581 {
1582     return ( a >= b ) ? a : b;
1583 }
1584 /*-----------------------------------------------------------*/
1585 
1586 /**
1587  * @brief Get the highest value of two uint32_t's.
1588  * @param[in] a the first value.
1589  * @param[in] b the second value.
1590  * @return The highest of the two values.
1591  */
FreeRTOS_max_uint32(uint32_t a,uint32_t b)1592 uint32_t FreeRTOS_max_uint32( uint32_t a,
1593                               uint32_t b )
1594 {
1595     return ( a >= b ) ? a : b;
1596 }
1597 /*-----------------------------------------------------------*/
1598 
1599 /**
1600  * @brief Get the highest value of two size_t's.
1601  * @param[in] a the first value.
1602  * @param[in] b the second value.
1603  * @return The highest of the two values.
1604  */
FreeRTOS_max_size_t(size_t a,size_t b)1605 size_t FreeRTOS_max_size_t( size_t a,
1606                             size_t b )
1607 {
1608     return ( a >= b ) ? a : b;
1609 }
1610 /*-----------------------------------------------------------*/
1611 
1612 /**
1613  * @brief Get the lowest value of two int32_t's.
1614  * @param[in] a the first value.
1615  * @param[in] b the second value.
1616  * @return The lowest of the two values.
1617  */
FreeRTOS_min_int32(int32_t a,int32_t b)1618 int32_t FreeRTOS_min_int32( int32_t a,
1619                             int32_t b )
1620 {
1621     return ( a <= b ) ? a : b;
1622 }
1623 /*-----------------------------------------------------------*/
1624 
1625 /**
1626  * @brief Get the lowest value of two uint32_t's.
1627  * @param[in] a the first value.
1628  * @param[in] b the second value.
1629  * @return The lowest of the two values.
1630  */
FreeRTOS_min_uint32(uint32_t a,uint32_t b)1631 uint32_t FreeRTOS_min_uint32( uint32_t a,
1632                               uint32_t b )
1633 {
1634     return ( a <= b ) ? a : b;
1635 }
1636 /*-----------------------------------------------------------*/
1637 
1638 /**
1639  * @brief Get the lowest value of two size_t's.
1640  * @param[in] a the first value.
1641  * @param[in] b the second value.
1642  * @return The lowest of the two values.
1643  */
FreeRTOS_min_size_t(size_t a,size_t b)1644 size_t FreeRTOS_min_size_t( size_t a,
1645                             size_t b )
1646 {
1647     return ( a <= b ) ? a : b;
1648 }
1649 /*-----------------------------------------------------------*/
1650 
1651 /**
1652  * @brief Round-up a number to a multiple of 'd'.
1653  * @param[in] a the first value.
1654  * @param[in] d the second value.
1655  * @return A multiple of d.
1656  */
FreeRTOS_round_up(uint32_t a,uint32_t d)1657 uint32_t FreeRTOS_round_up( uint32_t a,
1658                             uint32_t d )
1659 {
1660     uint32_t ulResult = a;
1661 
1662     configASSERT( d != 0U );
1663 
1664     if( d != 0U )
1665     {
1666         ulResult = d * ( ( a + d - 1U ) / d );
1667     }
1668 
1669     return ulResult;
1670 }
1671 /*-----------------------------------------------------------*/
1672 
1673 /**
1674  * @brief Round-down a number to a multiple of 'd'.
1675  * @param[in] a the first value.
1676  * @param[in] d the second value.
1677  * @return A multiple of d.
1678  */
FreeRTOS_round_down(uint32_t a,uint32_t d)1679 uint32_t FreeRTOS_round_down( uint32_t a,
1680                               uint32_t d )
1681 {
1682     uint32_t ulResult = 0;
1683 
1684     configASSERT( d != 0U );
1685 
1686     if( d != 0U )
1687     {
1688         ulResult = d * ( a / d );
1689     }
1690 
1691     return ulResult;
1692 }
1693 /*-----------------------------------------------------------*/
1694 
1695 /**
1696  * @brief Convert character array (of size 4) to equivalent 32-bit value.
1697  * @param[in] pucPtr The character array.
1698  * @return 32-bit equivalent value extracted from the character array.
1699  *
1700  * @note Going by MISRA rules, these utility functions should not be defined
1701  *        if they are not being used anywhere. But their use depends on the
1702  *        application and hence these functions are defined unconditionally.
1703  */
ulChar2u32(const uint8_t * pucPtr)1704 uint32_t ulChar2u32( const uint8_t * pucPtr )
1705 {
1706     return ( ( ( uint32_t ) pucPtr[ 0 ] ) << 24 ) |
1707            ( ( ( uint32_t ) pucPtr[ 1 ] ) << 16 ) |
1708            ( ( ( uint32_t ) pucPtr[ 2 ] ) << 8 ) |
1709            ( ( ( uint32_t ) pucPtr[ 3 ] ) );
1710 }
1711 /*-----------------------------------------------------------*/
1712 
1713 /**
1714  * @brief Convert character array (of size 2) to equivalent 16-bit value.
1715  * @param[in] pucPtr The character array.
1716  * @return 16-bit equivalent value extracted from the character array.
1717  *
1718  * @note Going by MISRA rules, these utility functions should not be defined
1719  *        if they are not being used anywhere. But their use depends on the
1720  *        application and hence these functions are defined unconditionally.
1721  */
usChar2u16(const uint8_t * pucPtr)1722 uint16_t usChar2u16( const uint8_t * pucPtr )
1723 {
1724     return ( uint16_t )
1725            ( ( ( ( uint32_t ) pucPtr[ 0 ] ) << 8 ) |
1726              ( ( ( uint32_t ) pucPtr[ 1 ] ) ) );
1727 }
1728 /*-----------------------------------------------------------*/
1729