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