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