xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_UDP_IPv6.c (revision 574b646147a48c508a8bfc82181fd89ea89c8c17)
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_UDP_IPv6.c
30  * @brief This file has the source code for the UDP-IP functionality of the FreeRTOS+TCP
31  *        network stack.
32  */
33 
34 /* Standard includes. */
35 #include <stdint.h>
36 #include <stdio.h>
37 
38 /* FreeRTOS includes. */
39 #include "FreeRTOS.h"
40 #include "task.h"
41 #include "queue.h"
42 #include "semphr.h"
43 #include "event_groups.h"
44 #include "list.h"
45 
46 /* FreeRTOS+TCP includes. */
47 #include "FreeRTOS_IP.h"
48 #include "FreeRTOS_Sockets.h"
49 #include "FreeRTOS_IP_Private.h"
50 #include "FreeRTOS_UDP_IP.h"
51 #include "FreeRTOS_ARP.h"
52 #include "FreeRTOS_DNS.h"
53 #include "FreeRTOS_DHCP.h"
54 #include "FreeRTOS_ND.h"
55 #include "FreeRTOS_IP_Utils.h"
56 #include "NetworkInterface.h"
57 #include "NetworkBufferManagement.h"
58 
59 #if ( ipconfigUSE_DNS == 1 )
60     #include "FreeRTOS_DNS.h"
61 #endif
62 
63 /* Just make sure the contents doesn't get compiled if IPv6 is not enabled. */
64 /* *INDENT-OFF* */
65     #if( ipconfigUSE_IPv6 != 0 )
66 /* *INDENT-ON* */
67 
68 
69 /** @brief The expected IP version and header length coded into the IP header itself. */
70 #define ipIP_VERSION_AND_HEADER_LENGTH_BYTE    ( ( uint8_t ) 0x45 )
71 
72 /*-----------------------------------------------------------*/
73 
74 /* _HT_ this is a temporary aid while testing. In case an end-0point is not found,
75  * this function will return the first end-point of the required type,
76  * either 'ipTYPE_IPv4' or 'ipTYPE_IPv6' */
77 static NetworkEndPoint_t * pxGetEndpoint( BaseType_t xIPType,
78                                           BaseType_t xIsGlobal );
79 
80 /**
81  * @brief Get the first end point of the type (IPv4/IPv6) from the list
82  *        the list of end points.
83  *
84  * @param[in] xIPType IP type (ipTYPE_IPv6/ipTYPE_IPv4)
85  * @param[in] xIsGlobal when pdTRUE, an endpoint with a global address must be
86  *                      returned. When pdFALSE, a local-link endpoint is returned.
87  *                      This only applies to IPv6 endpoints.
88  *
89  * @returns Pointer to the first end point of the given IP type from the
90  *          list of end points.
91  */
pxGetEndpoint(BaseType_t xIPType,BaseType_t xIsGlobal)92 static NetworkEndPoint_t * pxGetEndpoint( BaseType_t xIPType,
93                                           BaseType_t xIsGlobal )
94 {
95     NetworkEndPoint_t * pxEndPoint;
96 
97     for( pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
98          pxEndPoint != NULL;
99          pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) )
100     {
101         if( xIPType == ( BaseType_t ) ipTYPE_IPv6 )
102         {
103             if( pxEndPoint->bits.bIPv6 != 0U )
104             {
105                 IPv6_Type_t eEndpointType = xIPv6_GetIPType( &( pxEndPoint->ipv6_settings.xIPAddress ) );
106                 BaseType_t xEndpointGlobal = ( eEndpointType == eIPv6_Global ) ? pdTRUE : pdFALSE;
107 
108                 if( xEndpointGlobal == xIsGlobal )
109                 {
110                     break;
111                 }
112             }
113         }
114     }
115 
116     return pxEndPoint;
117 }
118 
119 /**
120  * @brief This function is called in case the IP-address was not found,
121  *        i.e. in the cache 'eARPCacheMiss' was returned.
122  *        Either an ARP request or a Neighbour solicitation will be emitted.
123  *
124  * @param[in] pxNetworkBuffer  The network buffer carrying the UDP or ICMP packet.
125  *
126  * @param[out] pxLostBuffer  The pointee will be set to true in case the network packet got released
127  *                            ( the ownership was taken ).
128  */
prvStartLookup(NetworkBufferDescriptor_t * const pxNetworkBuffer,BaseType_t * pxLostBuffer)129 static eARPLookupResult_t prvStartLookup( NetworkBufferDescriptor_t * const pxNetworkBuffer,
130                                           BaseType_t * pxLostBuffer )
131 {
132     eARPLookupResult_t eReturned = eARPCacheMiss;
133     uint32_t ulIPAddress;
134 
135     /* MISRA Ref 11.3.1 [Misaligned access] */
136     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
137     /* coverity[misra_c_2012_rule_11_3_violation] */
138     const UDPPacket_t * pxUDPPacket = ( ( const UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
139 
140     if( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
141     {
142         FreeRTOS_printf( ( "Looking up %pip with%s end-point\n",
143                            ( void * ) pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes,
144                            ( pxNetworkBuffer->pxEndPoint != NULL ) ? "" : "out" ) );
145 
146         if( pxNetworkBuffer->pxEndPoint == NULL )
147         {
148             IPv6_Type_t eTargetType = xIPv6_GetIPType( &( pxNetworkBuffer->xIPAddress.xIP_IPv6 ) );
149             BaseType_t xIsGlobal = ( eTargetType == eIPv6_Global ) ? pdTRUE : pdFALSE;
150             pxNetworkBuffer->pxEndPoint = pxGetEndpoint( ( BaseType_t ) ipTYPE_IPv6, xIsGlobal );
151             FreeRTOS_printf( ( "prvStartLookup: Got an end-point: %s\n", pxNetworkBuffer->pxEndPoint ? "yes" : "no" ) );
152         }
153 
154         if( pxNetworkBuffer->pxEndPoint != NULL )
155         {
156             vNDSendNeighbourSolicitation( pxNetworkBuffer, &( pxNetworkBuffer->xIPAddress.xIP_IPv6 ) );
157 
158             /* pxNetworkBuffer has been sent and released.
159              * Make sure it won't be used again.. */
160             *pxLostBuffer = pdTRUE;
161         }
162     }
163     else
164     {
165         ulIPAddress = pxNetworkBuffer->xIPAddress.ulIP_IPv4;
166 
167         FreeRTOS_printf( ( "Looking up %xip with%s end-point\n",
168                            ( unsigned ) FreeRTOS_ntohl( pxNetworkBuffer->xIPAddress.ulIP_IPv4 ),
169                            ( pxNetworkBuffer->pxEndPoint != NULL ) ? "" : "out" ) );
170 
171         /* Add an entry to the ARP table with a null hardware address.
172          * This allows the ARP timer to know that an ARP reply is
173          * outstanding, and perform retransmissions if necessary. */
174         vARPRefreshCacheEntry( NULL, ulIPAddress, NULL );
175 
176         /* Generate an ARP for the required IP address. */
177         iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->xIPAddress.ulIP_IPv4 );
178 
179         /* 'ulIPAddress' might have become the address of the Gateway.
180          * Find the route again. */
181 
182         pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnNetMask( pxNetworkBuffer->xIPAddress.ulIP_IPv4, 11 );
183 
184         if( pxNetworkBuffer->pxEndPoint == NULL )
185         {
186             eReturned = eCantSendPacket;
187         }
188         else
189         {
190             pxNetworkBuffer->xIPAddress.ulIP_IPv4 = ulIPAddress;
191             vARPGenerateRequestPacket( pxNetworkBuffer );
192         }
193     }
194 
195     return eReturned;
196 }
197 /*-----------------------------------------------------------*/
198 
199 /**
200  * @brief Process the generated UDP packet and do other checks before sending the
201  *        packet such as ARP cache check and address resolution.
202  *
203  * @param[in] pxNetworkBuffer The network buffer carrying the packet.
204  */
vProcessGeneratedUDPPacket_IPv6(NetworkBufferDescriptor_t * const pxNetworkBuffer)205 void vProcessGeneratedUDPPacket_IPv6( NetworkBufferDescriptor_t * const pxNetworkBuffer )
206 {
207     UDPPacket_IPv6_t * pxUDPPacket_IPv6;
208     IPHeader_IPv6_t * pxIPHeader_IPv6;
209     eARPLookupResult_t eReturned;
210     size_t uxPayloadSize;
211     /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
212     NetworkInterface_t * pxInterface = NULL;
213     EthernetHeader_t * pxEthernetHeader = NULL;
214     BaseType_t xLostBuffer = pdFALSE;
215     NetworkEndPoint_t * pxEndPoint = NULL;
216     IPv6_Address_t xIPv6Address;
217 
218     /* Map the UDP packet onto the start of the frame. */
219 
220     /* MISRA Ref 11.3.1 [Misaligned access] */
221     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
222     /* coverity[misra_c_2012_rule_11_3_violation] */
223     pxUDPPacket_IPv6 = ( ( UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
224     pxIPHeader_IPv6 = &( pxUDPPacket_IPv6->xIPHeader );
225 
226     /* Remember the original address. It might get replaced with
227      * the address of the gateway. */
228     ( void ) memcpy( xIPv6Address.ucBytes, pxNetworkBuffer->xIPAddress.xIP_IPv6.ucBytes, sizeof( xIPv6Address.ucBytes ) );
229 
230     #if ipconfigSUPPORT_OUTGOING_PINGS == 1
231         if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
232         {
233             size_t uxHeadersSize = sizeof( EthernetHeader_t ) + sizeof( IPHeader_IPv6_t ) + sizeof( ICMPHeader_t );
234             uxPayloadSize = pxNetworkBuffer->xDataLength - uxHeadersSize;
235         }
236         else
237     #endif
238     {
239         uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_IPv6_t );
240     }
241 
242     /* Look in the IPv6 MAC-address cache for the target IP-address. */
243     eReturned = eNDGetCacheEntry( &( pxNetworkBuffer->xIPAddress.xIP_IPv6 ), &( pxUDPPacket_IPv6->xEthernetHeader.xDestinationAddress ),
244                                   &( pxEndPoint ) );
245 
246     if( eReturned != eCantSendPacket )
247     {
248         if( eReturned == eARPCacheHit )
249         {
250             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
251                 uint8_t ucSocketOptions;
252             #endif
253             iptraceSENDING_UDP_PACKET( pxNetworkBuffer->xIPAddress.ulIP_IPv4 );
254 
255             pxNetworkBuffer->pxEndPoint = pxEndPoint;
256 
257             #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
258 
259                 /* Is it possible that the packet is not actually a UDP packet
260                  * after all, but an ICMP packet. */
261                 if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
262                 {
263                     pxIPHeader_IPv6->ucVersionTrafficClass = 0x60;
264                     pxIPHeader_IPv6->ucNextHeader = ipPROTOCOL_ICMP_IPv6;
265                     pxIPHeader_IPv6->ucHopLimit = 128;
266                 }
267                 else
268             #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
269             {
270                 UDPHeader_t * pxUDPHeader = NULL;
271 
272                 pxUDPHeader = &( pxUDPPacket_IPv6->xUDPHeader );
273 
274                 pxIPHeader_IPv6->ucVersionTrafficClass = 0x60;
275                 pxIPHeader_IPv6->ucTrafficClassFlow = 0;
276                 pxIPHeader_IPv6->usFlowLabel = 0;
277                 pxIPHeader_IPv6->ucHopLimit = 255;
278                 pxUDPHeader->usLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength - ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ) );
279 
280                 pxIPHeader_IPv6->ucNextHeader = ipPROTOCOL_UDP;
281                 pxIPHeader_IPv6->usPayloadLength = ( uint16_t ) ( pxNetworkBuffer->xDataLength - sizeof( IPPacket_IPv6_t ) );
282                 /* The total transmit size adds on the Ethernet header. */
283                 pxIPHeader_IPv6->usPayloadLength = FreeRTOS_htons( pxIPHeader_IPv6->usPayloadLength );
284 
285                 pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
286                 pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
287                 pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
288                 pxUDPHeader->usChecksum = 0U;
289 
290                 if( pxNetworkBuffer->pxEndPoint != NULL )
291                 {
292                     ( void ) memcpy( pxIPHeader_IPv6->xSourceAddress.ucBytes,
293                                      pxNetworkBuffer->pxEndPoint->ipv6_settings.xIPAddress.ucBytes,
294                                      ipSIZE_OF_IPv6_ADDRESS );
295                 }
296             }
297 
298             /* memcpy() the constant parts of the header information into
299              * the correct location within the packet.  This fills in:
300              *  xEthernetHeader.xSourceAddress
301              *  xEthernetHeader.usFrameType
302              *  xIPHeader.ucVersionHeaderLength
303              *  xIPHeader.ucDifferentiatedServicesCode
304              *  xIPHeader.usLength
305              *  xIPHeader.usIdentification
306              *  xIPHeader.usFragmentOffset
307              *  xIPHeader.ucTimeToLive
308              *  xIPHeader.ucProtocol
309              * and
310              *  xIPHeader.usHeaderChecksum
311              */
312 
313             /* Save options now, as they will be overwritten by memcpy */
314             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
315                 {
316                     ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
317                 }
318             #endif
319 
320             #if ipconfigSUPPORT_OUTGOING_PINGS == 1
321                 if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
322                 {
323                     pxIPHeader_IPv6->usPayloadLength = FreeRTOS_htons( sizeof( ICMPEcho_IPv6_t ) + uxPayloadSize );
324                 }
325                 else
326             #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
327             {
328                 pxIPHeader_IPv6->ucNextHeader = ipPROTOCOL_UDP;
329                 pxIPHeader_IPv6->usPayloadLength = FreeRTOS_htons( sizeof( UDPHeader_t ) + uxPayloadSize );
330             }
331 
332             #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
333                 {
334                     if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0U )
335                     {
336                         ( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxUDPPacket_IPv6, pxNetworkBuffer->xDataLength, pdTRUE );
337                     }
338                     else
339                     {
340                         pxUDPPacket_IPv6->xUDPHeader.usChecksum = 0U;
341                     }
342                 }
343             #endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */
344         }
345         else if( eReturned == eARPCacheMiss )
346         {
347             if( pxEndPoint != NULL )
348             {
349                 pxNetworkBuffer->pxEndPoint = pxEndPoint;
350             }
351 
352             eReturned = prvStartLookup( pxNetworkBuffer, &( xLostBuffer ) );
353         }
354         else
355         {
356             /* The lookup indicated that an ARP request has already been
357              * sent out for the queried IP address. */
358             eReturned = eCantSendPacket;
359         }
360     }
361 
362     if( xLostBuffer == pdTRUE )
363     {
364         /* An ND solicitation or ARP request has been sent. */
365     }
366     else if( eReturned != eCantSendPacket )
367     {
368         /* The network driver is responsible for freeing the network buffer
369          * after the packet has been sent. */
370 
371         if( pxNetworkBuffer->pxEndPoint != NULL )
372         {
373             pxInterface = pxNetworkBuffer->pxEndPoint->pxNetworkInterface;
374             /* MISRA Ref 11.3.1 [Misaligned access] */
375             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
376             /* coverity[misra_c_2012_rule_11_3_violation] */
377             pxEthernetHeader = ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
378             ( void ) memcpy( pxEthernetHeader->xSourceAddress.ucBytes,
379                              pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes,
380                              ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
381 
382             #if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
383                 {
384                     if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
385                     {
386                         BaseType_t xIndex;
387 
388                         for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
389                         {
390                             pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
391                         }
392 
393                         pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
394                     }
395                 }
396             #endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
397             iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
398             ( void ) pxInterface->pfOutput( pxInterface, pxNetworkBuffer, pdTRUE );
399         }
400         else
401         {
402             /* The packet can't be sent (no route found).  Drop the packet. */
403             vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
404         }
405     }
406     else
407     {
408         /* The packet can't be sent (DHCP not completed?).  Just drop the
409          * packet. */
410         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
411     }
412 }
413 /*-----------------------------------------------------------*/
414 
415 /**
416  * @brief Process the received UDP packet.
417  *
418  * @param[in] pxNetworkBuffer The network buffer carrying the UDP packet.
419  * @param[in] usPort The port number on which this packet was received.
420  * @param[out] pxIsWaitingForARPResolution If the packet is awaiting ARP resolution,
421  *             this pointer will be set to pdTRUE. pdFALSE otherwise.
422  *
423  * @return pdPASS in case the UDP packet could be processed. Else pdFAIL is returned.
424  */
xProcessReceivedUDPPacket_IPv6(NetworkBufferDescriptor_t * pxNetworkBuffer,uint16_t usPort,BaseType_t * pxIsWaitingForARPResolution)425 BaseType_t xProcessReceivedUDPPacket_IPv6( NetworkBufferDescriptor_t * pxNetworkBuffer,
426                                            uint16_t usPort,
427                                            BaseType_t * pxIsWaitingForARPResolution )
428 {
429     /* Returning pdPASS means that the packet was consumed, released. */
430     BaseType_t xReturn = pdPASS;
431     FreeRTOS_Socket_t * pxSocket;
432     const UDPPacket_IPv6_t * pxUDPPacket_IPv6;
433 
434     configASSERT( pxNetworkBuffer != NULL );
435     configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
436 
437     /* When refreshing the ARP/ND cache with received UDP packets we must be
438      * careful;  hundreds of broadcast messages may pass and if we're not
439      * handling them, no use to fill the cache with those IP addresses. */
440 
441     /* MISRA Ref 11.3.1 [Misaligned access] */
442     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
443     /* coverity[misra_c_2012_rule_11_3_violation] */
444     pxUDPPacket_IPv6 = ( ( UDPPacket_IPv6_t * ) pxNetworkBuffer->pucEthernetBuffer );
445 
446     /* Caller must check for minimum packet size. */
447     pxSocket = pxUDPSocketLookup( usPort );
448 
449     *pxIsWaitingForARPResolution = pdFALSE;
450 
451     do
452     {
453         /* UDPv6 doesn't allow zero-checksum, refer to RFC2460 - section 8.1.
454          * Some platforms (such as Zynq) pass the packet to upper layer for flexibility to allow zero-checksum. */
455         if( pxUDPPacket_IPv6->xUDPHeader.usChecksum == 0U )
456         {
457             FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket_IPv6: Drop packets with checksum %d\n",
458                                      pxUDPPacket_IPv6->xUDPHeader.usChecksum ) );
459 
460             xReturn = pdFAIL;
461             break;
462         }
463 
464         if( pxSocket != NULL )
465         {
466             if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )
467             {
468                 /* Mark this packet as waiting for ARP resolution. */
469                 *pxIsWaitingForARPResolution = pdTRUE;
470 
471                 /* Return a fail to show that the frame will not be processed right now. */
472                 xReturn = pdFAIL;
473                 break;
474             }
475 
476             vNDRefreshCacheEntry( &( pxUDPPacket_IPv6->xEthernetHeader.xSourceAddress ), &( pxUDPPacket_IPv6->xIPHeader.xSourceAddress ),
477                                   pxNetworkBuffer->pxEndPoint );
478 
479             #if ( ipconfigUSE_CALLBACKS == 1 )
480                 {
481                     size_t uxIPLength = uxIPHeaderSizePacket( pxNetworkBuffer );
482                     size_t uxPayloadSize;
483 
484                     /* Did the owner of this socket register a reception handler ? */
485                     if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
486                     {
487                         struct freertos_sockaddr xSourceAddress, destinationAddress;
488                         /* The application hook needs to know the from- and to-addresses. */
489 
490                         void * pcData = &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + uxIPLength + ipSIZE_OF_UDP_HEADER ] );
491                         FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
492 
493                         xSourceAddress.sin_port = pxNetworkBuffer->usPort;
494                         destinationAddress.sin_port = usPort;
495                         ( void ) memcpy( xSourceAddress.sin_address.xIP_IPv6.ucBytes, pxUDPPacket_IPv6->xIPHeader.xSourceAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
496                         ( void ) memcpy( destinationAddress.sin_address.xIP_IPv6.ucBytes, pxUDPPacket_IPv6->xIPHeader.xDestinationAddress.ucBytes, ipSIZE_OF_IPv6_ADDRESS );
497                         xSourceAddress.sin_family = ( uint8_t ) FREERTOS_AF_INET6;
498                         destinationAddress.sin_family = ( uint8_t ) FREERTOS_AF_INET6;
499                         xSourceAddress.sin_len = ( uint8_t ) sizeof( xSourceAddress );
500                         destinationAddress.sin_len = ( uint8_t ) sizeof( destinationAddress );
501                         uxPayloadSize = pxNetworkBuffer->xDataLength - ( ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER + ( size_t ) ipSIZE_OF_IPv6_HEADER );
502 
503                         /* The value of 'xDataLength' was proven to be at least the size of a UDP packet in prvProcessIPPacket(). */
504                         if( xHandler( ( Socket_t ) pxSocket,
505                                       ( void * ) pcData,
506                                       uxPayloadSize,
507                                       &( xSourceAddress ),
508                                       &( destinationAddress ) ) != 0 )
509                         {
510                             xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
511                         }
512                     }
513                 }
514             #endif /* ipconfigUSE_CALLBACKS */
515 
516             #if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
517                 {
518                     if( xReturn == pdPASS )
519                     {
520                         if( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
521                         {
522                             FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
523                                                      listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
524                                                      pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
525                             xReturn = pdFAIL; /* we did not consume or release the buffer */
526                         }
527                     }
528                 }
529             #endif /* if ( ipconfigUDP_MAX_RX_PACKETS > 0U ) */
530 
531             #if ( ipconfigUSE_CALLBACKS == 1 ) || ( ipconfigUDP_MAX_RX_PACKETS > 0U )
532                 if( xReturn == pdPASS ) /*lint !e774: Boolean within 'if' always evaluates to True, depending on configuration. [MISRA 2012 Rule 14.3, required. */
533             #else
534                 /* xReturn is still pdPASS. */
535             #endif
536             {
537                 vTaskSuspendAll();
538                 {
539                     taskENTER_CRITICAL();
540                     {
541                         /* Add the network packet to the list of packets to be
542                          * processed by the socket. */
543                         vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
544                     }
545                     taskEXIT_CRITICAL();
546                 }
547                 ( void ) xTaskResumeAll();
548 
549                 /* Set the socket's receive event */
550                 if( pxSocket->xEventGroup != NULL )
551                 {
552                     ( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
553                 }
554 
555                 #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
556                     {
557                         if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U ) )
558                         {
559                             ( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_READ );
560                         }
561                     }
562                 #endif
563 
564                 #if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
565                     {
566                         if( pxSocket->pxUserSemaphore != NULL )
567                         {
568                             ( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
569                         }
570                     }
571                 #endif
572 
573                 #if ( ipconfigUSE_DHCP == 1 )
574                     {
575                         if( xIsDHCPSocket( pxSocket ) != 0 )
576                         {
577                             ( void ) xSendDHCPEvent( pxNetworkBuffer->pxEndPoint );
578                         }
579                     }
580                 #endif
581             }
582         }
583         else
584         {
585             /* There is no socket listening to the target port, but still it might
586              * be for this node. */
587 
588             #if ( ipconfigUSE_DNS == 1 ) && ( ipconfigDNS_USE_CALLBACKS == 1 )
589 
590                 /* A DNS reply, check for the source port.  Although the DNS client
591                  * does open a UDP socket to send a messages, this socket will be
592                  * closed after a short timeout.  Messages that come late (after the
593                  * socket is closed) will be treated here. */
594                 if( FreeRTOS_ntohs( pxUDPPacket_IPv6->xUDPHeader.usSourcePort ) == ( uint16_t ) ipDNS_PORT )
595                 {
596                     xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
597                 }
598                 else
599             #endif
600 
601             #if ( ipconfigUSE_DNS == 1 ) && ( ipconfigUSE_LLMNR == 1 )
602                 /* A LLMNR request, check for the destination port. */
603                 if( ( usPort == FreeRTOS_htons( ipLLMNR_PORT ) ) ||
604                     ( pxUDPPacket_IPv6->xUDPHeader.usSourcePort == FreeRTOS_htons( ipLLMNR_PORT ) ) )
605                 {
606                     xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
607                 }
608                 else
609             #endif /* ipconfigUSE_LLMNR */
610 
611             #if ( ipconfigUSE_DNS == 1 ) && ( ipconfigUSE_MDNS == 1 )
612                 /* A MDNS request, check for the destination port. */
613                 if( ( usPort == FreeRTOS_ntohs( ipMDNS_PORT ) ) ||
614                     ( pxUDPPacket_IPv6->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipMDNS_PORT ) ) )
615                 {
616                     xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
617                 }
618                 else
619             #endif /* ipconfigUSE_MDNS */
620 
621             #if ( ipconfigUSE_NBNS == 1 )
622                 /* a NetBIOS request, check for the destination port */
623                 if( ( usPort == FreeRTOS_htons( ipNBNS_PORT ) ) ||
624                     ( pxUDPPacket_IPv6->xUDPHeader.usSourcePort == FreeRTOS_htons( ipNBNS_PORT ) ) )
625                 {
626                     xReturn = ( BaseType_t ) ulNBNSHandlePacket( pxNetworkBuffer );
627                 }
628                 else
629             #endif /* ipconfigUSE_NBNS */
630             {
631                 xReturn = pdFAIL;
632             }
633         }
634     } while( ipFALSE_BOOL );
635 
636     return xReturn;
637 }
638 /*-----------------------------------------------------------*/
639 
640 /* *INDENT-OFF* */
641     #endif /* ipconfigUSE_IPv6 != 0 ) */
642 /* *INDENT-ON* */
643