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