xref: /FreeRTOS-Plus-TCP-v4.0.0/source/FreeRTOS_IP.c (revision f5ecc5f201ba569467d090b79b19c5e0baead322)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 /**
29  * @file FreeRTOS_IP.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_ICMP.h"
47 #include "FreeRTOS_IP_Timers.h"
48 #include "FreeRTOS_IP_Utils.h"
49 #include "FreeRTOS_Sockets.h"
50 #include "FreeRTOS_IP_Private.h"
51 #include "FreeRTOS_ARP.h"
52 #include "FreeRTOS_UDP_IP.h"
53 #include "FreeRTOS_DHCP.h"
54 #if ( ipconfigUSE_DHCPv6 == 1 )
55     #include "FreeRTOS_DHCPv6.h"
56 #endif
57 #include "NetworkInterface.h"
58 #include "NetworkBufferManagement.h"
59 #include "FreeRTOS_DNS.h"
60 #include "FreeRTOS_Routing.h"
61 #include "FreeRTOS_ND.h"
62 
63 /** @brief Time delay between repeated attempts to initialise the network hardware. */
64 #ifndef ipINITIALISATION_RETRY_DELAY
65     #define ipINITIALISATION_RETRY_DELAY    ( pdMS_TO_TICKS( 3000U ) )
66 #endif
67 #if ( ipconfigUSE_TCP_MEM_STATS != 0 )
68     #include "tcp_mem_stats.h"
69 #endif
70 
71 /** @brief Maximum time to wait for an ARP resolution while holding a packet. */
72 #ifndef ipARP_RESOLUTION_MAX_DELAY
73     #define ipARP_RESOLUTION_MAX_DELAY    ( pdMS_TO_TICKS( 2000U ) )
74 #endif
75 
76 #ifndef iptraceIP_TASK_STARTING
77     #define iptraceIP_TASK_STARTING()    do {} while( ipFALSE_BOOL ) /**< Empty definition in case iptraceIP_TASK_STARTING is not defined. */
78 #endif
79 
80 #if ( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
81     /** @brief When initialising the TCP timer, give it an initial time-out of 1 second. */
82     #define ipTCP_TIMER_PERIOD_MS    ( 1000U )
83 #endif
84 
85 /** @brief Defines how often the ARP timer callback function is executed.  The time is
86  * shorter in the Windows simulator as simulated time is not real time. */
87 #ifndef ipARP_TIMER_PERIOD_MS
88     #ifdef _WINDOWS_
89         #define ipARP_TIMER_PERIOD_MS    ( 500U ) /* For windows simulator builds. */
90     #else
91         #define ipARP_TIMER_PERIOD_MS    ( 10000U )
92     #endif
93 #endif
94 
95 #if ( ipconfigUSE_TCP != 0 )
96 
97 /** @brief Set to a non-zero value if one or more TCP message have been processed
98  * within the last round. */
99     BaseType_t xProcessedTCPMessage;
100 #endif
101 
102 /** @brief If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
103  * driver will filter incoming packets and only pass the stack those packets it
104  * considers need processing.  In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
105  * be #-defined away.  If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
106  * then the Ethernet driver will pass all received packets to the stack, and the
107  * stack must do the filtering itself.  In this case ipCONSIDER_FRAME_FOR_PROCESSING
108  * needs to call eConsiderFrameForProcessing.
109  */
110 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
111     #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer )    eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
112 #else
113     #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer )    eProcessBuffer
114 #endif
115 
116 static void prvCallDHCP_RA_Handler( NetworkEndPoint_t * pxEndPoint );
117 
118 static void prvIPTask_Initialise( void );
119 
120 static void prvIPTask_CheckPendingEvents( void );
121 
122 /*-----------------------------------------------------------*/
123 
124 /** @brief The pointer to buffer with packet waiting for ARP resolution. */
125 NetworkBufferDescriptor_t * pxARPWaitingNetworkBuffer = NULL;
126 
127 /*-----------------------------------------------------------*/
128 
129 static void prvProcessIPEventsAndTimers( void );
130 
131 /*
132  * The main TCP/IP stack processing task.  This task receives commands/events
133  * from the network hardware drivers and tasks that are using sockets.  It also
134  * maintains a set of protocol timers.
135  */
136 static void prvIPTask( void * pvParameters );
137 
138 /*
139  * Called when new data is available from the network interface.
140  */
141 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
142 
143 #if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 )
144 
145 /*
146  * The stack will call this user hook for all Ethernet frames that it
147  * does not support, i.e. other than IPv4, IPv6 and ARP ( for the moment )
148  * If this hook returns eReleaseBuffer or eProcessBuffer, the stack will
149  * release and reuse the network buffer.  If this hook returns
150  * eReturnEthernetFrame, that means user code has reused the network buffer
151  * to generate a response and the stack will send that response out.
152  * If this hook returns eFrameConsumed, the user code has ownership of the
153  * network buffer and has to release it when it's done.
154  */
155     extern eFrameProcessingResult_t eApplicationProcessCustomFrameHook( NetworkBufferDescriptor_t * const pxNetworkBuffer );
156 #endif /* ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 ) */
157 
158 /*
159  * Process incoming IP packets.
160  */
161 static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacket,
162                                                     NetworkBufferDescriptor_t * const pxNetworkBuffer );
163 
164 /*
165  * The network card driver has received a packet.  In the case that it is part
166  * of a linked packet chain, walk through it to handle every message.
167  */
168 static void prvHandleEthernetPacket( NetworkBufferDescriptor_t * pxBuffer );
169 
170 /* Handle the 'eNetworkTxEvent': forward a packet from an application to the NIC. */
171 static void prvForwardTxPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
172                                 BaseType_t xReleaseAfterSend );
173 
174 static eFrameProcessingResult_t prvProcessUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
175 
176 /*-----------------------------------------------------------*/
177 
178 /** @brief The queue used to pass events into the IP-task for processing. */
179 QueueHandle_t xNetworkEventQueue = NULL;
180 
181 /** @brief The IP packet ID. */
182 uint16_t usPacketIdentifier = 0U;
183 
184 /** @brief For convenience, a MAC address of all 0xffs is defined const for quick
185  * reference. */
186 const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
187 
188 /** @brief Default values for the above struct in case DHCP
189  * does not lead to a confirmed request. */
190 
191 /* MISRA Ref 8.9.1 [File scoped variables] */
192 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-89 */
193 /* coverity[misra_c_2012_rule_8_9_violation] */
194 NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };
195 
196 /** @brief Used to ensure network down events cannot be missed when they cannot be
197  * posted to the network event queue because the network event queue is already
198  * full. */
199 static volatile BaseType_t xNetworkDownEventPending = pdFALSE;
200 
201 /** @brief Stores the handle of the task that handles the stack.  The handle is used
202  * (indirectly) by some utility function to determine if the utility function is
203  * being called by a task (in which case it is ok to block) or by the IP task
204  * itself (in which case it is not ok to block). */
205 
206 static TaskHandle_t xIPTaskHandle = NULL;
207 
208 /** @brief Set to pdTRUE when the IP task is ready to start processing packets. */
209 static BaseType_t xIPTaskInitialised = pdFALSE;
210 
211 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
212     /** @brief Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
213     static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;
214 #endif
215 
216 /*-----------------------------------------------------------*/
217 
218 /* Coverity wants to make pvParameters const, which would make it incompatible. Leave the
219  * function signature as is. */
220 
221 /**
222  * @brief The IP task handles all requests from the user application and the
223  *        network interface. It receives messages through a FreeRTOS queue called
224  *        'xNetworkEventQueue'. prvIPTask() is the only task which has access to
225  *        the data of the IP-stack, and so it has no need of using mutexes.
226  *
227  * @param[in] pvParameters Not used.
228  */
229 
230 /** @brief Stores interface structures. */
231 
232 /* MISRA Ref 8.13.1 [Not decorating a pointer to const parameter with const] */
233 /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-813 */
234 /* coverity[misra_c_2012_rule_8_13_violation] */
prvIPTask(void * pvParameters)235 static void prvIPTask( void * pvParameters )
236 {
237     /* Just to prevent compiler warnings about unused parameters. */
238     ( void ) pvParameters;
239 
240     prvIPTask_Initialise();
241 
242     FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );
243 
244     /* Loop, processing IP events. */
245     while( ipFOREVER() == pdTRUE )
246     {
247         prvProcessIPEventsAndTimers();
248     }
249 }
250 /*-----------------------------------------------------------*/
251 
252 /**
253  * @brief Process the events sent to the IP task and process the timers.
254  */
prvProcessIPEventsAndTimers(void)255 static void prvProcessIPEventsAndTimers( void )
256 {
257     IPStackEvent_t xReceivedEvent;
258     TickType_t xNextIPSleep;
259     FreeRTOS_Socket_t * pxSocket;
260     struct freertos_sockaddr xAddress;
261 
262     ipconfigWATCHDOG_TIMER();
263 
264     /* Check the ARP, DHCP and TCP timers to see if there is any periodic
265      * or timeout processing to perform. */
266     vCheckNetworkTimers();
267 
268     /* Calculate the acceptable maximum sleep time. */
269     xNextIPSleep = xCalculateSleepTime();
270 
271     /* Wait until there is something to do. If the following call exits
272      * due to a time out rather than a message being received, set a
273      * 'NoEvent' value. */
274     if( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
275     {
276         xReceivedEvent.eEventType = eNoEvent;
277     }
278 
279     #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
280         {
281             if( xReceivedEvent.eEventType != eNoEvent )
282             {
283                 UBaseType_t uxCount;
284 
285                 uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );
286 
287                 if( uxQueueMinimumSpace > uxCount )
288                 {
289                     uxQueueMinimumSpace = uxCount;
290                 }
291             }
292         }
293     #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
294 
295     iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
296 
297     switch( xReceivedEvent.eEventType )
298     {
299         case eNetworkDownEvent:
300             /* Attempt to establish a connection. */
301             prvProcessNetworkDownEvent( ( ( NetworkInterface_t * ) xReceivedEvent.pvData ) );
302             break;
303 
304         case eNetworkRxEvent:
305 
306             /* The network hardware driver has received a new packet.  A
307              * pointer to the received buffer is located in the pvData member
308              * of the received event structure. */
309             prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) xReceivedEvent.pvData );
310             break;
311 
312         case eNetworkTxEvent:
313 
314             /* Send a network packet. The ownership will  be transferred to
315              * the driver, which will release it after delivery. */
316             prvForwardTxPacket( ( ( NetworkBufferDescriptor_t * ) xReceivedEvent.pvData ), pdTRUE );
317             break;
318 
319         case eARPTimerEvent:
320             /* The ARP timer has expired, process the ARP cache. */
321             #if ( ipconfigUSE_IPv4 != 0 )
322                 vARPAgeCache();
323             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
324 
325             #if ( ipconfigUSE_IPv6 != 0 )
326                 vNDAgeCache();
327             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
328 
329             break;
330 
331         case eSocketBindEvent:
332 
333             /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
334              * to a port. The port number is communicated in the socket field
335              * usLocalPort. vSocketBind() will actually bind the socket and the
336              * API will unblock as soon as the eSOCKET_BOUND event is
337              * triggered. */
338             pxSocket = ( ( FreeRTOS_Socket_t * ) xReceivedEvent.pvData );
339             xAddress.sin_len = ( uint8_t ) sizeof( xAddress );
340 
341             switch( pxSocket->bits.bIsIPv6 ) /* LCOV_EXCL_BR_LINE */
342             {
343                 #if ( ipconfigUSE_IPv4 != 0 )
344                     case pdFALSE_UNSIGNED:
345                         xAddress.sin_family = FREERTOS_AF_INET;
346                         xAddress.sin_address.ulIP_IPv4 = FreeRTOS_htonl( pxSocket->xLocalAddress.ulIP_IPv4 );
347                         /* 'ulLocalAddress' will be set again by vSocketBind(). */
348                         pxSocket->xLocalAddress.ulIP_IPv4 = 0;
349                         break;
350                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
351 
352                 #if ( ipconfigUSE_IPv6 != 0 )
353                     case pdTRUE_UNSIGNED:
354                         xAddress.sin_family = FREERTOS_AF_INET6;
355                         ( void ) memcpy( xAddress.sin_address.xIP_IPv6.ucBytes, pxSocket->xLocalAddress.xIP_IPv6.ucBytes, sizeof( xAddress.sin_address.xIP_IPv6.ucBytes ) );
356                         /* 'ulLocalAddress' will be set again by vSocketBind(). */
357                         ( void ) memset( pxSocket->xLocalAddress.xIP_IPv6.ucBytes, 0, sizeof( pxSocket->xLocalAddress.xIP_IPv6.ucBytes ) );
358                         break;
359                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
360 
361                 default:
362                     /* MISRA 16.4 Compliance */
363                     break;
364             }
365 
366             xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
367             /* 'usLocalPort' will be set again by vSocketBind(). */
368             pxSocket->usLocalPort = 0U;
369             ( void ) vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );
370 
371             /* Before 'eSocketBindEvent' was sent it was tested that
372              * ( xEventGroup != NULL ) so it can be used now to wake up the
373              * user. */
374             pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_BOUND;
375             vSocketWakeUpUser( pxSocket );
376             break;
377 
378         case eSocketCloseEvent:
379 
380             /* The user API FreeRTOS_closesocket() has sent a message to the
381              * IP-task to actually close a socket. This is handled in
382              * vSocketClose().  As the socket gets closed, there is no way to
383              * report back to the API, so the API won't wait for the result */
384             ( void ) vSocketClose( ( ( FreeRTOS_Socket_t * ) xReceivedEvent.pvData ) );
385             break;
386 
387         case eStackTxEvent:
388 
389             /* The network stack has generated a packet to send.  A
390              * pointer to the generated buffer is located in the pvData
391              * member of the received event structure. */
392             vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) xReceivedEvent.pvData );
393             break;
394 
395         case eDHCPEvent:
396             prvCallDHCP_RA_Handler( ( ( NetworkEndPoint_t * ) xReceivedEvent.pvData ) );
397             break;
398 
399         case eSocketSelectEvent:
400 
401             /* FreeRTOS_select() has got unblocked by a socket event,
402              * vSocketSelect() will check which sockets actually have an event
403              * and update the socket field xSocketBits. */
404             #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
405                 #if ( ipconfigSELECT_USES_NOTIFY != 0 )
406                     {
407                         SocketSelectMessage_t * pxMessage = ( ( SocketSelectMessage_t * ) xReceivedEvent.pvData );
408                         vSocketSelect( pxMessage->pxSocketSet );
409                         ( void ) xTaskNotifyGive( pxMessage->xTaskhandle );
410                     }
411                 #else
412                     {
413                         vSocketSelect( ( ( SocketSelect_t * ) xReceivedEvent.pvData ) );
414                     }
415                 #endif /* ( ipconfigSELECT_USES_NOTIFY != 0 ) */
416             #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
417             break;
418 
419         case eSocketSignalEvent:
420             #if ( ipconfigSUPPORT_SIGNALS != 0 )
421 
422                 /* Some task wants to signal the user of this socket in
423                  * order to interrupt a call to recv() or a call to select(). */
424                 ( void ) FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData );
425             #endif /* ipconfigSUPPORT_SIGNALS */
426             break;
427 
428         case eTCPTimerEvent:
429             #if ( ipconfigUSE_TCP == 1 )
430 
431                 /* Simply mark the TCP timer as expired so it gets processed
432                  * the next time prvCheckNetworkTimers() is called. */
433                 vIPSetTCPTimerExpiredState( pdTRUE );
434             #endif /* ipconfigUSE_TCP */
435             break;
436 
437         case eTCPAcceptEvent:
438 
439             /* The API FreeRTOS_accept() was called, the IP-task will now
440              * check if the listening socket (communicated in pvData) actually
441              * received a new connection. */
442             #if ( ipconfigUSE_TCP == 1 )
443                 pxSocket = ( ( FreeRTOS_Socket_t * ) xReceivedEvent.pvData );
444 
445                 if( xTCPCheckNewClient( pxSocket ) != pdFALSE )
446                 {
447                     pxSocket->xEventBits |= ( EventBits_t ) eSOCKET_ACCEPT;
448                     vSocketWakeUpUser( pxSocket );
449                 }
450             #endif /* ipconfigUSE_TCP */
451             break;
452 
453         case eTCPNetStat:
454 
455             /* FreeRTOS_netstat() was called to have the IP-task print an
456              * overview of all sockets and their connections */
457             #if ( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )
458                 vTCPNetStat();
459             #endif /* ipconfigUSE_TCP */
460             break;
461 
462         case eSocketSetDeleteEvent:
463             #if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
464                 {
465                     SocketSelect_t * pxSocketSet = ( SocketSelect_t * ) ( xReceivedEvent.pvData );
466 
467                     iptraceMEM_STATS_DELETE( pxSocketSet );
468                     vEventGroupDelete( pxSocketSet->xSelectGroup );
469                     vPortFree( ( void * ) pxSocketSet );
470                 }
471             #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
472             break;
473 
474         case eNoEvent:
475             /* xQueueReceive() returned because of a normal time-out. */
476             break;
477 
478         default:
479             /* Should not get here. */
480             break;
481     }
482 
483     prvIPTask_CheckPendingEvents();
484 }
485 
486 /*-----------------------------------------------------------*/
487 
488 /**
489  * @brief Helper function for prvIPTask, it does the first initializations
490  *        at start-up. No parameters, no return type.
491  */
prvIPTask_Initialise(void)492 static void prvIPTask_Initialise( void )
493 {
494     NetworkInterface_t * pxInterface;
495 
496     /* A possibility to set some additional task properties. */
497     iptraceIP_TASK_STARTING();
498 
499     /* Generate a dummy message to say that the network connection has gone
500      * down.  This will cause this task to initialise the network interface.  After
501      * this it is the responsibility of the network interface hardware driver to
502      * send this message if a previously connected network is disconnected. */
503 
504     vNetworkTimerReload( pdMS_TO_TICKS( ipINITIALISATION_RETRY_DELAY ) );
505 
506     for( pxInterface = pxNetworkInterfaces; pxInterface != NULL; pxInterface = pxInterface->pxNext )
507     {
508         /* Post a 'eNetworkDownEvent' for every interface. */
509         FreeRTOS_NetworkDown( pxInterface );
510     }
511 
512     #if ( ipconfigUSE_TCP == 1 )
513         {
514             /* Initialise the TCP timer. */
515             vTCPTimerReload( pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
516         }
517     #endif
518 
519     /* Mark the timer as inactive since we are not waiting on any ARP resolution as of now. */
520     vIPSetARPResolutionTimerEnableState( pdFALSE );
521 
522     #if ( ( ipconfigDNS_USE_CALLBACKS != 0 ) && ( ipconfigUSE_DNS != 0 ) )
523         {
524             /* The following function is declared in FreeRTOS_DNS.c and 'private' to
525              * this library */
526             vDNSInitialise();
527         }
528     #endif /* ( ipconfigDNS_USE_CALLBACKS != 0 ) && ( ipconfigUSE_DNS != 0 ) */
529 
530     #if ( ( ipconfigUSE_DNS_CACHE != 0 ) && ( ipconfigUSE_DNS != 0 ) )
531         {
532             /* Clear the DNS cache once only. */
533             FreeRTOS_dnsclear();
534         }
535     #endif /* ( ( ipconfigUSE_DNS_CACHE != 0 ) && ( ipconfigUSE_DNS != 0 ) ) */
536 
537     /* Initialisation is complete and events can now be processed. */
538     xIPTaskInitialised = pdTRUE;
539 }
540 /*-----------------------------------------------------------*/
541 
542 /**
543  * @brief Check the value of 'xNetworkDownEventPending'. When non-zero, pending
544  *        network-down events will be handled.
545  */
prvIPTask_CheckPendingEvents(void)546 static void prvIPTask_CheckPendingEvents( void )
547 {
548     NetworkInterface_t * pxInterface;
549 
550     if( xNetworkDownEventPending != pdFALSE )
551     {
552         /* A network down event could not be posted to the network event
553          * queue because the queue was full.
554          * As this code runs in the IP-task, it can be done directly by
555          * calling prvProcessNetworkDownEvent(). */
556         xNetworkDownEventPending = pdFALSE;
557 
558         for( pxInterface = FreeRTOS_FirstNetworkInterface();
559              pxInterface != NULL;
560              pxInterface = FreeRTOS_NextNetworkInterface( pxInterface ) )
561         {
562             if( pxInterface->bits.bCallDownEvent != pdFALSE_UNSIGNED )
563             {
564                 prvProcessNetworkDownEvent( pxInterface );
565                 pxInterface->bits.bCallDownEvent = pdFALSE_UNSIGNED;
566             }
567         }
568     }
569 }
570 
571 /*-----------------------------------------------------------*/
572 
573 /**
574  * @brief Call the state machine of either DHCP, DHCPv6, or RA, whichever is activated.
575  *
576  * @param[in] pxEndPoint The end-point for which the state-machine will be called.
577  */
prvCallDHCP_RA_Handler(NetworkEndPoint_t * pxEndPoint)578 static void prvCallDHCP_RA_Handler( NetworkEndPoint_t * pxEndPoint )
579 {
580     BaseType_t xIsIPv6 = pdFALSE;
581 
582     #if ( ( ipconfigUSE_DHCP == 1 ) || ( ipconfigUSE_DHCPv6 == 1 ) || ( ipconfigUSE_RA == 1 ) )
583         if( pxEndPoint->bits.bIPv6 != pdFALSE_UNSIGNED )
584         {
585             xIsIPv6 = pdTRUE;
586         }
587     #endif
588     /* The DHCP state machine needs processing. */
589     #if ( ipconfigUSE_DHCP == 1 )
590         {
591             if( ( pxEndPoint->bits.bWantDHCP != pdFALSE_UNSIGNED ) && ( xIsIPv6 == pdFALSE ) )
592             {
593                 /* Process DHCP messages for a given end-point. */
594                 vDHCPProcess( pdFALSE, pxEndPoint );
595             }
596         }
597     #endif /* ipconfigUSE_DHCP */
598     #if ( ( ipconfigUSE_DHCPv6 == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
599         {
600             if( ( xIsIPv6 == pdTRUE ) && ( pxEndPoint->bits.bWantDHCP != pdFALSE_UNSIGNED ) )
601             {
602                 /* Process DHCPv6 messages for a given end-point. */
603                 vDHCPv6Process( pdFALSE, pxEndPoint );
604             }
605         }
606     #endif /* ipconfigUSE_DHCPv6 */
607     #if ( ( ipconfigUSE_RA == 1 ) && ( ipconfigUSE_IPv6 != 0 ) )
608         {
609             if( ( xIsIPv6 == pdTRUE ) && ( pxEndPoint->bits.bWantRA != pdFALSE_UNSIGNED ) )
610             {
611                 /* Process RA messages for a given end-point. */
612                 vRAProcess( pdFALSE, pxEndPoint );
613             }
614         }
615     #endif /* ( ( ipconfigUSE_RA == 1 ) && ( ipconfigUSE_IPv6 != 0 ) ) */
616 
617     /* Mention pxEndPoint and xIsIPv6 in case they have not been used. */
618     ( void ) pxEndPoint;
619     ( void ) xIsIPv6;
620 }
621 /*-----------------------------------------------------------*/
622 
623 /**
624  * @brief The variable 'xIPTaskHandle' is declared static.  This function
625  *        gives read-only access to it.
626  *
627  * @return The handle of the IP-task.
628  */
FreeRTOS_GetIPTaskHandle(void)629 TaskHandle_t FreeRTOS_GetIPTaskHandle( void )
630 {
631     return xIPTaskHandle;
632 }
633 /*-----------------------------------------------------------*/
634 
635 /**
636  * @brief Perform all the required tasks when the network gets connected.
637  *
638  * @param pxEndPoint The end-point which goes up.
639  */
vIPNetworkUpCalls(struct xNetworkEndPoint * pxEndPoint)640 void vIPNetworkUpCalls( struct xNetworkEndPoint * pxEndPoint )
641 {
642     pxEndPoint->bits.bEndPointUp = pdTRUE_UNSIGNED;
643 
644     #if ( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
645         #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
646             {
647                 vApplicationIPNetworkEventHook( eNetworkUp );
648             }
649         #else
650             {
651                 vApplicationIPNetworkEventHook_Multi( eNetworkUp, pxEndPoint );
652             }
653         #endif
654     #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
655 
656     #if ( ipconfigDNS_USE_CALLBACKS != 0 )
657         {
658             /* The following function is declared in FreeRTOS_DNS.c and 'private' to
659              * this library */
660             extern void vDNSInitialise( void );
661             vDNSInitialise();
662         }
663     #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
664 
665     /* Set remaining time to 0 so it will become active immediately. */
666     vARPTimerReload( pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );
667 }
668 /*-----------------------------------------------------------*/
669 
670 /**
671  * @brief Handle the incoming Ethernet packets.
672  *
673  * @param[in] pxBuffer Linked/un-linked network buffer descriptor(s)
674  *                      to be processed.
675  */
prvHandleEthernetPacket(NetworkBufferDescriptor_t * pxBuffer)676 static void prvHandleEthernetPacket( NetworkBufferDescriptor_t * pxBuffer )
677 {
678     #if ( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
679         {
680             /* When ipconfigUSE_LINKED_RX_MESSAGES is set to 0 then only one
681              * buffer will be sent at a time.  This is the default way for +TCP to pass
682              * messages from the MAC to the TCP/IP stack. */
683             prvProcessEthernetPacket( pxBuffer );
684         }
685     #else /* ipconfigUSE_LINKED_RX_MESSAGES */
686         {
687             NetworkBufferDescriptor_t * pxNextBuffer;
688 
689             /* An optimisation that is useful when there is high network traffic.
690              * Instead of passing received packets into the IP task one at a time the
691              * network interface can chain received packets together and pass them into
692              * the IP task in one go.  The packets are chained using the pxNextBuffer
693              * member.  The loop below walks through the chain processing each packet
694              * in the chain in turn. */
695 
696             /* While there is another packet in the chain. */
697             while( pxBuffer != NULL )
698             {
699                 /* Store a pointer to the buffer after pxBuffer for use later on. */
700                 pxNextBuffer = pxBuffer->pxNextBuffer;
701 
702                 /* Make it NULL to avoid using it later on. */
703                 pxBuffer->pxNextBuffer = NULL;
704 
705                 prvProcessEthernetPacket( pxBuffer );
706                 pxBuffer = pxNextBuffer;
707             }
708         }
709     #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
710 }
711 /*-----------------------------------------------------------*/
712 
713 /**
714  * @brief Send a network packet.
715  *
716  * @param[in] pxNetworkBuffer The message buffer.
717  * @param[in] xReleaseAfterSend When true, the network interface will own the buffer and is responsible for it's release.
718  */
prvForwardTxPacket(NetworkBufferDescriptor_t * pxNetworkBuffer,BaseType_t xReleaseAfterSend)719 static void prvForwardTxPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
720                                 BaseType_t xReleaseAfterSend )
721 {
722     iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
723 
724     if( pxNetworkBuffer->pxInterface != NULL )
725     {
726         ( void ) pxNetworkBuffer->pxInterface->pfOutput( pxNetworkBuffer->pxInterface, pxNetworkBuffer, xReleaseAfterSend );
727     }
728 }
729 /*-----------------------------------------------------------*/
730 
731 /**
732  * @brief Send a network down event to the IP-task. If it fails to post a message,
733  *         the failure will be noted in the variable 'xNetworkDownEventPending'
734  *         and later on a 'network-down' event, it will be executed.
735  *
736  * @param[in] pxNetworkInterface The interface that goes down.
737  */
FreeRTOS_NetworkDown(struct xNetworkInterface * pxNetworkInterface)738 void FreeRTOS_NetworkDown( struct xNetworkInterface * pxNetworkInterface )
739 {
740     IPStackEvent_t xNetworkDownEvent;
741     const TickType_t xDontBlock = ( TickType_t ) 0;
742 
743     pxNetworkInterface->bits.bInterfaceUp = pdFALSE_UNSIGNED;
744     xNetworkDownEvent.eEventType = eNetworkDownEvent;
745     xNetworkDownEvent.pvData = pxNetworkInterface;
746 
747     /* Simply send the network task the appropriate event. */
748     if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )
749     {
750         /* Could not send the message, so it is still pending. */
751         pxNetworkInterface->bits.bCallDownEvent = pdTRUE;
752         xNetworkDownEventPending = pdTRUE;
753     }
754     else
755     {
756         /* Message was sent so it is not pending. */
757         pxNetworkInterface->bits.bCallDownEvent = pdFALSE;
758     }
759 
760     iptraceNETWORK_DOWN();
761 }
762 /*-----------------------------------------------------------*/
763 
764 /**
765  * @brief Utility function. Process Network Down event from ISR.
766  *        This function is supposed to be called form an ISR. It is recommended
767  * - *        use 'FreeRTOS_NetworkDown()', when calling from a normal task.
768  *
769  * @param[in] pxNetworkInterface The interface that goes down.
770  *
771  * @return If the event was processed successfully, then return pdTRUE.
772  *         Else pdFALSE.
773  */
FreeRTOS_NetworkDownFromISR(struct xNetworkInterface * pxNetworkInterface)774 BaseType_t FreeRTOS_NetworkDownFromISR( struct xNetworkInterface * pxNetworkInterface )
775 {
776     IPStackEvent_t xNetworkDownEvent;
777     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
778 
779     xNetworkDownEvent.eEventType = eNetworkDownEvent;
780     xNetworkDownEvent.pvData = pxNetworkInterface;
781 
782     /* Simply send the network task the appropriate event. */
783     if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
784     {
785         /* Could not send the message, so it is still pending. */
786         pxNetworkInterface->bits.bCallDownEvent = pdTRUE;
787         xNetworkDownEventPending = pdTRUE;
788     }
789     else
790     {
791         /* Message was sent so it is not pending. */
792         pxNetworkInterface->bits.bCallDownEvent = pdFALSE;
793         xNetworkDownEventPending = pdFALSE;
794     }
795 
796     iptraceNETWORK_DOWN();
797 
798     return xHigherPriorityTaskWoken;
799 }
800 /*-----------------------------------------------------------*/
801 
802 #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
803 
804 /**
805  * @brief Obtain a buffer big enough for a UDP payload of given size.
806  *        NOTE: This function is kept for backward compatibility and will
807  *        only allocate IPv4 payload buffers. Newer designs should use
808  *        FreeRTOS_GetUDPPayloadBuffer_Multi(), which can
809  *        allocate a IPv4 or IPv6 buffer based on ucIPType parameter .
810  *
811  * @param[in] uxRequestedSizeBytes The size of the UDP payload.
812  * @param[in] uxBlockTimeTicks Maximum amount of time for which this call
813  *            can block. This value is capped internally.
814  *
815  * @return If a buffer was created then the pointer to that buffer is returned,
816  *         else a NULL pointer is returned.
817  */
FreeRTOS_GetUDPPayloadBuffer(size_t uxRequestedSizeBytes,TickType_t uxBlockTimeTicks)818     void * FreeRTOS_GetUDPPayloadBuffer( size_t uxRequestedSizeBytes,
819                                          TickType_t uxBlockTimeTicks )
820     {
821         return FreeRTOS_GetUDPPayloadBuffer_Multi( uxRequestedSizeBytes, uxBlockTimeTicks, ipTYPE_IPv4 );
822     }
823 #endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
824 /*-----------------------------------------------------------*/
825 
826 /**
827  * @brief Obtain a buffer big enough for a UDP payload of given size and
828  *        given IP type.
829  *
830  * @param[in] uxRequestedSizeBytes The size of the UDP payload.
831  * @param[in] uxBlockTimeTicks Maximum amount of time for which this call
832  *            can block. This value is capped internally.
833  * @param[in] ucIPType Either ipTYPE_IPv4 (0x40) or ipTYPE_IPv6 (0x60)
834  *
835  * @return If a buffer was created then the pointer to that buffer is returned,
836  *         else a NULL pointer is returned.
837  */
FreeRTOS_GetUDPPayloadBuffer_Multi(size_t uxRequestedSizeBytes,TickType_t uxBlockTimeTicks,uint8_t ucIPType)838 void * FreeRTOS_GetUDPPayloadBuffer_Multi( size_t uxRequestedSizeBytes,
839                                            TickType_t uxBlockTimeTicks,
840                                            uint8_t ucIPType )
841 {
842     NetworkBufferDescriptor_t * pxNetworkBuffer;
843     void * pvReturn = NULL;
844     TickType_t uxBlockTime = uxBlockTimeTicks;
845     size_t uxPayloadOffset = 0U;
846 
847     configASSERT( ( ucIPType == ipTYPE_IPv6 ) || ( ucIPType == ipTYPE_IPv4 ) );
848 
849     /* Cap the block time.  The reason for this is explained where
850      * ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
851      * FreeRTOSIPConfig.h header file is being used). */
852     if( uxBlockTime > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
853     {
854         uxBlockTime = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
855     }
856 
857     switch( ucIPType ) /* LCOV_EXCL_BR_LINE */
858     {
859         #if ( ipconfigUSE_IPv4 != 0 )
860             case ipTYPE_IPv4:
861                 uxPayloadOffset = sizeof( UDPPacket_t );
862                 break;
863         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
864 
865         #if ( ipconfigUSE_IPv6 != 0 )
866             case ipTYPE_IPv6:
867                 uxPayloadOffset = sizeof( UDPPacket_IPv6_t );
868                 break;
869         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
870 
871         default:
872             /* Shouldn't reach here. */
873             /* MISRA 16.4 Compliance */
874             break;
875     }
876 
877     if( uxPayloadOffset != 0U )
878     {
879         /* Obtain a network buffer with the required amount of storage. */
880         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxPayloadOffset + uxRequestedSizeBytes, uxBlockTime );
881 
882         if( pxNetworkBuffer != NULL )
883         {
884             size_t uxIndex = ipUDP_PAYLOAD_IP_TYPE_OFFSET;
885             BaseType_t xPayloadIPTypeOffset = ( BaseType_t ) uxIndex;
886 
887             /* Set the actual packet size in case a bigger buffer was returned. */
888             pxNetworkBuffer->xDataLength = uxPayloadOffset + uxRequestedSizeBytes;
889 
890             /* Skip 3 headers. */
891             pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ uxPayloadOffset ] );
892 
893             uint8_t * pucIPType;
894 
895             /* Later a pointer to a UDP payload is used to retrieve a NetworkBuffer.
896              * Store the packet type at 48 bytes before the start of the UDP payload. */
897             pucIPType = ( uint8_t * ) pvReturn;
898             pucIPType = &( pucIPType[ -xPayloadIPTypeOffset ] );
899 
900             /* For a IPv4 packet, pucIPType points to 6 bytes before the
901              * pucEthernetBuffer, for a IPv6 packet, pucIPType will point to the
902              * first byte of the IP-header: 'ucVersionTrafficClass'. */
903             *pucIPType = ucIPType;
904         }
905     }
906 
907     return ( void * ) pvReturn;
908 }
909 /*-----------------------------------------------------------*/
910 
911 /*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */
912 
913 /*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.
914  * As that bug has been repaired, there is not an urgent reason to warn.
915  * It is better though to use the advised priority scheme. */
916 
917 #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) && ( ipconfigUSE_IPv4 != 0 )
918 
919 /* Provide backward-compatibility with the earlier FreeRTOS+TCP which only had
920  * single network interface. */
FreeRTOS_IPInit(const uint8_t ucIPAddress[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucNetMask[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucGatewayAddress[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucDNSServerAddress[ipIP_ADDRESS_LENGTH_BYTES],const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES])921     BaseType_t FreeRTOS_IPInit( const uint8_t ucIPAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
922                                 const uint8_t ucNetMask[ ipIP_ADDRESS_LENGTH_BYTES ],
923                                 const uint8_t ucGatewayAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
924                                 const uint8_t ucDNSServerAddress[ ipIP_ADDRESS_LENGTH_BYTES ],
925                                 const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
926     {
927         static NetworkInterface_t xInterfaces[ 1 ];
928         static NetworkEndPoint_t xEndPoints[ 1 ];
929 
930         /* IF the following function should be declared in the NetworkInterface.c
931          * linked in the project. */
932         pxFillInterfaceDescriptor( 0, &( xInterfaces[ 0 ] ) );
933         FreeRTOS_FillEndPoint( &( xInterfaces[ 0 ] ), &( xEndPoints[ 0 ] ), ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
934         #if ( ipconfigUSE_DHCP != 0 )
935             {
936                 xEndPoints[ 0 ].bits.bWantDHCP = pdTRUE;
937             }
938         #endif /* ipconfigUSE_DHCP */
939         return FreeRTOS_IPInit_Multi();
940     }
941 #endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) && ( ipconfigUSE_IPv4 != 0 ) */
942 /*-----------------------------------------------------------*/
943 
944 /**
945  * @brief Initialise the FreeRTOS-Plus-TCP network stack and initialise the IP-task.
946  *        Before calling this function, at least 1 interface and 1 end-point must
947  *        have been set-up.
948  */
FreeRTOS_IPInit_Multi(void)949 BaseType_t FreeRTOS_IPInit_Multi( void )
950 {
951     BaseType_t xReturn = pdFALSE;
952 
953     /* There must be at least one interface and one end-point. */
954     configASSERT( FreeRTOS_FirstNetworkInterface() != NULL );
955 
956     /* Check that the configuration values are correct and that the IP-task has not
957      * already been initialized. */
958     vPreCheckConfigs();
959 
960     /* Attempt to create the queue used to communicate with the IP task. */
961     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
962         {
963             static StaticQueue_t xNetworkEventStaticQueue;
964             static uint8_t ucNetworkEventQueueStorageArea[ ipconfigEVENT_QUEUE_LENGTH * sizeof( IPStackEvent_t ) ];
965             xNetworkEventQueue = xQueueCreateStatic( ipconfigEVENT_QUEUE_LENGTH,
966                                                      sizeof( IPStackEvent_t ),
967                                                      ucNetworkEventQueueStorageArea,
968                                                      &xNetworkEventStaticQueue );
969         }
970     #else
971         {
972             xNetworkEventQueue = xQueueCreate( ipconfigEVENT_QUEUE_LENGTH, sizeof( IPStackEvent_t ) );
973             configASSERT( xNetworkEventQueue != NULL );
974         }
975     #endif /* configSUPPORT_STATIC_ALLOCATION */
976 
977     if( xNetworkEventQueue != NULL )
978     {
979         #if ( configQUEUE_REGISTRY_SIZE > 0 )
980             {
981                 /* A queue registry is normally used to assist a kernel aware
982                  * debugger.  If one is in use then it will be helpful for the debugger
983                  * to show information about the network event queue. */
984                 vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
985             }
986         #endif /* configQUEUE_REGISTRY_SIZE */
987 
988         if( xNetworkBuffersInitialise() == pdPASS )
989         {
990             /* Prepare the sockets interface. */
991             vNetworkSocketsInit();
992 
993             /* Create the task that processes Ethernet and stack events. */
994             #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
995                 {
996                     static StaticTask_t xIPTaskBuffer;
997                     static StackType_t xIPTaskStack[ ipconfigIP_TASK_STACK_SIZE_WORDS ];
998                     xIPTaskHandle = xTaskCreateStatic( prvIPTask,
999                                                        "IP-Task",
1000                                                        ipconfigIP_TASK_STACK_SIZE_WORDS,
1001                                                        NULL,
1002                                                        ipconfigIP_TASK_PRIORITY,
1003                                                        xIPTaskStack,
1004                                                        &xIPTaskBuffer );
1005 
1006                     if( xIPTaskHandle != NULL )
1007                     {
1008                         xReturn = pdTRUE;
1009                     }
1010                 }
1011             #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
1012                 {
1013                     xReturn = xTaskCreate( prvIPTask,
1014                                            "IP-task",
1015                                            ipconfigIP_TASK_STACK_SIZE_WORDS,
1016                                            NULL,
1017                                            ipconfigIP_TASK_PRIORITY,
1018                                            &( xIPTaskHandle ) );
1019                 }
1020             #endif /* configSUPPORT_STATIC_ALLOCATION */
1021         }
1022         else
1023         {
1024             FreeRTOS_debug_printf( ( "FreeRTOS_IPInit_Multi: xNetworkBuffersInitialise() failed\n" ) );
1025 
1026             /* Clean up. */
1027             vQueueDelete( xNetworkEventQueue );
1028             xNetworkEventQueue = NULL;
1029         }
1030     }
1031     else
1032     {
1033         FreeRTOS_debug_printf( ( "FreeRTOS_IPInit_Multi: Network event queue could not be created\n" ) );
1034     }
1035 
1036     return xReturn;
1037 }
1038 /*-----------------------------------------------------------*/
1039 
1040 /**
1041  * @brief Release the UDP payload buffer.
1042  *
1043  * @param[in] pvBuffer Pointer to the UDP buffer that is to be released.
1044  */
FreeRTOS_ReleaseUDPPayloadBuffer(void const * pvBuffer)1045 void FreeRTOS_ReleaseUDPPayloadBuffer( void const * pvBuffer )
1046 {
1047     NetworkBufferDescriptor_t * pxBuffer;
1048 
1049     pxBuffer = pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer );
1050     configASSERT( pxBuffer != NULL );
1051     vReleaseNetworkBufferAndDescriptor( pxBuffer );
1052 }
1053 /*-----------------------------------------------------------*/
1054 
1055 /**
1056  * @brief Get the current IPv4 address configuration. Only non-NULL pointers will
1057  *        be filled in. pxEndPoint must be non-NULL.
1058  *
1059  * @param[out] pulIPAddress The current IP-address assigned.
1060  * @param[out] pulNetMask The netmask used for current subnet.
1061  * @param[out] pulGatewayAddress The gateway address.
1062  * @param[out] pulDNSServerAddress The DNS server address.
1063  * @param[in] pxEndPoint The end-point which is being questioned.
1064  */
FreeRTOS_GetEndPointConfiguration(uint32_t * pulIPAddress,uint32_t * pulNetMask,uint32_t * pulGatewayAddress,uint32_t * pulDNSServerAddress,const struct xNetworkEndPoint * pxEndPoint)1065 void FreeRTOS_GetEndPointConfiguration( uint32_t * pulIPAddress,
1066                                         uint32_t * pulNetMask,
1067                                         uint32_t * pulGatewayAddress,
1068                                         uint32_t * pulDNSServerAddress,
1069                                         const struct xNetworkEndPoint * pxEndPoint )
1070 {
1071     if( ENDPOINT_IS_IPv4( pxEndPoint ) )
1072     {
1073         /* Return the address configuration to the caller. */
1074 
1075         if( pulIPAddress != NULL )
1076         {
1077             *pulIPAddress = pxEndPoint->ipv4_settings.ulIPAddress;
1078         }
1079 
1080         if( pulNetMask != NULL )
1081         {
1082             *pulNetMask = pxEndPoint->ipv4_settings.ulNetMask;
1083         }
1084 
1085         if( pulGatewayAddress != NULL )
1086         {
1087             *pulGatewayAddress = pxEndPoint->ipv4_settings.ulGatewayAddress;
1088         }
1089 
1090         if( pulDNSServerAddress != NULL )
1091         {
1092             *pulDNSServerAddress = pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ]; /*_RB_ Only returning the address of the first DNS server. */
1093         }
1094     }
1095 }
1096 /*-----------------------------------------------------------*/
1097 
1098 #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
1099 
1100 /**
1101  * @brief Get the current IPv4 address configuration of the first endpoint.
1102  *        Only non-NULL pointers will be filled in.
1103  *        NOTE: This function is kept for backward compatibility. Newer
1104  *        designs should use FreeRTOS_SetEndPointConfiguration().
1105  *
1106  * @param[out] pulIPAddress The current IP-address assigned.
1107  * @param[out] pulNetMask The netmask used for current subnet.
1108  * @param[out] pulGatewayAddress The gateway address.
1109  * @param[out] pulDNSServerAddress The DNS server address.
1110  */
FreeRTOS_GetAddressConfiguration(uint32_t * pulIPAddress,uint32_t * pulNetMask,uint32_t * pulGatewayAddress,uint32_t * pulDNSServerAddress)1111     void FreeRTOS_GetAddressConfiguration( uint32_t * pulIPAddress,
1112                                            uint32_t * pulNetMask,
1113                                            uint32_t * pulGatewayAddress,
1114                                            uint32_t * pulDNSServerAddress )
1115     {
1116         NetworkEndPoint_t * pxEndPoint;
1117 
1118         /* Get first end point. */
1119         pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
1120 
1121         if( pxEndPoint != NULL )
1122         {
1123             FreeRTOS_GetEndPointConfiguration( pulIPAddress, pulNetMask,
1124                                                pulGatewayAddress, pulDNSServerAddress, pxEndPoint );
1125         }
1126     }
1127 #endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
1128 /*-----------------------------------------------------------*/
1129 
1130 /**
1131  * @brief Set the current IPv4 network address configuration. Only non-NULL pointers will
1132  *        pointers will be used. pxEndPoint must pointer to a valid end-point.
1133  *
1134  * @param[in] pulIPAddress The current IP-address assigned.
1135  * @param[in] pulNetMask The netmask used for current subnet.
1136  * @param[in] pulGatewayAddress The gateway address.
1137  * @param[in] pulDNSServerAddress The DNS server address.
1138  * @param[in] pxEndPoint The end-point which is being questioned.
1139  */
FreeRTOS_SetEndPointConfiguration(const uint32_t * pulIPAddress,const uint32_t * pulNetMask,const uint32_t * pulGatewayAddress,const uint32_t * pulDNSServerAddress,struct xNetworkEndPoint * pxEndPoint)1140 void FreeRTOS_SetEndPointConfiguration( const uint32_t * pulIPAddress,
1141                                         const uint32_t * pulNetMask,
1142                                         const uint32_t * pulGatewayAddress,
1143                                         const uint32_t * pulDNSServerAddress,
1144                                         struct xNetworkEndPoint * pxEndPoint )
1145 {
1146     /* Update the address configuration. */
1147 
1148     if( ENDPOINT_IS_IPv4( pxEndPoint ) )
1149     {
1150         if( pulIPAddress != NULL )
1151         {
1152             pxEndPoint->ipv4_settings.ulIPAddress = *pulIPAddress;
1153         }
1154 
1155         if( pulNetMask != NULL )
1156         {
1157             pxEndPoint->ipv4_settings.ulNetMask = *pulNetMask;
1158         }
1159 
1160         if( pulGatewayAddress != NULL )
1161         {
1162             pxEndPoint->ipv4_settings.ulGatewayAddress = *pulGatewayAddress;
1163         }
1164 
1165         if( pulDNSServerAddress != NULL )
1166         {
1167             pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ] = *pulDNSServerAddress;
1168         }
1169     }
1170 }
1171 /*-----------------------------------------------------------*/
1172 
1173 #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
1174 
1175 /**
1176  * @brief Set the current IPv4 network address configuration. Only non-NULL
1177  *        pointers will be used.
1178  *        NOTE: This function is kept for backward compatibility. Newer
1179  *        designs should use FreeRTOS_SetEndPointConfiguration().
1180  *
1181  * @param[in] pulIPAddress The current IP-address assigned.
1182  * @param[in] pulNetMask The netmask used for current subnet.
1183  * @param[in] pulGatewayAddress The gateway address.
1184  * @param[in] pulDNSServerAddress The DNS server address.
1185  */
FreeRTOS_SetAddressConfiguration(const uint32_t * pulIPAddress,const uint32_t * pulNetMask,const uint32_t * pulGatewayAddress,const uint32_t * pulDNSServerAddress)1186     void FreeRTOS_SetAddressConfiguration( const uint32_t * pulIPAddress,
1187                                            const uint32_t * pulNetMask,
1188                                            const uint32_t * pulGatewayAddress,
1189                                            const uint32_t * pulDNSServerAddress )
1190     {
1191         NetworkEndPoint_t * pxEndPoint;
1192 
1193         /* Get first end point. */
1194         pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
1195 
1196         if( pxEndPoint != NULL )
1197         {
1198             FreeRTOS_SetEndPointConfiguration( pulIPAddress, pulNetMask,
1199                                                pulGatewayAddress, pulDNSServerAddress, pxEndPoint );
1200         }
1201     }
1202 #endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
1203 /*-----------------------------------------------------------*/
1204 
1205 #if ( ipconfigUSE_TCP == 1 )
1206 
1207 /**
1208  * @brief Release the memory that was previously obtained by calling FreeRTOS_recv()
1209  *        with the flag 'FREERTOS_ZERO_COPY'.
1210  *
1211  * @param[in] xSocket The socket that was read from.
1212  * @param[in] pvBuffer The buffer returned in the call to FreeRTOS_recv().
1213  * @param[in] xByteCount The number of bytes that have been used.
1214  *
1215  * @return pdPASS if the buffer was released successfully, otherwise pdFAIL is returned.
1216  */
FreeRTOS_ReleaseTCPPayloadBuffer(Socket_t xSocket,void const * pvBuffer,BaseType_t xByteCount)1217     BaseType_t FreeRTOS_ReleaseTCPPayloadBuffer( Socket_t xSocket,
1218                                                  void const * pvBuffer,
1219                                                  BaseType_t xByteCount )
1220     {
1221         BaseType_t xByteCountReleased;
1222         BaseType_t xReturn = pdFAIL;
1223         uint8_t * pucData;
1224         size_t uxBytesAvailable = uxStreamBufferGetPtr( xSocket->u.xTCP.rxStream, &( pucData ) );
1225 
1226         /* Make sure the pointer is correct. */
1227         configASSERT( pucData == ( uint8_t * ) pvBuffer );
1228 
1229         /* Avoid releasing more bytes than available. */
1230         configASSERT( uxBytesAvailable >= ( size_t ) xByteCount );
1231 
1232         if( ( pucData == pvBuffer ) && ( uxBytesAvailable >= ( size_t ) xByteCount ) )
1233         {
1234             /* Call recv with NULL pointer to advance the circular buffer. */
1235             xByteCountReleased = FreeRTOS_recv( xSocket,
1236                                                 NULL,
1237                                                 ( size_t ) xByteCount,
1238                                                 FREERTOS_MSG_DONTWAIT );
1239 
1240             configASSERT( xByteCountReleased == xByteCount );
1241 
1242             if( xByteCountReleased == xByteCount )
1243             {
1244                 xReturn = pdPASS;
1245             }
1246         }
1247 
1248         return xReturn;
1249     }
1250 #endif /* ( ipconfigUSE_TCP == 1 ) */
1251 /*-----------------------------------------------------------*/
1252 
1253 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1254 
1255 /**
1256  * @brief Send a ping request to the given IP address. After receiving a reply,
1257  *        IP-task will call a user-supplied function 'vApplicationPingReplyHook()'.
1258  *
1259  * @param[in] ulIPAddress The IP address to which the ping is to be sent.
1260  * @param[in] uxNumberOfBytesToSend Number of bytes in the ping request.
1261  * @param[in] uxBlockTimeTicks Maximum number of ticks to wait.
1262  *
1263  * @return If successfully sent to IP task for processing then the sequence
1264  *         number of the ping packet or else, pdFAIL.
1265  */
FreeRTOS_SendPingRequest(uint32_t ulIPAddress,size_t uxNumberOfBytesToSend,TickType_t uxBlockTimeTicks)1266     BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress,
1267                                          size_t uxNumberOfBytesToSend,
1268                                          TickType_t uxBlockTimeTicks )
1269     {
1270         NetworkBufferDescriptor_t * pxNetworkBuffer;
1271         ICMPHeader_t * pxICMPHeader;
1272         EthernetHeader_t * pxEthernetHeader;
1273         BaseType_t xReturn = pdFAIL;
1274         static uint16_t usSequenceNumber = 0;
1275         uint8_t * pucChar;
1276         size_t uxTotalLength;
1277         BaseType_t xEnoughSpace;
1278         IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
1279 
1280         uxTotalLength = uxNumberOfBytesToSend + sizeof( ICMPPacket_t );
1281 
1282         if( uxNumberOfBytesToSend < ( ipconfigNETWORK_MTU - ( sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) ) ) )
1283         {
1284             xEnoughSpace = pdTRUE;
1285         }
1286         else
1287         {
1288             xEnoughSpace = pdFALSE;
1289         }
1290 
1291         if( ( uxGetNumberOfFreeNetworkBuffers() >= 4U ) && ( uxNumberOfBytesToSend >= 1U ) && ( xEnoughSpace != pdFALSE ) )
1292         {
1293             pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( uxTotalLength, uxBlockTimeTicks );
1294 
1295             if( pxNetworkBuffer != NULL )
1296             {
1297                 pxEthernetHeader = ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
1298                 pxEthernetHeader->usFrameType = ipIPv4_FRAME_TYPE;
1299 
1300                 pxICMPHeader = ( ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] ) );
1301                 usSequenceNumber++;
1302 
1303                 /* Fill in the basic header information. */
1304                 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
1305                 pxICMPHeader->ucTypeOfService = 0;
1306                 pxICMPHeader->usIdentifier = usSequenceNumber;
1307                 pxICMPHeader->usSequenceNumber = usSequenceNumber;
1308 
1309                 /* Find the start of the data. */
1310                 pucChar = ( uint8_t * ) pxICMPHeader;
1311                 pucChar = &( pucChar[ sizeof( ICMPHeader_t ) ] );
1312 
1313                 /* Just memset the data to a fixed value. */
1314                 ( void ) memset( pucChar, ( int ) ipECHO_DATA_FILL_BYTE, uxNumberOfBytesToSend );
1315 
1316                 /* The message is complete, IP and checksum's are handled by
1317                  * vProcessGeneratedUDPPacket */
1318                 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;
1319                 pxNetworkBuffer->xIPAddress.ulIP_IPv4 = ulIPAddress;
1320                 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
1321                 /* xDataLength is the size of the total packet, including the Ethernet header. */
1322                 pxNetworkBuffer->xDataLength = uxTotalLength;
1323 
1324                 /* Send to the stack. */
1325                 xStackTxEvent.pvData = pxNetworkBuffer;
1326 
1327                 if( xSendEventStructToIPTask( &( xStackTxEvent ), uxBlockTimeTicks ) != pdPASS )
1328                 {
1329                     vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1330                     iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
1331                 }
1332                 else
1333                 {
1334                     xReturn = ( BaseType_t ) usSequenceNumber;
1335                 }
1336             }
1337         }
1338         else
1339         {
1340             /* The requested number of bytes will not fit in the available space
1341              * in the network buffer. */
1342         }
1343 
1344         return xReturn;
1345     }
1346 
1347 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
1348 /*-----------------------------------------------------------*/
1349 
1350 /**
1351  * @brief Send an event to the IP task. It calls 'xSendEventStructToIPTask' internally.
1352  *
1353  * @param[in] eEvent The event to be sent.
1354  *
1355  * @return pdPASS if the event was sent (or the desired effect was achieved). Else, pdFAIL.
1356  */
xSendEventToIPTask(eIPEvent_t eEvent)1357 BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )
1358 {
1359     IPStackEvent_t xEventMessage;
1360     const TickType_t xDontBlock = ( TickType_t ) 0;
1361 
1362     xEventMessage.eEventType = eEvent;
1363     xEventMessage.pvData = ( void * ) NULL;
1364 
1365     return xSendEventStructToIPTask( &xEventMessage, xDontBlock );
1366 }
1367 /*-----------------------------------------------------------*/
1368 
1369 /**
1370  * @brief Send an event (in form of struct) to the IP task to be processed.
1371  *
1372  * @param[in] pxEvent The event to be sent.
1373  * @param[in] uxTimeout Timeout for waiting in case the queue is full. 0 for non-blocking calls.
1374  *
1375  * @return pdPASS if the event was sent (or the desired effect was achieved). Else, pdFAIL.
1376  */
xSendEventStructToIPTask(const IPStackEvent_t * pxEvent,TickType_t uxTimeout)1377 BaseType_t xSendEventStructToIPTask( const IPStackEvent_t * pxEvent,
1378                                      TickType_t uxTimeout )
1379 {
1380     BaseType_t xReturn, xSendMessage;
1381     TickType_t uxUseTimeout = uxTimeout;
1382 
1383     if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )
1384     {
1385         /* Only allow eNetworkDownEvent events if the IP task is not ready
1386          * yet.  Not going to attempt to send the message so the send failed. */
1387         xReturn = pdFAIL;
1388     }
1389     else
1390     {
1391         xSendMessage = pdTRUE;
1392 
1393         #if ( ipconfigUSE_TCP == 1 )
1394             {
1395                 if( pxEvent->eEventType == eTCPTimerEvent )
1396                 {
1397                     /* TCP timer events are sent to wake the timer task when
1398                      * xTCPTimer has expired, but there is no point sending them if the
1399                      * IP task is already awake processing other message. */
1400                     vIPSetTCPTimerExpiredState( pdTRUE );
1401 
1402                     if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0U )
1403                     {
1404                         /* Not actually going to send the message but this is not a
1405                          * failure as the message didn't need to be sent. */
1406                         xSendMessage = pdFALSE;
1407                     }
1408                 }
1409             }
1410         #endif /* ipconfigUSE_TCP */
1411 
1412         if( xSendMessage != pdFALSE )
1413         {
1414             /* The IP task cannot block itself while waiting for itself to
1415              * respond. */
1416             if( ( xIsCallingFromIPTask() == pdTRUE ) && ( uxUseTimeout > ( TickType_t ) 0U ) )
1417             {
1418                 uxUseTimeout = ( TickType_t ) 0;
1419             }
1420 
1421             xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, uxUseTimeout );
1422 
1423             if( xReturn == pdFAIL )
1424             {
1425                 /* A message should have been sent to the IP task, but wasn't. */
1426                 FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );
1427                 iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );
1428             }
1429         }
1430         else
1431         {
1432             /* It was not necessary to send the message to process the event so
1433              * even though the message was not sent the call was successful. */
1434             xReturn = pdPASS;
1435         }
1436     }
1437 
1438     return xReturn;
1439 }
1440 /*-----------------------------------------------------------*/
1441 
1442 /**
1443  * @brief Decide whether this packet should be processed or not based on the IP address in the packet.
1444  *
1445  * @param[in] pucEthernetBuffer The ethernet packet under consideration.
1446  *
1447  * @return Enum saying whether to release or to process the packet.
1448  */
eConsiderFrameForProcessing(const uint8_t * const pucEthernetBuffer)1449 eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
1450 {
1451     eFrameProcessingResult_t eReturn = eProcessBuffer;
1452     const EthernetHeader_t * pxEthernetHeader = NULL;
1453     const NetworkEndPoint_t * pxEndPoint = NULL;
1454 
1455     if( pucEthernetBuffer == NULL )
1456     {
1457         eReturn = eReleaseBuffer;
1458     }
1459     else
1460     {
1461         /* Map the buffer onto Ethernet Header struct for easy access to fields. */
1462 
1463         /* MISRA Ref 11.3.1 [Misaligned access] */
1464         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1465         /* coverity[misra_c_2012_rule_11_3_violation] */
1466         pxEthernetHeader = ( ( const EthernetHeader_t * ) pucEthernetBuffer );
1467 
1468         /* Examine the destination MAC from the Ethernet header to see if it matches
1469          * that of an end point managed by FreeRTOS+TCP. */
1470         pxEndPoint = FreeRTOS_FindEndPointOnMAC( &( pxEthernetHeader->xDestinationAddress ), NULL );
1471 
1472         if( pxEndPoint != NULL )
1473         {
1474             /* The packet was directed to this node - process it. */
1475             eReturn = eProcessBuffer;
1476         }
1477         else if( memcmp( xBroadcastMACAddress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
1478         {
1479             /* The packet was a broadcast - process it. */
1480             eReturn = eProcessBuffer;
1481         }
1482         else
1483         #if ( ( ipconfigUSE_LLMNR == 1 ) && ( ipconfigUSE_DNS != 0 ) )
1484             if( memcmp( xLLMNR_MacAdress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
1485             {
1486                 /* The packet is a request for LLMNR - process it. */
1487                 eReturn = eProcessBuffer;
1488             }
1489             else
1490         #endif /* ipconfigUSE_LLMNR */
1491         #if ( ( ipconfigUSE_MDNS == 1 ) && ( ipconfigUSE_DNS != 0 ) )
1492             if( memcmp( xMDNS_MacAdress.ucBytes, pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
1493             {
1494                 /* The packet is a request for MDNS - process it. */
1495                 eReturn = eProcessBuffer;
1496             }
1497             else
1498         #endif /* ipconfigUSE_MDNS */
1499         if( ( pxEthernetHeader->xDestinationAddress.ucBytes[ 0 ] == ipMULTICAST_MAC_ADDRESS_IPv6_0 ) &&
1500             ( pxEthernetHeader->xDestinationAddress.ucBytes[ 1 ] == ipMULTICAST_MAC_ADDRESS_IPv6_1 ) )
1501         {
1502             /* The packet is a request for LLMNR - process it. */
1503             eReturn = eProcessBuffer;
1504         }
1505         else
1506         {
1507             /* The packet was not a broadcast, or for this node, just release
1508              * the buffer without taking any other action. */
1509             eReturn = eReleaseBuffer;
1510         }
1511     }
1512 
1513     #if ( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )
1514         {
1515             uint16_t usFrameType;
1516 
1517             if( eReturn == eProcessBuffer )
1518             {
1519                 usFrameType = pxEthernetHeader->usFrameType;
1520                 usFrameType = FreeRTOS_ntohs( usFrameType );
1521 
1522                 if( usFrameType <= 0x600U )
1523                 {
1524                     /* Not an Ethernet II frame. */
1525                     eReturn = eReleaseBuffer;
1526                 }
1527             }
1528         }
1529     #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1  */
1530 
1531     return eReturn;
1532 }
1533 /*-----------------------------------------------------------*/
1534 
1535 /**
1536  * @brief Process the Ethernet packet.
1537  *
1538  * @param[in,out] pxNetworkBuffer the network buffer containing the ethernet packet. If the
1539  *                                 buffer is large enough, it may be reused to send a reply.
1540  */
prvProcessEthernetPacket(NetworkBufferDescriptor_t * const pxNetworkBuffer)1541 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
1542 {
1543     const EthernetHeader_t * pxEthernetHeader;
1544     eFrameProcessingResult_t eReturned = eReleaseBuffer;
1545 
1546     configASSERT( pxNetworkBuffer != NULL );
1547 
1548     iptraceNETWORK_INTERFACE_INPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
1549 
1550     /* Interpret the Ethernet frame. */
1551     if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )
1552     {
1553         eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
1554 
1555         /* Map the buffer onto the Ethernet Header struct for easy access to the fields. */
1556 
1557         /* MISRA Ref 11.3.1 [Misaligned access] */
1558         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1559         /* coverity[misra_c_2012_rule_11_3_violation] */
1560         pxEthernetHeader = ( ( const EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
1561 
1562         /* The condition "eReturned == eProcessBuffer" must be true. */
1563         #if ( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )
1564             if( eReturned == eProcessBuffer )
1565         #endif
1566         {
1567             /* Interpret the received Ethernet packet. */
1568             switch( pxEthernetHeader->usFrameType )
1569             {
1570                 #if ( ipconfigUSE_IPv4 != 0 )
1571                     case ipARP_FRAME_TYPE:
1572 
1573                         /* The Ethernet frame contains an ARP packet. */
1574                         if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )
1575                         {
1576                             /* MISRA Ref 11.3.1 [Misaligned access] */
1577                             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1578                             /* coverity[misra_c_2012_rule_11_3_violation] */
1579                             eReturned = eARPProcessPacket( pxNetworkBuffer );
1580                         }
1581                         else
1582                         {
1583                             eReturned = eReleaseBuffer;
1584                         }
1585                         break;
1586                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1587 
1588                 case ipIPv4_FRAME_TYPE:
1589                 case ipIPv6_FRAME_TYPE:
1590 
1591                     /* The Ethernet frame contains an IP packet. */
1592                     if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )
1593                     {
1594                         /* MISRA Ref 11.3.1 [Misaligned access] */
1595                         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1596                         /* coverity[misra_c_2012_rule_11_3_violation] */
1597                         eReturned = prvProcessIPPacket( ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer );
1598                     }
1599                     else
1600                     {
1601                         eReturned = eReleaseBuffer;
1602                     }
1603 
1604                     break;
1605 
1606                 default:
1607                     #if ( ipconfigPROCESS_CUSTOM_ETHERNET_FRAMES != 0 )
1608                         /* Custom frame handler. */
1609                         eReturned = eApplicationProcessCustomFrameHook( pxNetworkBuffer );
1610                     #else
1611                         /* No other packet types are handled.  Nothing to do. */
1612                         eReturned = eReleaseBuffer;
1613                     #endif
1614                     break;
1615             }
1616         }
1617     }
1618 
1619     /* Perform any actions that resulted from processing the Ethernet frame. */
1620     switch( eReturned )
1621     {
1622         case eReturnEthernetFrame:
1623 
1624             /* The Ethernet frame will have been updated (maybe it was
1625              * an ARP request or a PING request?) and should be sent back to
1626              * its source. */
1627             vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );
1628 
1629             /* parameter pdTRUE: the buffer must be released once
1630              * the frame has been transmitted */
1631             break;
1632 
1633         case eFrameConsumed:
1634 
1635             /* The frame is in use somewhere, don't release the buffer
1636              * yet. */
1637             break;
1638 
1639         case eWaitingARPResolution:
1640 
1641             if( pxARPWaitingNetworkBuffer == NULL )
1642             {
1643                 pxARPWaitingNetworkBuffer = pxNetworkBuffer;
1644                 vIPTimerStartARPResolution( ipARP_RESOLUTION_MAX_DELAY );
1645 
1646                 iptraceDELAYED_ARP_REQUEST_STARTED();
1647             }
1648             else
1649             {
1650                 /* We are already waiting on one ARP resolution. This frame will be dropped. */
1651                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1652 
1653                 iptraceDELAYED_ARP_BUFFER_FULL();
1654             }
1655 
1656             break;
1657 
1658         case eReleaseBuffer:
1659         case eProcessBuffer:
1660         default:
1661 
1662             /* The frame is not being used anywhere, and the
1663              * NetworkBufferDescriptor_t structure containing the frame should
1664              * just be released back to the list of free buffers. */
1665             vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1666             break;
1667     }
1668 }
1669 /*-----------------------------------------------------------*/
1670 
1671 /**
1672  * @brief Check the sizes of the UDP packet and forward it to the UDP module
1673  *        ( xProcessReceivedUDPPacket() )
1674  * @param[in] pxNetworkBuffer The network buffer containing the UDP packet.
1675  * @return eReleaseBuffer ( please release the buffer ).
1676  *         eFrameConsumed ( the buffer has now been released ).
1677  */
1678 
prvProcessUDPPacket(NetworkBufferDescriptor_t * const pxNetworkBuffer)1679 static eFrameProcessingResult_t prvProcessUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
1680 {
1681     eFrameProcessingResult_t eReturn = eReleaseBuffer;
1682     BaseType_t xIsWaitingARPResolution = pdFALSE;
1683     /* The IP packet contained a UDP frame. */
1684     /* MISRA Ref 11.3.1 [Misaligned access] */
1685     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1686     /* coverity[misra_c_2012_rule_11_3_violation] */
1687     const UDPPacket_t * pxUDPPacket = ( ( UDPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
1688     const UDPHeader_t * pxUDPHeader = &( pxUDPPacket->xUDPHeader );
1689 
1690     size_t uxMinSize = ipSIZE_OF_ETH_HEADER + ( size_t ) uxIPHeaderSizePacket( pxNetworkBuffer ) + ipSIZE_OF_UDP_HEADER;
1691     size_t uxLength;
1692     uint16_t usLength;
1693 
1694     #if ( ipconfigUSE_IPv6 != 0 )
1695         if( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv6_FRAME_TYPE )
1696         {
1697             const ProtocolHeaders_t * pxProtocolHeaders;
1698 
1699             /* MISRA Ref 11.3.1 [Misaligned access] */
1700             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1701             /* coverity[misra_c_2012_rule_11_3_violation] */
1702             pxProtocolHeaders = ( ( ProtocolHeaders_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER + ipSIZE_OF_IPv6_HEADER ] ) );
1703             pxUDPHeader = &( pxProtocolHeaders->xUDPHeader );
1704         }
1705     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1706 
1707     usLength = FreeRTOS_ntohs( pxUDPHeader->usLength );
1708     uxLength = ( size_t ) usLength;
1709 
1710     /* Note the header values required prior to the checksum
1711      * generation as the checksum pseudo header may clobber some of
1712      * these values. */
1713     if( ( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) &&
1714         ( usLength > ( FreeRTOS_ntohs( pxUDPPacket->xIPHeader.usLength ) - uxIPHeaderSizePacket( pxNetworkBuffer ) ) ) )
1715     {
1716         eReturn = eReleaseBuffer;
1717     }
1718     else if( ( pxUDPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE ) &&
1719              ( ipFIRST_LOOPBACK_IPv4 <= ( FreeRTOS_ntohl( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) ) ) &&
1720              ( ( FreeRTOS_ntohl( pxUDPPacket->xIPHeader.ulDestinationIPAddress ) ) < ipLAST_LOOPBACK_IPv4 ) )
1721     {
1722         /* The local loopback addresses must never appear outside a host. See RFC 1122
1723          * section 3.2.1.3. */
1724         eReturn = eReleaseBuffer;
1725     }
1726     else if( ( pxNetworkBuffer->xDataLength >= uxMinSize ) &&
1727              ( uxLength >= sizeof( UDPHeader_t ) ) )
1728     {
1729         size_t uxPayloadSize_1, uxPayloadSize_2;
1730 
1731         /* Ensure that downstream UDP packet handling has the lesser
1732          * of: the actual network buffer Ethernet frame length, or
1733          * the sender's UDP packet header payload length, minus the
1734          * size of the UDP header.
1735          *
1736          * The size of the UDP packet structure in this implementation
1737          * includes the size of the Ethernet header, the size of
1738          * the IP header, and the size of the UDP header. */
1739         uxPayloadSize_1 = pxNetworkBuffer->xDataLength - uxMinSize;
1740         uxPayloadSize_2 = uxLength - ipSIZE_OF_UDP_HEADER;
1741 
1742         if( uxPayloadSize_1 > uxPayloadSize_2 )
1743         {
1744             pxNetworkBuffer->xDataLength = uxPayloadSize_2 + uxMinSize;
1745         }
1746 
1747         pxNetworkBuffer->usPort = pxUDPHeader->usSourcePort;
1748         pxNetworkBuffer->xIPAddress.ulIP_IPv4 = pxUDPPacket->xIPHeader.ulSourceIPAddress;
1749 
1750         /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:
1751          * In some cases, the upper-layer checksum has been calculated
1752          * by the NIC driver. */
1753 
1754         /* Pass the packet payload to the UDP sockets
1755          * implementation. */
1756         if( xProcessReceivedUDPPacket( pxNetworkBuffer,
1757                                        pxUDPHeader->usDestinationPort,
1758                                        &( xIsWaitingARPResolution ) ) == pdPASS )
1759         {
1760             eReturn = eFrameConsumed;
1761         }
1762         else
1763         {
1764             /* Is this packet to be set aside for ARP resolution. */
1765             if( xIsWaitingARPResolution == pdTRUE )
1766             {
1767                 eReturn = eWaitingARPResolution;
1768             }
1769         }
1770     }
1771     else
1772     {
1773         /* Length checks failed, the buffer will be released. */
1774     }
1775 
1776     return eReturn;
1777 }
1778 /*-----------------------------------------------------------*/
1779 
1780 /**
1781  * @brief Process an IP-packet.
1782  *
1783  * @param[in] pxIPPacket The IP packet to be processed.
1784  * @param[in] pxNetworkBuffer The networkbuffer descriptor having the IP packet.
1785  *
1786  * @return An enum to show whether the packet should be released/kept/processed etc.
1787  */
prvProcessIPPacket(const IPPacket_t * pxIPPacket,NetworkBufferDescriptor_t * const pxNetworkBuffer)1788 static eFrameProcessingResult_t prvProcessIPPacket( const IPPacket_t * pxIPPacket,
1789                                                     NetworkBufferDescriptor_t * const pxNetworkBuffer )
1790 {
1791     eFrameProcessingResult_t eReturn;
1792     UBaseType_t uxHeaderLength = ipSIZE_OF_IPv4_HEADER;
1793     uint8_t ucProtocol = 0U;
1794 
1795     #if ( ipconfigUSE_IPv6 != 0 )
1796         const IPHeader_IPv6_t * pxIPHeader_IPv6 = NULL;
1797     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1798 
1799     #if ( ipconfigUSE_IPv4 != 0 )
1800         const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
1801     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1802 
1803     switch( pxIPPacket->xEthernetHeader.usFrameType )
1804     {
1805         #if ( ipconfigUSE_IPv6 != 0 )
1806             case ipIPv6_FRAME_TYPE:
1807 
1808                 if( pxNetworkBuffer->xDataLength < sizeof( IPPacket_IPv6_t ) )
1809                 {
1810                     /* The packet size is less than minimum IPv6 packet. */
1811                     eReturn = eReleaseBuffer;
1812                 }
1813                 else
1814                 {
1815                     /* MISRA Ref 11.3.1 [Misaligned access] */
1816                     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1817                     /* coverity[misra_c_2012_rule_11_3_violation] */
1818                     pxIPHeader_IPv6 = ( ( const IPHeader_IPv6_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipSIZE_OF_ETH_HEADER ] ) );
1819 
1820                     uxHeaderLength = ipSIZE_OF_IPv6_HEADER;
1821                     ucProtocol = pxIPHeader_IPv6->ucNextHeader;
1822                     /* MISRA Ref 11.3.1 [Misaligned access] */
1823                     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
1824                     /* coverity[misra_c_2012_rule_11_3_violation] */
1825                     eReturn = prvAllowIPPacketIPv6( ( ( const IPHeader_IPv6_t * ) &( pxIPPacket->xIPHeader ) ), pxNetworkBuffer, uxHeaderLength );
1826 
1827                     /* The IP-header type is copied to a special reserved location a few bytes before the message
1828                      * starts. In the case of IPv6, this value is never actually used and the line below can safely be removed
1829                      * with no ill effects. We only store it to help with debugging. */
1830                     pxNetworkBuffer->pucEthernetBuffer[ 0 - ( BaseType_t ) ipIP_TYPE_OFFSET ] = pxIPHeader_IPv6->ucVersionTrafficClass;
1831                 }
1832                 break;
1833         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1834 
1835         #if ( ipconfigUSE_IPv4 != 0 )
1836             case ipIPv4_FRAME_TYPE:
1837                {
1838                    size_t uxLength = ( size_t ) pxIPHeader->ucVersionHeaderLength;
1839 
1840                    /* Check if the IP headers are acceptable and if it has our destination.
1841                     * The lowest four bits of 'ucVersionHeaderLength' indicate the IP-header
1842                     * length in multiples of 4. */
1843                    uxHeaderLength = ( size_t ) ( ( uxLength & 0x0FU ) << 2 );
1844 
1845                    if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
1846                        ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
1847                    {
1848                        eReturn = eReleaseBuffer;
1849                    }
1850                    else
1851                    {
1852                        ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
1853                        /* Check if the IP headers are acceptable and if it has our destination. */
1854                        eReturn = prvAllowIPPacketIPv4( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
1855 
1856                        {
1857                            /* The IP-header type is copied to a special reserved location a few bytes before the
1858                             * messages starts.  It might be needed later on when a UDP-payload
1859                             * buffer is being used. */
1860                            pxNetworkBuffer->pucEthernetBuffer[ 0 - ( BaseType_t ) ipIP_TYPE_OFFSET ] = pxIPHeader->ucVersionHeaderLength;
1861                        }
1862                    }
1863 
1864                    break;
1865                }
1866         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1867 
1868         default:
1869             eReturn = eReleaseBuffer;
1870             FreeRTOS_debug_printf( ( "prvProcessIPPacket: Undefined Frame Type \n" ) );
1871             /* MISRA 16.4 Compliance */
1872             break;
1873     }
1874 
1875     /* MISRA Ref 14.3.1 [Configuration dependent invariant] */
1876     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-143 */
1877     /* coverity[misra_c_2012_rule_14_3_violation] */
1878     /* coverity[cond_const] */
1879     if( eReturn == eProcessBuffer )
1880     {
1881         /* Are there IP-options. */
1882         /* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
1883         switch( pxIPPacket->xEthernetHeader.usFrameType ) /* LCOV_EXCL_BR_LINE */
1884         {
1885             #if ( ipconfigUSE_IPv4 != 0 )
1886                 case ipIPv4_FRAME_TYPE:
1887 
1888                     if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )
1889                     {
1890                         /* The size of the IP-header is larger than 20 bytes.
1891                          * The extra space is used for IP-options. */
1892                         eReturn = prvCheckIP4HeaderOptions( pxNetworkBuffer );
1893                     }
1894                     break;
1895             #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1896 
1897             #if ( ipconfigUSE_IPv6 != 0 )
1898                 case ipIPv6_FRAME_TYPE:
1899 
1900                     if( xGetExtensionOrder( ucProtocol, 0U ) > 0 )
1901                     {
1902                         eReturn = eHandleIPv6ExtensionHeaders( pxNetworkBuffer, pdTRUE );
1903 
1904                         if( eReturn != eReleaseBuffer )
1905                         {
1906                             /* Ignore warning for `pxIPHeader_IPv6`. */
1907                             ucProtocol = pxIPHeader_IPv6->ucNextHeader;
1908                         }
1909                     }
1910                     break;
1911             #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1912 
1913             /* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
1914             default:   /* LCOV_EXCL_LINE */
1915                 /* MISRA 16.4 Compliance */
1916                 break; /* LCOV_EXCL_LINE */
1917         }
1918 
1919         /* MISRA Ref 14.3.1 [Configuration dependent invariant] */
1920         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-143 */
1921         /* coverity[misra_c_2012_rule_14_3_violation] */
1922         /* coverity[const] */
1923         if( eReturn != eReleaseBuffer )
1924         {
1925             /* Add the IP and MAC addresses to the ARP table if they are not
1926              * already there - otherwise refresh the age of the existing
1927              * entry. */
1928             if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )
1929             {
1930                 if( xCheckRequiresARPResolution( pxNetworkBuffer ) == pdTRUE )
1931                 {
1932                     eReturn = eWaitingARPResolution;
1933                 }
1934                 else
1935                 {
1936                     /* Refresh the ARP cache with the IP/MAC-address of the received
1937                      * packet.  For UDP packets, this will be done later in
1938                      * xProcessReceivedUDPPacket(), as soon as it's know that the message
1939                      * will be handled.  This will prevent the ARP cache getting
1940                      * overwritten with the IP address of useless broadcast packets. */
1941                     /* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
1942                     switch( pxIPPacket->xEthernetHeader.usFrameType ) /* LCOV_EXCL_BR_LINE */
1943                     {
1944                         #if ( ipconfigUSE_IPv6 != 0 )
1945                             case ipIPv6_FRAME_TYPE:
1946                                 vNDRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), &( pxIPHeader_IPv6->xSourceAddress ), pxNetworkBuffer->pxEndPoint );
1947                                 break;
1948                         #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1949 
1950                         #if ( ipconfigUSE_IPv4 != 0 )
1951                             case ipIPv4_FRAME_TYPE:
1952                                 /* Refresh the age of this cache entry since a packet was received. */
1953                                 vARPRefreshCacheEntryAge( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
1954                                 break;
1955                         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1956 
1957                         /* Case default is never toggled because eReturn is not eProcessBuffer in previous step. */
1958                         default:   /* LCOV_EXCL_LINE */
1959                             /* MISRA 16.4 Compliance */
1960                             break; /* LCOV_EXCL_LINE */
1961                     }
1962                 }
1963             }
1964 
1965             if( eReturn != eWaitingARPResolution ) /*TODO eReturn != eReleaseBuffer */
1966             {
1967                 switch( ucProtocol )
1968                 {
1969                     #if ( ipconfigUSE_IPv4 != 0 )
1970                         case ipPROTOCOL_ICMP:
1971 
1972                             /* The IP packet contained an ICMP frame.  Don't bother checking
1973                              * the ICMP checksum, as if it is wrong then the wrong data will
1974                              * also be returned, and the source of the ping will know something
1975                              * went wrong because it will not be able to validate what it
1976                              * receives. */
1977                             #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1978                                 {
1979                                     eReturn = ProcessICMPPacket( pxNetworkBuffer );
1980                                 }
1981                             #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
1982                             break;
1983                     #endif /* ( ipconfigUSE_IPv4 != 0 ) */
1984 
1985                     #if ( ipconfigUSE_IPv6 != 0 )
1986                         case ipPROTOCOL_ICMP_IPv6:
1987                             eReturn = prvProcessICMPMessage_IPv6( pxNetworkBuffer );
1988                             break;
1989                     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
1990 
1991                     case ipPROTOCOL_UDP:
1992                         /* The IP packet contained a UDP frame. */
1993 
1994                         eReturn = prvProcessUDPPacket( pxNetworkBuffer );
1995                         break;
1996 
1997                         #if ipconfigUSE_TCP == 1
1998                             case ipPROTOCOL_TCP:
1999 
2000                                 if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )
2001                                 {
2002                                     eReturn = eFrameConsumed;
2003                                 }
2004 
2005                                 /* Setting this variable will cause xTCPTimerCheck()
2006                                  * to be called just before the IP-task blocks. */
2007                                 xProcessedTCPMessage++;
2008                                 break;
2009                         #endif /* if ipconfigUSE_TCP == 1 */
2010                     default:
2011                         /* Not a supported frame type. */
2012                         eReturn = eReleaseBuffer;
2013                         break;
2014                 }
2015             }
2016         }
2017     }
2018 
2019     return eReturn;
2020 }
2021 
2022 /*-----------------------------------------------------------*/
2023 
2024 /* This function is used in other files, has external linkage e.g. in
2025  * FreeRTOS_DNS.c. Not to be made static. */
2026 
2027 /**
2028  * @brief Send the Ethernet frame after checking for some conditions.
2029  *
2030  * @param[in,out] pxNetworkBuffer The network buffer which is to be sent.
2031  * @param[in] xReleaseAfterSend Whether this network buffer is to be released or not.
2032  */
vReturnEthernetFrame(NetworkBufferDescriptor_t * pxNetworkBuffer,BaseType_t xReleaseAfterSend)2033 void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer,
2034                            BaseType_t xReleaseAfterSend )
2035 {
2036     #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
2037         NetworkBufferDescriptor_t * pxNewBuffer;
2038     #endif
2039 
2040     #if ( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 )
2041         {
2042             if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
2043             {
2044                 BaseType_t xIndex;
2045 
2046                 FreeRTOS_printf( ( "vReturnEthernetFrame: length %u\n", ( unsigned ) pxNetworkBuffer->xDataLength ) );
2047 
2048                 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
2049                 {
2050                     pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
2051                 }
2052 
2053                 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
2054             }
2055         }
2056     #endif /* if( ipconfigETHERNET_MINIMUM_PACKET_BYTES > 0 ) */
2057 
2058     #if ( ipconfigZERO_COPY_TX_DRIVER != 0 )
2059         if( xReleaseAfterSend == pdFALSE )
2060         {
2061             pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, pxNetworkBuffer->xDataLength );
2062 
2063             if( pxNewBuffer != NULL )
2064             {
2065                 xReleaseAfterSend = pdTRUE;
2066                 /* Want no rounding up. */
2067                 pxNewBuffer->xDataLength = pxNetworkBuffer->xDataLength;
2068             }
2069 
2070             pxNetworkBuffer = pxNewBuffer;
2071         }
2072 
2073         if( pxNetworkBuffer != NULL )
2074     #endif /* if ( ipconfigZERO_COPY_TX_DRIVER != 0 ) */
2075     {
2076         /* MISRA Ref 11.3.1 [Misaligned access] */
2077         /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
2078         /* coverity[misra_c_2012_rule_11_3_violation] */
2079         IPPacket_t * pxIPPacket = ( ( IPPacket_t * ) pxNetworkBuffer->pucEthernetBuffer );
2080         /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
2081         const void * pvCopySource = NULL;
2082         void * pvCopyDest;
2083 
2084         #if ( ipconfigUSE_IPv4 != 0 )
2085             MACAddress_t xMACAddress;
2086             eARPLookupResult_t eResult;
2087             uint32_t ulDestinationIPAddress = 0U;
2088         #endif /* ( ipconfigUSE_IPv4 != 0 ) */
2089 
2090         /* Send! */
2091         if( pxNetworkBuffer->pxEndPoint == NULL )
2092         {
2093             /* _HT_ I wonder if this ad-hoc search of an end-point it necessary. */
2094             FreeRTOS_printf( ( "vReturnEthernetFrame: No pxEndPoint yet for %x ip?\n", ( unsigned int ) FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ) ) );
2095 
2096             /* MISRA Ref 11.3.1 [Misaligned access] */
2097             /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
2098             /* coverity[misra_c_2012_rule_11_3_violation] */
2099             switch( ( ( ( EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer ) )->usFrameType )
2100             {
2101                 #if ( ipconfigUSE_IPv6 != 0 )
2102                     case ipIPv6_FRAME_TYPE:
2103                         /* No IPv6 endpoint found */
2104                         break;
2105                 #endif /* ( ipconfigUSE_IPv6 != 0 ) */
2106 
2107                 #if ( ipconfigUSE_IPv4 != 0 )
2108                     case ipIPv4_FRAME_TYPE:
2109                         pxNetworkBuffer->pxEndPoint = FreeRTOS_FindEndPointOnNetMask( pxIPPacket->xIPHeader.ulDestinationIPAddress, 7 );
2110                         break;
2111                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
2112 
2113                 default:
2114                     /* MISRA 16.4 Compliance */
2115                     break;
2116             }
2117         }
2118 
2119         if( pxNetworkBuffer->pxEndPoint != NULL )
2120         {
2121             NetworkInterface_t * pxInterface = pxNetworkBuffer->pxEndPoint->pxNetworkInterface; /*_RB_ Why not use the pxNetworkBuffer->pxNetworkInterface directly? */
2122 
2123             /* Interpret the Ethernet packet being sent. */
2124             switch( pxIPPacket->xEthernetHeader.usFrameType )
2125             {
2126                 #if ( ipconfigUSE_IPv4 != 0 )
2127                     case ipIPv4_FRAME_TYPE:
2128                         ulDestinationIPAddress = pxIPPacket->xIPHeader.ulDestinationIPAddress;
2129 
2130                         /* Try to find a MAC address corresponding to the destination IP
2131                          * address. */
2132                         eResult = eARPGetCacheEntry( &ulDestinationIPAddress, &xMACAddress, &( pxNetworkBuffer->pxEndPoint ) );
2133 
2134                         if( eResult == eARPCacheHit )
2135                         {
2136                             /* Best case scenario - an address is found, use it. */
2137                             pvCopySource = &xMACAddress;
2138                         }
2139                         else
2140                         {
2141                             /* If an address is not found, just swap the source and destination MAC addresses. */
2142                             pvCopySource = &( pxIPPacket->xEthernetHeader.xSourceAddress );
2143                         }
2144                         break;
2145                 #endif /* ( ipconfigUSE_IPv4 != 0 ) */
2146 
2147                 case ipIPv6_FRAME_TYPE:
2148                 case ipARP_FRAME_TYPE:
2149                 default:
2150                     /* In case of ARP frame, just swap the source and destination MAC addresses. */
2151                     pvCopySource = &( pxIPPacket->xEthernetHeader.xSourceAddress );
2152                     break;
2153             }
2154 
2155             /*
2156              * Use helper variables for memcpy() to remain
2157              * compliant with MISRA Rule 21.15.  These should be
2158              * optimized away.
2159              */
2160             pvCopyDest = &( pxIPPacket->xEthernetHeader.xDestinationAddress );
2161             ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxIPPacket->xEthernetHeader.xDestinationAddress ) );
2162 
2163             pvCopySource = pxNetworkBuffer->pxEndPoint->xMACAddress.ucBytes;
2164             pvCopyDest = &( pxIPPacket->xEthernetHeader.xSourceAddress );
2165             ( void ) memcpy( pvCopyDest, pvCopySource, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
2166 
2167             /* Send! */
2168             if( xIsCallingFromIPTask() == pdTRUE )
2169             {
2170                 iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
2171                 ( void ) pxInterface->pfOutput( pxInterface, pxNetworkBuffer, xReleaseAfterSend );
2172             }
2173             else if( xReleaseAfterSend != pdFALSE )
2174             {
2175                 IPStackEvent_t xSendEvent;
2176 
2177                 /* Send a message to the IP-task to send this ARP packet. */
2178                 xSendEvent.eEventType = eNetworkTxEvent;
2179                 xSendEvent.pvData = pxNetworkBuffer;
2180 
2181                 if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
2182                 {
2183                     /* Failed to send the message, so release the network buffer. */
2184                     vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
2185                 }
2186             }
2187             else
2188             {
2189                 /* This should never reach or the packet is gone. */
2190                 configASSERT( pdFALSE );
2191             }
2192         }
2193     }
2194 }
2195 /*-----------------------------------------------------------*/
2196 
2197 /**
2198  * @brief Returns the IP address of the NIC.
2199  *
2200  * @return The IP address of the NIC.
2201  */
FreeRTOS_GetIPAddress(void)2202 uint32_t FreeRTOS_GetIPAddress( void )
2203 {
2204     NetworkEndPoint_t * pxEndPoint;
2205     uint32_t ulIPAddress;
2206 
2207     pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2208 
2209     #if ( ipconfigUSE_IPv6 != 0 )
2210         if( ENDPOINT_IS_IPv6( pxEndPoint ) )
2211         {
2212             for( ;
2213                  pxEndPoint != NULL;
2214                  pxEndPoint = FreeRTOS_NextEndPoint( NULL, pxEndPoint ) )
2215             {
2216                 /* Break if the endpoint is IPv4. */
2217                 if( pxEndPoint->bits.bIPv6 == 0U )
2218                 {
2219                     break;
2220                 }
2221             }
2222         }
2223     #endif /* ( ipconfigUSE_IPv6 != 0 ) */
2224 
2225     /* Returns the IP address of the NIC. */
2226     if( pxEndPoint == NULL )
2227     {
2228         ulIPAddress = 0U;
2229     }
2230     else if( pxEndPoint->ipv4_settings.ulIPAddress != 0U )
2231     {
2232         ulIPAddress = pxEndPoint->ipv4_settings.ulIPAddress;
2233     }
2234     else
2235     {
2236         ulIPAddress = pxEndPoint->ipv4_defaults.ulIPAddress;
2237     }
2238 
2239     return ulIPAddress;
2240 }
2241 /*-----------------------------------------------------------*/
2242 
2243 #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
2244 
2245 /*
2246  * The helper functions here below assume that there is a single
2247  * interface and a single end-point (ipconfigIPv4_BACKWARD_COMPATIBLE)
2248  */
2249 
2250 /**
2251  * @brief Sets the IP address of the NIC.
2252  *
2253  * @param[in] ulIPAddress IP address of the NIC to be set.
2254  */
FreeRTOS_SetIPAddress(uint32_t ulIPAddress)2255     void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )
2256     {
2257         /* Sets the IP address of the NIC. */
2258         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2259 
2260         if( pxEndPoint != NULL )
2261         {
2262             pxEndPoint->ipv4_settings.ulIPAddress = ulIPAddress;
2263         }
2264     }
2265 /*-----------------------------------------------------------*/
2266 
2267 /**
2268  * @brief Get the gateway address of the subnet.
2269  *
2270  * @return The IP-address of the gateway, zero if a gateway is
2271  *         not used/defined.
2272  */
FreeRTOS_GetGatewayAddress(void)2273     uint32_t FreeRTOS_GetGatewayAddress( void )
2274     {
2275         uint32_t ulIPAddress = 0U;
2276         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2277 
2278         if( pxEndPoint != NULL )
2279         {
2280             ulIPAddress = pxEndPoint->ipv4_settings.ulGatewayAddress;
2281         }
2282 
2283         return ulIPAddress;
2284     }
2285 /*-----------------------------------------------------------*/
2286 
2287 /**
2288  * @brief Get the DNS server address.
2289  *
2290  * @return The IP address of the DNS server.
2291  */
FreeRTOS_GetDNSServerAddress(void)2292     uint32_t FreeRTOS_GetDNSServerAddress( void )
2293     {
2294         uint32_t ulIPAddress = 0U;
2295         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2296 
2297         if( pxEndPoint != NULL )
2298         {
2299             ulIPAddress = pxEndPoint->ipv4_settings.ulDNSServerAddresses[ 0 ];
2300         }
2301 
2302         return ulIPAddress;
2303     }
2304 /*-----------------------------------------------------------*/
2305 
2306 /**
2307  * @brief Get the netmask for the subnet.
2308  *
2309  * @return The 32 bit netmask for the subnet.
2310  */
FreeRTOS_GetNetmask(void)2311     uint32_t FreeRTOS_GetNetmask( void )
2312     {
2313         uint32_t ulIPAddress = 0U;
2314         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2315 
2316         if( pxEndPoint != NULL )
2317         {
2318             ulIPAddress = pxEndPoint->ipv4_settings.ulNetMask;
2319         }
2320 
2321         return ulIPAddress;
2322     }
2323 /*-----------------------------------------------------------*/
2324 
2325 /**
2326  * @brief Update the MAC address.
2327  *
2328  * @param[in] ucMACAddress the MAC address to be set.
2329  */
FreeRTOS_UpdateMACAddress(const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES])2330     void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ ipMAC_ADDRESS_LENGTH_BYTES ] )
2331     {
2332         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2333 
2334         if( pxEndPoint != NULL )
2335         {
2336             /* Copy the MAC address at the start of the default packet header fragment. */
2337             ( void ) memcpy( pxEndPoint->xMACAddress.ucBytes, ( const void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
2338         }
2339     }
2340 /*-----------------------------------------------------------*/
2341 
2342 /**
2343  * @brief Get the MAC address.
2344  *
2345  * @return The pointer to MAC address.
2346  */
FreeRTOS_GetMACAddress(void)2347     const uint8_t * FreeRTOS_GetMACAddress( void )
2348     {
2349         const uint8_t * pucReturn = NULL;
2350         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2351 
2352         if( pxEndPoint != NULL )
2353         {
2354             /* Copy the MAC address at the start of the default packet header fragment. */
2355             pucReturn = pxEndPoint->xMACAddress.ucBytes;
2356         }
2357 
2358         return pucReturn;
2359     }
2360 /*-----------------------------------------------------------*/
2361 
2362 /**
2363  * @brief Set the netmask for the subnet.
2364  *
2365  * @param[in] ulNetmask The 32 bit netmask of the subnet.
2366  */
FreeRTOS_SetNetmask(uint32_t ulNetmask)2367     void FreeRTOS_SetNetmask( uint32_t ulNetmask )
2368     {
2369         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2370 
2371         if( pxEndPoint != NULL )
2372         {
2373             pxEndPoint->ipv4_settings.ulNetMask = ulNetmask;
2374         }
2375     }
2376 /*-----------------------------------------------------------*/
2377 
2378 /**
2379  * @brief Set the gateway address.
2380  *
2381  * @param[in] ulGatewayAddress The gateway address.
2382  */
FreeRTOS_SetGatewayAddress(uint32_t ulGatewayAddress)2383     void FreeRTOS_SetGatewayAddress( uint32_t ulGatewayAddress )
2384     {
2385         NetworkEndPoint_t * pxEndPoint = FreeRTOS_FirstEndPoint( NULL );
2386 
2387         if( pxEndPoint != NULL )
2388         {
2389             pxEndPoint->ipv4_settings.ulGatewayAddress = ulGatewayAddress;
2390         }
2391     }
2392 /*-----------------------------------------------------------*/
2393 #endif /* if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
2394 
2395 /**
2396  * @brief Returns whether the IP task is ready.
2397  *
2398  * @return pdTRUE if IP task is ready, else pdFALSE.
2399  */
xIPIsNetworkTaskReady(void)2400 BaseType_t xIPIsNetworkTaskReady( void )
2401 {
2402     return xIPTaskInitialised;
2403 }
2404 /*-----------------------------------------------------------*/
2405 
2406 /**
2407  * @brief Returns whether all end-points are up.
2408  *
2409  * @return pdTRUE if all defined end-points are up.
2410  */
FreeRTOS_IsNetworkUp(void)2411 BaseType_t FreeRTOS_IsNetworkUp( void )
2412 {
2413     /* IsNetworkUp() is kept for backward compatibility. */
2414     return FreeRTOS_IsEndPointUp( NULL );
2415 }
2416 /*-----------------------------------------------------------*/
2417 
2418 /**
2419  * @brief The variable 'xNetworkDownEventPending' is declared static.  This function
2420  *        gives read-only access to it.
2421  *
2422  * @return pdTRUE if there a network-down event pending. pdFALSE otherwise.
2423  */
xIsNetworkDownEventPending(void)2424 BaseType_t xIsNetworkDownEventPending( void )
2425 {
2426     return xNetworkDownEventPending;
2427 }
2428 /*-----------------------------------------------------------*/
2429 
2430 /**
2431  * @brief Returns whether a particular end-point is up.
2432  *
2433  * @return pdTRUE if a particular end-points is up.
2434  */
FreeRTOS_IsEndPointUp(const struct xNetworkEndPoint * pxEndPoint)2435 BaseType_t FreeRTOS_IsEndPointUp( const struct xNetworkEndPoint * pxEndPoint )
2436 {
2437     BaseType_t xReturn;
2438 
2439     if( pxEndPoint != NULL )
2440     {
2441         /* Is this particular end-point up? */
2442         xReturn = ( BaseType_t ) pxEndPoint->bits.bEndPointUp;
2443     }
2444     else
2445     {
2446         /* Are all end-points up? */
2447         xReturn = FreeRTOS_AllEndPointsUp( NULL );
2448     }
2449 
2450     return xReturn;
2451 }
2452 /*-----------------------------------------------------------*/
2453 
2454 /**
2455  * @brief Return pdTRUE if all end-points belonging to a given interface are up.  When
2456  *        pxInterface is null, all end-points will be checked.
2457  *
2458  * @param[in] pxInterface The network interface of interest, or NULL to check all end-points.
2459  *
2460  * @return pdTRUE if all end-points are up, otherwise pdFALSE;
2461  */
FreeRTOS_AllEndPointsUp(const struct xNetworkInterface * pxInterface)2462 BaseType_t FreeRTOS_AllEndPointsUp( const struct xNetworkInterface * pxInterface )
2463 {
2464     BaseType_t xResult = pdTRUE;
2465     const NetworkEndPoint_t * pxEndPoint = pxNetworkEndPoints;
2466 
2467     while( pxEndPoint != NULL )
2468     {
2469         if( ( pxInterface == NULL ) ||
2470             ( pxEndPoint->pxNetworkInterface == pxInterface ) )
2471 
2472         {
2473             if( pxEndPoint->bits.bEndPointUp == pdFALSE_UNSIGNED )
2474             {
2475                 xResult = pdFALSE;
2476                 break;
2477             }
2478         }
2479 
2480         pxEndPoint = pxEndPoint->pxNext;
2481     }
2482 
2483     return xResult;
2484 }
2485 /*-----------------------------------------------------------*/
2486 
2487 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
2488 
2489 /**
2490  * @brief Get the minimum space in the IP task queue.
2491  *
2492  * @return The minimum possible space in the IP task queue.
2493  */
uxGetMinimumIPQueueSpace(void)2494     UBaseType_t uxGetMinimumIPQueueSpace( void )
2495     {
2496         return uxQueueMinimumSpace;
2497     }
2498 #endif
2499 /*-----------------------------------------------------------*/
2500 
2501 /**
2502  * @brief Get the size of the IP-header, by checking the type of the network buffer.
2503  * @param[in] pxNetworkBuffer The network buffer.
2504  * @return The size of the corresponding IP-header.
2505  */
uxIPHeaderSizePacket(const NetworkBufferDescriptor_t * pxNetworkBuffer)2506 size_t uxIPHeaderSizePacket( const NetworkBufferDescriptor_t * pxNetworkBuffer )
2507 {
2508     size_t uxResult;
2509     /* Map the buffer onto Ethernet Header struct for easy access to fields. */
2510     /* MISRA Ref 11.3.1 [Misaligned access] */
2511     /* More details at: https://github.com/FreeRTOS/FreeRTOS-Plus-TCP/blob/main/MISRA.md#rule-113 */
2512     /* coverity[misra_c_2012_rule_11_3_violation] */
2513     const EthernetHeader_t * pxHeader = ( ( const EthernetHeader_t * ) pxNetworkBuffer->pucEthernetBuffer );
2514 
2515     if( pxHeader->usFrameType == ( uint16_t ) ipIPv6_FRAME_TYPE )
2516     {
2517         uxResult = ipSIZE_OF_IPv6_HEADER;
2518     }
2519     else
2520     {
2521         uxResult = ipSIZE_OF_IPv4_HEADER;
2522     }
2523 
2524     return uxResult;
2525 }
2526 /*-----------------------------------------------------------*/
2527 
2528 /**
2529  * @brief Get the size of the IP-header, by checking if the socket bIsIPv6 set.
2530  * @param[in] pxSocket The socket.
2531  * @return The size of the corresponding IP-header.
2532  */
uxIPHeaderSizeSocket(const FreeRTOS_Socket_t * pxSocket)2533 size_t uxIPHeaderSizeSocket( const FreeRTOS_Socket_t * pxSocket )
2534 {
2535     size_t uxResult;
2536 
2537     if( ( pxSocket != NULL ) && ( pxSocket->bits.bIsIPv6 != pdFALSE_UNSIGNED ) )
2538     {
2539         uxResult = ipSIZE_OF_IPv6_HEADER;
2540     }
2541     else
2542     {
2543         uxResult = ipSIZE_OF_IPv4_HEADER;
2544     }
2545 
2546     return uxResult;
2547 }
2548 /*-----------------------------------------------------------*/
2549 
2550 /* Provide access to private members for verification. */
2551 #ifdef FREERTOS_TCP_ENABLE_VERIFICATION
2552     #include "aws_freertos_ip_verification_access_ip_define.h"
2553 #endif
2554