3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
6 * this software and associated documentation files (the "Software"), to deal in
7 * the Software without restriction, including without limitation the rights to
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 * the Software, and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * http://aws.amazon.com/freertos
23 * http://www.FreeRTOS.org
26 /* Standard includes. */
31 /* FreeRTOS includes. */
37 /* FreeRTOS+TCP includes. */
38 #include "FreeRTOS_IP.h"
39 #include "FreeRTOS_Sockets.h"
40 #include "FreeRTOS_IP_Private.h"
41 #include "FreeRTOS_ARP.h"
42 #include "FreeRTOS_UDP_IP.h"
43 #include "FreeRTOS_TCP_IP.h"
44 #include "FreeRTOS_DHCP.h"
45 #include "NetworkInterface.h"
46 #include "NetworkBufferManagement.h"
47 #include "FreeRTOS_DNS.h"
50 /* Used to ensure the structure packing is having the desired effect. The
51 'volatile' is used to prevent compiler warnings about comparing a constant with
53 #define ipEXPECTED_EthernetHeader_t_SIZE ( ( size_t ) 14 )
54 #define ipEXPECTED_ARPHeader_t_SIZE ( ( size_t ) 28 )
55 #define ipEXPECTED_IPHeader_t_SIZE ( ( size_t ) 20 )
56 #define ipEXPECTED_IGMPHeader__SIZE ( ( size_t ) 8 )
57 #define ipEXPECTED_ICMPHeader_t_SIZE ( ( size_t ) 8 )
58 #define ipEXPECTED_UDPHeader_t_SIZE ( ( size_t ) 8 )
59 #define ipEXPECTED_TCPHeader_t_SIZE ( ( size_t ) 20 )
62 /* ICMP protocol definitions. */
63 #define ipICMP_ECHO_REQUEST ( ( uint8_t ) 8 )
64 #define ipICMP_ECHO_REPLY ( ( uint8_t ) 0 )
67 /* Time delay between repeated attempts to initialise the network hardware. */
68 #ifndef ipINITIALISATION_RETRY_DELAY
69 #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) )
72 /* Defines how often the ARP timer callback function is executed. The time is
73 shorted in the Windows simulator as simulated time is not real time. */
74 #ifndef ipARP_TIMER_PERIOD_MS
76 #define ipARP_TIMER_PERIOD_MS ( 500 ) /* For windows simulator builds. */
78 #define ipARP_TIMER_PERIOD_MS ( 10000 )
82 #ifndef iptraceIP_TASK_STARTING
83 #define iptraceIP_TASK_STARTING() do {} while( 0 )
86 #if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
87 /* When initialising the TCP timer,
88 give it an initial time-out of 1 second. */
89 #define ipTCP_TIMER_PERIOD_MS ( 1000 )
92 /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
93 driver will filter incoming packets and only pass the stack those packets it
94 considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
95 be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
96 then the Ethernet driver will pass all received packets to the stack, and the
97 stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
98 needs to call eConsiderFrameForProcessing. */
99 #if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
100 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
102 #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
105 /* The character used to fill ICMP echo requests, and therefore also the
106 character expected to fill ICMP echo replies. */
107 #define ipECHO_DATA_FILL_BYTE 'x'
109 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
110 /* The bits in the two byte IP header field that make up the fragment offset value. */
111 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff0f )
113 /* The bits in the two byte IP header field that make up the fragment offset value. */
114 #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff )
115 #endif /* ipconfigBYTE_ORDER */
117 /* The maximum time the IP task is allowed to remain in the Blocked state if no
118 events are posted to the network event queue. */
119 #ifndef ipconfigMAX_IP_TASK_SLEEP_TIME
120 #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )
123 /* When a new TCP connection is established, the value of
124 'ulNextInitialSequenceNumber' will be used as the initial sequence number. It
125 is very important that at start-up, 'ulNextInitialSequenceNumber' contains a
126 random value. Also its value must be increased continuously in time, to prevent
127 a third party guessing the next sequence number and take-over a TCP connection.
128 It is advised to increment it by 1 ever 4us, which makes about 256 times
130 #define ipINITIAL_SEQUENCE_NUMBER_FACTOR 256UL
132 /* Returned as the (invalid) checksum when the protocol being checked is not
133 handled. The value is chosen simply to be easy to spot when debugging. */
134 #define ipUNHANDLED_PROTOCOL 0x4321u
136 /* Returned to indicate a valid checksum when the checksum does not need to be
138 #define ipCORRECT_CRC 0xffffu
140 /* Returned as the (invalid) checksum when the length of the data being checked
141 had an invalid length. */
142 #define ipINVALID_LENGTH 0x1234u
144 /*-----------------------------------------------------------*/
146 typedef struct xIP_TIMER
149 bActive : 1, /* This timer is running and must be processed. */
150 bExpired : 1; /* Timer has expired and a task must be processed. */
152 TickType_t ulRemainingTime;
153 TickType_t ulReloadTime;
156 /* Used in checksum calculation. */
157 typedef union _xUnion32
164 /* Used in checksum calculation. */
165 typedef union _xUnionPtr
172 /*-----------------------------------------------------------*/
175 * The main TCP/IP stack processing task. This task receives commands/events
176 * from the network hardware drivers and tasks that are using sockets. It also
177 * maintains a set of protocol timers.
179 static void prvIPTask( void *pvParameters );
182 * Called when new data is available from the network interface.
184 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
187 * Process incoming IP packets.
189 static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );
191 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
193 * Process incoming ICMP packets.
195 static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket );
196 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
199 * Turns around an incoming ping request to convert it into a ping reply.
201 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
202 static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket );
203 #endif /* ipconfigREPLY_TO_INCOMING_PINGS */
206 * Processes incoming ping replies. The application callback function
207 * vApplicationPingReplyHook() is called with the results.
209 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
210 static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );
211 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
214 * Called to create a network connection when the stack is first started, or
215 * when the network connection is lost.
217 static void prvProcessNetworkDownEvent( void );
220 * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout
221 * processing is required.
223 static void prvCheckNetworkTimers( void );
226 * Determine how long the IP task can sleep for, which depends on when the next
227 * periodic or timeout processing must be performed.
229 static TickType_t prvCalculateSleepTime( void );
232 * The network card driver has received a packet. In the case that it is part
233 * of a linked packet chain, walk through it to handle every message.
235 static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer );
238 * Utility functions for the light weight IP timers.
240 static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime );
241 static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer );
242 static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime );
244 static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
245 NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength );
247 /*-----------------------------------------------------------*/
249 /* The queue used to pass events into the IP-task for processing. */
250 QueueHandle_t xNetworkEventQueue = NULL;
252 /*_RB_ Requires comment. */
253 uint16_t usPacketIdentifier = 0U;
255 /* For convenience, a MAC address of all 0xffs is defined const for quick
257 const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
259 /* Structure that stores the netmask, gateway address and DNS server addresses. */
260 NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 };
262 /* Default values for the above struct in case DHCP
263 does not lead to a confirmed request. */
264 NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };
266 /* Used to ensure network down events cannot be missed when they cannot be
267 posted to the network event queue because the network event queue is already
269 static BaseType_t xNetworkDownEventPending = pdFALSE;
271 /* Stores the handle of the task that handles the stack. The handle is used
272 (indirectly) by some utility function to determine if the utility function is
273 being called by a task (in which case it is ok to block) or by the IP task
274 itself (in which case it is not ok to block). */
275 static TaskHandle_t xIPTaskHandle = NULL;
277 #if( ipconfigUSE_TCP != 0 )
278 /* Set to a non-zero value if one or more TCP message have been processed
279 within the last round. */
280 static BaseType_t xProcessedTCPMessage;
283 /* Simple set to pdTRUE or pdFALSE depending on whether the network is up or
284 down (connected, not connected) respectively. */
285 static BaseType_t xNetworkUp = pdFALSE;
288 A timer for each of the following processes, all of which need attention on a
290 1. ARP, to check its table entries
291 2. DPHC, to send requests and to renew a reservation
292 3. TCP, to check for timeouts, resends
293 4. DNS, to check for timeouts when looking-up a domain.
295 static IPTimer_t xARPTimer;
296 #if( ipconfigUSE_DHCP != 0 )
297 static IPTimer_t xDHCPTimer;
299 #if( ipconfigUSE_TCP != 0 )
300 static IPTimer_t xTCPTimer;
302 #if( ipconfigDNS_USE_CALLBACKS != 0 )
303 static IPTimer_t xDNSTimer;
306 /* Set to pdTRUE when the IP task is ready to start processing packets. */
307 static BaseType_t xIPTaskInitialised = pdFALSE;
309 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
310 /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
311 static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;
314 /*-----------------------------------------------------------*/
316 static void prvIPTask( void *pvParameters )
318 IPStackEvent_t xReceivedEvent;
319 TickType_t xNextIPSleep;
320 FreeRTOS_Socket_t *pxSocket;
321 struct freertos_sockaddr xAddress;
323 /* Just to prevent compiler warnings about unused parameters. */
324 ( void ) pvParameters;
326 /* A possibility to set some additional task properties. */
327 iptraceIP_TASK_STARTING();
329 /* Generate a dummy message to say that the network connection has gone
330 down. This will cause this task to initialise the network interface. After
331 this it is the responsibility of the network interface hardware driver to
332 send this message if a previously connected network is disconnected. */
333 FreeRTOS_NetworkDown();
335 #if( ipconfigUSE_TCP == 1 )
337 /* Initialise the TCP timer. */
338 prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
342 /* Initialisation is complete and events can now be processed. */
343 xIPTaskInitialised = pdTRUE;
345 FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );
347 /* Loop, processing IP events. */
350 ipconfigWATCHDOG_TIMER();
352 /* Check the ARP, DHCP and TCP timers to see if there is any periodic
353 or timeout processing to perform. */
354 prvCheckNetworkTimers();
356 /* Calculate the acceptable maximum sleep time. */
357 xNextIPSleep = prvCalculateSleepTime();
359 /* Wait until there is something to do. If the following call exits
360 * due to a time out rather than a message being received, set a
361 * 'NoEvent' value. */
362 if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
364 xReceivedEvent.eEventType = eNoEvent;
367 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
369 if( xReceivedEvent.eEventType != eNoEvent )
373 uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );
374 if( uxQueueMinimumSpace > uxCount )
376 uxQueueMinimumSpace = uxCount;
380 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
382 iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
384 switch( xReceivedEvent.eEventType )
386 case eNetworkDownEvent :
387 /* Attempt to establish a connection. */
388 xNetworkUp = pdFALSE;
389 prvProcessNetworkDownEvent();
392 case eNetworkRxEvent:
393 /* The network hardware driver has received a new packet. A
394 pointer to the received buffer is located in the pvData member
395 of the received event structure. */
396 prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
399 case eNetworkTxEvent:
400 /* Send a network packet. The ownership will be transferred to
401 the driver, which will release it after delivery. */
402 xNetworkInterfaceOutput( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ), pdTRUE );
405 case eARPTimerEvent :
406 /* The ARP timer has expired, process the ARP cache. */
410 case eSocketBindEvent:
411 /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
412 to a port. The port number is communicated in the socket field
413 usLocalPort. vSocketBind() will actually bind the socket and the
414 API will unblock as soon as the eSOCKET_BOUND event is
416 pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );
417 xAddress.sin_addr = 0u; /* For the moment. */
418 xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
419 pxSocket->usLocalPort = 0u;
420 vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );
422 /* Before 'eSocketBindEvent' was sent it was tested that
423 ( xEventGroup != NULL ) so it can be used now to wake up the
425 pxSocket->xEventBits |= eSOCKET_BOUND;
426 vSocketWakeUpUser( pxSocket );
429 case eSocketCloseEvent :
430 /* The user API FreeRTOS_closesocket() has sent a message to the
431 IP-task to actually close a socket. This is handled in
432 vSocketClose(). As the socket gets closed, there is no way to
433 report back to the API, so the API won't wait for the result */
434 vSocketClose( ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ) );
438 /* The network stack has generated a packet to send. A
439 pointer to the generated buffer is located in the pvData
440 member of the received event structure. */
441 vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
445 /* The DHCP state machine needs processing. */
446 #if( ipconfigUSE_DHCP == 1 )
448 vDHCPProcess( pdFALSE );
450 #endif /* ipconfigUSE_DHCP */
453 case eSocketSelectEvent :
454 /* FreeRTOS_select() has got unblocked by a socket event,
455 vSocketSelect() will check which sockets actually have an event
456 and update the socket field xSocketBits. */
457 #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
459 vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) );
461 #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
464 case eSocketSignalEvent :
465 #if( ipconfigSUPPORT_SIGNALS != 0 )
467 /* Some task wants to signal the user of this socket in
468 order to interrupt a call to recv() or a call to select(). */
469 FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData );
471 #endif /* ipconfigSUPPORT_SIGNALS */
474 case eTCPTimerEvent :
475 #if( ipconfigUSE_TCP == 1 )
477 /* Simply mark the TCP timer as expired so it gets processed
478 the next time prvCheckNetworkTimers() is called. */
479 xTCPTimer.bExpired = pdTRUE_UNSIGNED;
481 #endif /* ipconfigUSE_TCP */
484 case eTCPAcceptEvent:
485 /* The API FreeRTOS_accept() was called, the IP-task will now
486 check if the listening socket (communicated in pvData) actually
487 received a new connection. */
488 #if( ipconfigUSE_TCP == 1 )
490 pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );
492 if( xTCPCheckNewClient( pxSocket ) != pdFALSE )
494 pxSocket->xEventBits |= eSOCKET_ACCEPT;
495 vSocketWakeUpUser( pxSocket );
498 #endif /* ipconfigUSE_TCP */
502 /* FreeRTOS_netstat() was called to have the IP-task print an
503 overview of all sockets and their connections */
504 #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )
508 #endif /* ipconfigUSE_TCP */
512 /* Should not get here. */
516 if( xNetworkDownEventPending != pdFALSE )
518 /* A network down event could not be posted to the network event
519 queue because the queue was full. Try posting again. */
520 FreeRTOS_NetworkDown();
524 /*-----------------------------------------------------------*/
526 BaseType_t xIsCallingFromIPTask( void )
530 if( xTaskGetCurrentTaskHandle() == xIPTaskHandle )
541 /*-----------------------------------------------------------*/
543 static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer )
545 #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
547 /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one
548 buffer will be sent at a time. This is the default way for +TCP to pass
549 messages from the MAC to the TCP/IP stack. */
550 prvProcessEthernetPacket( pxBuffer );
552 #else /* ipconfigUSE_LINKED_RX_MESSAGES */
554 NetworkBufferDescriptor_t *pxNextBuffer;
556 /* An optimisation that is useful when there is high network traffic.
557 Instead of passing received packets into the IP task one at a time the
558 network interface can chain received packets together and pass them into
559 the IP task in one go. The packets are chained using the pxNextBuffer
560 member. The loop below walks through the chain processing each packet
561 in the chain in turn. */
564 /* Store a pointer to the buffer after pxBuffer for use later on. */
565 pxNextBuffer = pxBuffer->pxNextBuffer;
567 /* Make it NULL to avoid using it later on. */
568 pxBuffer->pxNextBuffer = NULL;
570 prvProcessEthernetPacket( pxBuffer );
571 pxBuffer = pxNextBuffer;
573 /* While there is another packet in the chain. */
574 } while( pxBuffer != NULL );
576 #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
578 /*-----------------------------------------------------------*/
580 static TickType_t prvCalculateSleepTime( void )
582 TickType_t xMaximumSleepTime;
584 /* Start with the maximum sleep time, then check this against the remaining
585 time in any other timers that are active. */
586 xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
588 if( xARPTimer.bActive != pdFALSE_UNSIGNED )
590 if( xARPTimer.ulRemainingTime < xMaximumSleepTime )
592 xMaximumSleepTime = xARPTimer.ulReloadTime;
596 #if( ipconfigUSE_DHCP == 1 )
598 if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
600 if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime )
602 xMaximumSleepTime = xDHCPTimer.ulRemainingTime;
606 #endif /* ipconfigUSE_DHCP */
608 #if( ipconfigUSE_TCP == 1 )
610 if( xTCPTimer.ulRemainingTime < xMaximumSleepTime )
612 xMaximumSleepTime = xTCPTimer.ulRemainingTime;
617 #if( ipconfigDNS_USE_CALLBACKS != 0 )
619 if( xDNSTimer.bActive != pdFALSE )
621 if( xDNSTimer.ulRemainingTime < xMaximumSleepTime )
623 xMaximumSleepTime = xDNSTimer.ulRemainingTime;
629 return xMaximumSleepTime;
631 /*-----------------------------------------------------------*/
633 static void prvCheckNetworkTimers( void )
635 /* Is it time for ARP processing? */
636 if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
638 xSendEventToIPTask( eARPTimerEvent );
641 #if( ipconfigUSE_DHCP == 1 )
643 /* Is it time for DHCP processing? */
644 if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
646 xSendEventToIPTask( eDHCPEvent );
649 #endif /* ipconfigUSE_DHCP */
651 #if( ipconfigDNS_USE_CALLBACKS != 0 )
653 extern void vDNSCheckCallBack( void *pvSearchID );
655 /* Is it time for DNS processing? */
656 if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
658 vDNSCheckCallBack( NULL );
661 #endif /* ipconfigDNS_USE_CALLBACKS */
663 #if( ipconfigUSE_TCP == 1 )
665 BaseType_t xWillSleep;
666 TickType_t xNextTime;
667 BaseType_t xCheckTCPSockets;
669 if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )
675 xWillSleep = pdFALSE;
678 /* Sockets need to be checked if the TCP timer has expired. */
679 xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
681 /* Sockets will also be checked if there are TCP messages but the
682 message queue is empty (indicated by xWillSleep being true). */
683 if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
685 xCheckTCPSockets = pdTRUE;
688 if( xCheckTCPSockets != pdFALSE )
690 /* Attend to the sockets, returning the period after which the
691 check must be repeated. */
692 xNextTime = xTCPTimerCheck( xWillSleep );
693 prvIPTimerStart( &xTCPTimer, xNextTime );
694 xProcessedTCPMessage = 0;
697 #endif /* ipconfigUSE_TCP == 1 */
699 /*-----------------------------------------------------------*/
701 static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime )
703 vTaskSetTimeOutState( &pxTimer->xTimeOut );
704 pxTimer->ulRemainingTime = xTime;
706 if( xTime == ( TickType_t ) 0 )
708 pxTimer->bExpired = pdTRUE_UNSIGNED;
712 pxTimer->bExpired = pdFALSE_UNSIGNED;
715 pxTimer->bActive = pdTRUE_UNSIGNED;
717 /*-----------------------------------------------------------*/
719 static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime )
721 pxTimer->ulReloadTime = xTime;
722 prvIPTimerStart( pxTimer, xTime );
724 /*-----------------------------------------------------------*/
726 static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer )
730 if( pxTimer->bActive == pdFALSE_UNSIGNED )
732 /* The timer is not enabled. */
737 /* The timer might have set the bExpired flag already, if not, check the
738 value of xTimeOut against ulRemainingTime. */
739 if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) ||
740 ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) )
742 prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
753 /*-----------------------------------------------------------*/
755 void FreeRTOS_NetworkDown( void )
757 static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
758 const TickType_t xDontBlock = ( TickType_t ) 0;
760 /* Simply send the network task the appropriate event. */
761 if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )
763 /* Could not send the message, so it is still pending. */
764 xNetworkDownEventPending = pdTRUE;
768 /* Message was sent so it is not pending. */
769 xNetworkDownEventPending = pdFALSE;
772 iptraceNETWORK_DOWN();
774 /*-----------------------------------------------------------*/
776 BaseType_t FreeRTOS_NetworkDownFromISR( void )
778 static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
779 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
781 /* Simply send the network task the appropriate event. */
782 if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
784 xNetworkDownEventPending = pdTRUE;
788 xNetworkDownEventPending = pdFALSE;
791 iptraceNETWORK_DOWN();
793 return xHigherPriorityTaskWoken;
795 /*-----------------------------------------------------------*/
797 void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
799 NetworkBufferDescriptor_t *pxNetworkBuffer;
802 /* Cap the block time. The reason for this is explained where
803 ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
804 FreeRTOSIPConfig.h header file is being used). */
805 if( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
807 xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
810 /* Obtain a network buffer with the required amount of storage. */
811 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );
813 if( pxNetworkBuffer != NULL )
815 /* Set the actual packet size in case a bigger buffer was returned. */
816 pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + xRequestedSizeBytes;
818 /* Leave space for the UPD header. */
819 pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
826 return ( void * ) pvReturn;
828 /*-----------------------------------------------------------*/
830 NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer,
833 NetworkBufferDescriptor_t * pxNewBuffer;
835 /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.
836 The transmit routine wants to have ownership of the network buffer
837 descriptor, because it will pass the buffer straight to DMA. */
838 pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );
840 if( pxNewBuffer != NULL )
842 /* Set the actual packet size in case a bigger buffer than requested
844 pxNewBuffer->xDataLength = uxNewLength;
846 /* Copy the original packet information. */
847 pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;
848 pxNewBuffer->usPort = pxNetworkBuffer->usPort;
849 pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;
850 memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
855 /*-----------------------------------------------------------*/
857 #if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
859 NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer )
862 NetworkBufferDescriptor_t *pxResult;
864 if( pvBuffer == NULL )
870 /* Obtain the network buffer from the zero copy pointer. */
871 pucBuffer = ( uint8_t * ) pvBuffer;
873 /* The input here is a pointer to a payload buffer. Subtract the
874 size of the header in the network buffer, usually 8 + 2 bytes. */
875 pucBuffer -= ipBUFFER_PADDING;
877 /* Here a pointer was placed to the network descriptor. As a
878 pointer is dereferenced, make sure it is well aligned. */
879 if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 )
881 pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );
892 #endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */
893 /*-----------------------------------------------------------*/
895 NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer )
898 NetworkBufferDescriptor_t *pxResult;
900 if( pvBuffer == NULL )
906 /* Obtain the network buffer from the zero copy pointer. */
907 pucBuffer = ( uint8_t * ) pvBuffer;
909 /* The input here is a pointer to a payload buffer. Subtract
910 the total size of a UDP/IP header plus the size of the header in
911 the network buffer, usually 8 + 2 bytes. */
912 pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING );
914 /* Here a pointer was placed to the network descriptor,
915 As a pointer is dereferenced, make sure it is well aligned */
916 if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 )
918 /* The following statement may trigger a:
919 warning: cast increases required alignment of target type [-Wcast-align].
920 It has been confirmed though that the alignment is suitable. */
921 pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );
931 /*-----------------------------------------------------------*/
933 void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )
935 vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) );
937 /*-----------------------------------------------------------*/
939 /*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */
940 /*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.
941 As that bug has been repaired, there is not an urgent reason to warn.
942 It is better though to use the advised priority scheme. */
943 BaseType_t 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 ] )
945 BaseType_t xReturn = pdFALSE;
947 /* This function should only be called once. */
948 configASSERT( xIPIsNetworkTaskReady() == pdFALSE );
949 configASSERT( xNetworkEventQueue == NULL );
950 configASSERT( xIPTaskHandle == NULL );
952 /* Check structure packing is correct. */
953 configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE );
954 configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE );
955 configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE );
956 configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE );
957 configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE );
959 /* Attempt to create the queue used to communicate with the IP task. */
960 xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) );
961 configASSERT( xNetworkEventQueue );
963 if( xNetworkEventQueue != NULL )
965 #if ( configQUEUE_REGISTRY_SIZE > 0 )
967 /* A queue registry is normally used to assist a kernel aware
968 debugger. If one is in use then it will be helpful for the debugger
969 to show information about the network event queue. */
970 vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
972 #endif /* configQUEUE_REGISTRY_SIZE */
974 if( xNetworkBuffersInitialise() == pdPASS )
976 /* Store the local IP and MAC address. */
977 xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
978 xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
979 xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
980 xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
981 xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
983 memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) );
985 #if ipconfigUSE_DHCP == 1
987 /* The IP address is not set until DHCP completes. */
988 *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;
992 /* The IP address is set from the value passed in. */
993 *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
995 /* Added to prevent ARP flood to gateway. Ensure the
996 gateway is on the same subnet as the IP address. */
997 if( xNetworkAddressing.ulGatewayAddress != 0ul )
999 configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );
1002 #endif /* ipconfigUSE_DHCP == 1 */
1004 /* The MAC address is stored in the start of the default packet
1005 header fragment, which is used when sending UDP packets. */
1006 memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
1008 /* Prepare the sockets interface. */
1009 xReturn = vNetworkSocketsInit();
1011 if( pdTRUE == xReturn )
1013 /* Create the task that processes Ethernet and stack events. */
1014 xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );
1019 FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") );
1022 vQueueDelete( xNetworkEventQueue );
1023 xNetworkEventQueue = NULL;
1028 FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") );
1033 /*-----------------------------------------------------------*/
1035 void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )
1037 /* Return the address configuration to the caller. */
1039 if( pulIPAddress != NULL )
1041 *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
1044 if( pulNetMask != NULL )
1046 *pulNetMask = xNetworkAddressing.ulNetMask;
1049 if( pulGatewayAddress != NULL )
1051 *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;
1054 if( pulDNSServerAddress != NULL )
1056 *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;
1059 /*-----------------------------------------------------------*/
1061 void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress )
1063 /* Update the address configuration. */
1065 if( pulIPAddress != NULL )
1067 *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress;
1070 if( pulNetMask != NULL )
1072 xNetworkAddressing.ulNetMask = *pulNetMask;
1075 if( pulGatewayAddress != NULL )
1077 xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress;
1080 if( pulDNSServerAddress != NULL )
1082 xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress;
1085 /*-----------------------------------------------------------*/
1087 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1089 BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks )
1091 NetworkBufferDescriptor_t *pxNetworkBuffer;
1092 ICMPHeader_t *pxICMPHeader;
1093 BaseType_t xReturn = pdFAIL;
1094 static uint16_t usSequenceNumber = 0;
1096 IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
1098 if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) )
1100 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks );
1102 if( pxNetworkBuffer != NULL )
1104 pxICMPHeader = ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );
1107 /* Fill in the basic header information. */
1108 pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
1109 pxICMPHeader->ucTypeOfService = 0;
1110 pxICMPHeader->usIdentifier = usSequenceNumber;
1111 pxICMPHeader->usSequenceNumber = usSequenceNumber;
1113 /* Find the start of the data. */
1114 pucChar = ( uint8_t * ) pxICMPHeader;
1115 pucChar += sizeof( ICMPHeader_t );
1117 /* Just memset the data to a fixed value. */
1118 memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );
1120 /* The message is complete, IP and checksum's are handled by
1121 vProcessGeneratedUDPPacket */
1122 pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;
1123 pxNetworkBuffer->ulIPAddress = ulIPAddress;
1124 pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
1125 /* xDataLength is the size of the total packet, including the Ethernet header. */
1126 pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPPacket_t );
1128 /* Send to the stack. */
1129 xStackTxEvent.pvData = pxNetworkBuffer;
1131 if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS )
1133 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1134 iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
1138 xReturn = usSequenceNumber;
1144 /* The requested number of bytes will not fit in the available space
1145 in the network buffer. */
1151 #endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
1152 /*-----------------------------------------------------------*/
1154 BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )
1156 IPStackEvent_t xEventMessage;
1157 const TickType_t xDontBlock = ( TickType_t ) 0;
1159 xEventMessage.eEventType = eEvent;
1160 xEventMessage.pvData = ( void* )NULL;
1162 return xSendEventStructToIPTask( &xEventMessage, xDontBlock );
1164 /*-----------------------------------------------------------*/
1166 BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout )
1168 BaseType_t xReturn, xSendMessage;
1170 if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )
1172 /* Only allow eNetworkDownEvent events if the IP task is not ready
1173 yet. Not going to attempt to send the message so the send failed. */
1178 xSendMessage = pdTRUE;
1180 #if( ipconfigUSE_TCP == 1 )
1182 if( pxEvent->eEventType == eTCPTimerEvent )
1184 /* TCP timer events are sent to wake the timer task when
1185 xTCPTimer has expired, but there is no point sending them if the
1186 IP task is already awake processing other message. */
1187 xTCPTimer.bExpired = pdTRUE_UNSIGNED;
1189 if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0u )
1191 /* Not actually going to send the message but this is not a
1192 failure as the message didn't need to be sent. */
1193 xSendMessage = pdFALSE;
1197 #endif /* ipconfigUSE_TCP */
1199 if( xSendMessage != pdFALSE )
1201 /* The IP task cannot block itself while waiting for itself to
1203 if( ( xIsCallingFromIPTask() == pdTRUE ) && ( xTimeout > ( TickType_t ) 0 ) )
1205 xTimeout = ( TickType_t ) 0;
1208 xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout );
1210 if( xReturn == pdFAIL )
1212 /* A message should have been sent to the IP task, but wasn't. */
1213 FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );
1214 iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );
1219 /* It was not necessary to send the message to process the event so
1220 even though the message was not sent the call was successful. */
1227 /*-----------------------------------------------------------*/
1229 eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
1231 eFrameProcessingResult_t eReturn;
1232 const EthernetHeader_t *pxEthernetHeader;
1234 pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer;
1236 if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 )
1238 /* The packet was directed to this node directly - process it. */
1239 eReturn = eProcessBuffer;
1241 else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
1243 /* The packet was a broadcast - process it. */
1244 eReturn = eProcessBuffer;
1247 #if( ipconfigUSE_LLMNR == 1 )
1248 if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
1250 /* The packet is a request for LLMNR - process it. */
1251 eReturn = eProcessBuffer;
1254 #endif /* ipconfigUSE_LLMNR */
1256 /* The packet was not a broadcast, or for this node, just release
1257 the buffer without taking any other action. */
1258 eReturn = eReleaseBuffer;
1261 #if( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )
1263 uint16_t usFrameType;
1265 if( eReturn == eProcessBuffer )
1267 usFrameType = pxEthernetHeader->usFrameType;
1268 usFrameType = FreeRTOS_ntohs( usFrameType );
1270 if( usFrameType <= 0x600U )
1272 /* Not an Ethernet II frame. */
1273 eReturn = eReleaseBuffer;
1277 #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */
1281 /*-----------------------------------------------------------*/
1283 static void prvProcessNetworkDownEvent( void )
1285 /* Stop the ARP timer while there is no network. */
1286 xARPTimer.bActive = pdFALSE_UNSIGNED;
1288 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
1290 static BaseType_t xCallEventHook = pdFALSE;
1292 /* The first network down event is generated by the IP stack itself to
1293 initialise the network hardware, so do not call the network down event
1294 the first time through. */
1295 if( xCallEventHook == pdTRUE )
1297 vApplicationIPNetworkEventHook( eNetworkDown );
1299 xCallEventHook = pdTRUE;
1303 /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122,
1304 treat network down as a "delivery problem" and flush the ARP cache for this
1306 FreeRTOS_ClearARP( );
1308 /* The network has been disconnected (or is being initialised for the first
1309 time). Perform whatever hardware processing is necessary to bring it up
1310 again, or wait for it to be available again. This is hardware dependent. */
1311 if( xNetworkInterfaceInitialise() != pdPASS )
1313 /* Ideally the network interface initialisation function will only
1314 return when the network is available. In case this is not the case,
1315 wait a while before retrying the initialisation. */
1316 vTaskDelay( ipINITIALISATION_RETRY_DELAY );
1317 FreeRTOS_NetworkDown();
1321 /* Set remaining time to 0 so it will become active immediately. */
1322 #if ipconfigUSE_DHCP == 1
1324 /* The network is not up until DHCP has completed. */
1325 vDHCPProcess( pdTRUE );
1326 xSendEventToIPTask( eDHCPEvent );
1330 /* Perform any necessary 'network up' processing. */
1331 vIPNetworkUpCalls();
1336 /*-----------------------------------------------------------*/
1338 void vIPNetworkUpCalls( void )
1340 xNetworkUp = pdTRUE;
1342 #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
1344 vApplicationIPNetworkEventHook( eNetworkUp );
1346 #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
1348 #if( ipconfigDNS_USE_CALLBACKS != 0 )
1350 /* The following function is declared in FreeRTOS_DNS.c and 'private' to
1352 extern void vDNSInitialise( void );
1355 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
1357 /* Set remaining time to 0 so it will become active immediately. */
1358 prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );
1360 /*-----------------------------------------------------------*/
1362 static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
1364 EthernetHeader_t *pxEthernetHeader;
1365 eFrameProcessingResult_t eReturned = eReleaseBuffer;
1367 configASSERT( pxNetworkBuffer );
1369 /* Interpret the Ethernet frame. */
1370 if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )
1372 eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
1373 pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer );
1375 if( eReturned == eProcessBuffer )
1377 /* Interpret the received Ethernet packet. */
1378 switch( pxEthernetHeader->usFrameType )
1380 case ipARP_FRAME_TYPE:
1381 /* The Ethernet frame contains an ARP packet. */
1382 if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )
1384 eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer );
1388 eReturned = eReleaseBuffer;
1392 case ipIPv4_FRAME_TYPE:
1393 /* The Ethernet frame contains an IP packet. */
1394 if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )
1396 eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );
1400 eReturned = eReleaseBuffer;
1405 /* No other packet types are handled. Nothing to do. */
1406 eReturned = eReleaseBuffer;
1412 /* Perform any actions that resulted from processing the Ethernet frame. */
1415 case eReturnEthernetFrame :
1416 /* The Ethernet frame will have been updated (maybe it was
1417 an ARP request or a PING request?) and should be sent back to
1419 vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );
1420 /* parameter pdTRUE: the buffer must be released once
1421 the frame has been transmitted */
1424 case eFrameConsumed :
1425 /* The frame is in use somewhere, don't release the buffer
1430 /* The frame is not being used anywhere, and the
1431 NetworkBufferDescriptor_t structure containing the frame should
1432 just be released back to the list of free buffers. */
1433 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
1437 /*-----------------------------------------------------------*/
1439 static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
1440 NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength )
1442 eFrameProcessingResult_t eReturn = eProcessBuffer;
1444 #if( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )
1445 const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
1447 /* or else, the parameter won't be used and the function will be optimised
1449 ( void ) pxIPPacket;
1452 #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
1454 /* In systems with a very small amount of RAM, it might be advantageous
1455 to have incoming messages checked earlier, by the network card driver.
1456 This method may decrease the usage of sparse network buffers. */
1457 uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
1459 /* Ensure that the incoming packet is not fragmented (only outgoing
1460 packets can be fragmented) as these are the only handled IP frames
1462 if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )
1464 /* Can not handle, fragmented packet. */
1465 eReturn = eReleaseBuffer;
1467 /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
1468 * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
1469 else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) )
1471 /* Can not handle, unknown or invalid header version. */
1472 eReturn = eReleaseBuffer;
1474 /* Is the packet for this IP address? */
1475 else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
1476 /* Is it the global broadcast address 255.255.255.255 ? */
1477 ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) &&
1478 /* Is it a specific broadcast address 192.168.1.255 ? */
1479 ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) &&
1480 #if( ipconfigUSE_LLMNR == 1 )
1481 /* Is it the LLMNR multicast address? */
1482 ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
1484 /* Or (during DHCP negotiation) we have no IP-address yet? */
1485 ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
1487 /* Packet is not for this node, release it */
1488 eReturn = eReleaseBuffer;
1491 #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
1493 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )
1495 /* Some drivers of NIC's with checksum-offloading will enable the above
1496 define, so that the checksum won't be checked again here */
1497 if (eReturn == eProcessBuffer )
1499 /* Is the IP header checksum correct? */
1500 if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) &&
1501 ( usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) )
1503 /* Check sum in IP-header not correct. */
1504 eReturn = eReleaseBuffer;
1506 /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */
1507 else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )
1509 /* Protocol checksum not accepted. */
1510 eReturn = eReleaseBuffer;
1516 /* to avoid warning unused parameters */
1517 ( void ) pxNetworkBuffer;
1518 ( void ) uxHeaderLength;
1520 #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
1524 /*-----------------------------------------------------------*/
1526 static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )
1528 eFrameProcessingResult_t eReturn;
1529 IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
1530 UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );
1533 /* Bound the calculated header length: take away the Ethernet header size,
1534 then check if the IP header is claiming to be longer than the remaining
1535 total packet size. Also check for minimal header field length. */
1536 if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
1537 ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
1539 return eReleaseBuffer;
1542 ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
1543 /* Check if the IP headers are acceptable and if it has our destination. */
1544 eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
1546 if( eReturn == eProcessBuffer )
1548 if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )
1550 /* All structs of headers expect a IP header size of 20 bytes
1551 * IP header options were included, we'll ignore them and cut them out
1552 * Note: IP options are mostly use in Multi-cast protocols */
1553 const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;
1554 /* From: the previous start of UDP/ICMP/TCP data */
1555 uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength);
1556 /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */
1557 uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER);
1558 /* How many: total length minus the options and the lower headers */
1559 const size_t xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER;
1561 memmove( pucTarget, pucSource, xMoveLen );
1562 pxNetworkBuffer->xDataLength -= optlen;
1564 /* Fix-up new version/header length field in IP packet. */
1565 pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */
1566 ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */
1569 /* Add the IP and MAC addresses to the ARP table if they are not
1570 already there - otherwise refresh the age of the existing
1572 if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )
1574 /* Refresh the ARP cache with the IP/MAC-address of the received packet
1575 * For UDP packets, this will be done later in xProcessReceivedUDPPacket()
1576 * as soon as know that the message will be handled by someone
1577 * This will prevent that the ARP cache will get overwritten
1578 * with the IP-address of useless broadcast packets
1580 vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
1582 switch( ucProtocol )
1584 case ipPROTOCOL_ICMP :
1585 /* The IP packet contained an ICMP frame. Don't bother
1586 checking the ICMP checksum, as if it is wrong then the
1587 wrong data will also be returned, and the source of the
1588 ping will know something went wrong because it will not
1589 be able to validate what it receives. */
1590 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1592 if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )
1594 ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );
1595 if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
1597 eReturn = prvProcessICMPPacket( pxICMPPacket );
1602 eReturn = eReleaseBuffer;
1605 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
1608 case ipPROTOCOL_UDP :
1610 /* The IP packet contained a UDP frame. */
1611 UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
1613 /* Only proceed if the payload length indicated in the header
1614 appears to be valid. */
1615 if ( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) && ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) >= sizeof( UDPHeader_t ) ) )
1617 size_t uxPayloadSize_1, uxPayloadSize_2;
1618 /* The UDP payload size can be calculated by subtracting the
1619 * header size from `xDataLength`.
1620 * However, the `xDataLength` may be longer that expected,
1621 * e.g. when a small packet is padded with zero's.
1622 * The UDP header contains a field `usLength` reflecting
1623 * the payload size plus the UDP header ( 8 bytes ).
1624 * Set `xDataLength` to the size of the headers,
1625 * plus the lower of the two calculated payload sizes.
1628 uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
1629 uxPayloadSize_2 = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );
1630 if( uxPayloadSize_1 > uxPayloadSize_2 )
1632 pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t );
1635 /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */
1636 pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
1637 pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
1639 /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:
1640 * In some cases, the upper-layer checksum has been calculated
1641 * by the NIC driver.
1643 * Pass the packet payload to the UDP sockets implementation. */
1644 if( xProcessReceivedUDPPacket( pxNetworkBuffer,
1645 pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
1647 eReturn = eFrameConsumed;
1652 eReturn = eReleaseBuffer;
1657 #if ipconfigUSE_TCP == 1
1658 case ipPROTOCOL_TCP :
1661 if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )
1663 eReturn = eFrameConsumed;
1666 /* Setting this variable will cause xTCPTimerCheck()
1667 to be called just before the IP-task blocks. */
1668 xProcessedTCPMessage++;
1673 /* Not a supported frame type. */
1680 /*-----------------------------------------------------------*/
1682 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1684 static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )
1686 ePingReplyStatus_t eStatus = eSuccess;
1687 uint16_t usDataLength, usCount;
1690 /* Find the total length of the IP packet. */
1691 usDataLength = pxICMPPacket->xIPHeader.usLength;
1692 usDataLength = FreeRTOS_ntohs( usDataLength );
1694 /* Remove the length of the IP headers to obtain the length of the ICMP
1696 usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );
1698 /* Remove the length of the ICMP header, to obtain the length of
1699 data contained in the ping. */
1700 usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );
1702 /* Checksum has already been checked before in prvProcessIPPacket */
1704 /* Find the first byte of the data within the ICMP packet. */
1705 pucByte = ( uint8_t * ) pxICMPPacket;
1706 pucByte += sizeof( ICMPPacket_t );
1708 /* Check each byte. */
1709 for( usCount = 0; usCount < usDataLength; usCount++ )
1711 if( *pucByte != ipECHO_DATA_FILL_BYTE )
1713 eStatus = eInvalidData;
1720 /* Call back into the application to pass it the result. */
1721 vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
1725 /*-----------------------------------------------------------*/
1727 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
1729 static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket )
1731 ICMPHeader_t *pxICMPHeader;
1732 IPHeader_t *pxIPHeader;
1735 pxICMPHeader = &( pxICMPPacket->xICMPHeader );
1736 pxIPHeader = &( pxICMPPacket->xIPHeader );
1738 /* HT:endian: changed back */
1739 iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
1741 /* The checksum can be checked here - but a ping reply should be
1742 returned even if the checksum is incorrect so the other end can
1743 tell that the ping was received - even if the ping reply contains
1745 pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;
1746 pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
1747 pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
1749 /* Update the checksum because the ucTypeOfMessage member in the header
1750 has been changed to ipICMP_ECHO_REPLY. This is faster than calling
1751 usGenerateChecksum(). */
1753 /* due to compiler warning "integer operation result is out of range" */
1755 usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 );
1757 if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) )
1759 pxICMPHeader->usChecksum = ( uint16_t )
1760 ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +
1761 FreeRTOS_htons( usRequest + 1UL ) );
1765 pxICMPHeader->usChecksum = ( uint16_t )
1766 ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +
1767 FreeRTOS_htons( usRequest ) );
1769 return eReturnEthernetFrame;
1772 #endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
1773 /*-----------------------------------------------------------*/
1775 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1777 static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket )
1779 eFrameProcessingResult_t eReturn = eReleaseBuffer;
1781 iptraceICMP_PACKET_RECEIVED();
1782 switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
1784 case ipICMP_ECHO_REQUEST :
1785 #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
1787 eReturn = prvProcessICMPEchoRequest( pxICMPPacket );
1789 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
1792 case ipICMP_ECHO_REPLY :
1793 #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
1795 prvProcessICMPEchoReply( pxICMPPacket );
1797 #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
1807 #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
1808 /*-----------------------------------------------------------*/
1810 uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket )
1813 uint16_t usChecksum, *pusChecksum;
1814 const IPPacket_t * pxIPPacket;
1815 UBaseType_t uxIPHeaderLength;
1816 ProtocolPacket_t *pxProtPack;
1818 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1822 /* Check for minimum packet size. */
1823 if( uxBufferLength < sizeof( IPPacket_t ) )
1825 return ipINVALID_LENGTH;
1828 /* Parse the packet length. */
1829 pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;
1831 /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header
1832 Length field contains the length of the internet header in 32-bit words. */
1833 uxIPHeaderLength = ( UBaseType_t ) ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) );
1835 /* Check for minimum packet size. */
1836 if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER )
1838 return ipINVALID_LENGTH;
1840 if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) )
1842 return ipINVALID_LENGTH;
1845 /* Identify the next protocol. */
1846 ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
1848 /* N.B., if this IP packet header includes Options, then the following
1849 assignment results in a pointer into the protocol packet with the Ethernet
1850 and IP headers incorrectly aligned. However, either way, the "third"
1851 protocol (Layer 3 or 4) header will be aligned, which is the convenience
1852 of this calculation. */
1853 pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );
1855 /* Switch on the Layer 3/4 protocol. */
1856 if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
1858 if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) )
1860 return ipINVALID_LENGTH;
1863 pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );
1864 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1868 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
1870 else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
1872 if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) )
1874 return ipINVALID_LENGTH;
1877 pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );
1878 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1882 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
1884 else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
1885 ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
1887 if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) )
1889 return ipINVALID_LENGTH;
1892 pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );
1893 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1895 if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
1904 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
1908 /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
1909 return ipUNHANDLED_PROTOCOL;
1912 /* The protocol and checksum field have been identified. Check the direction
1914 if( xOutgoingPacket != pdFALSE )
1916 /* This is an outgoing packet. Before calculating the checksum, set it
1918 *( pusChecksum ) = 0u;
1920 else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
1922 /* Sender hasn't set the checksum, no use to calculate it. */
1923 return ipCORRECT_CRC;
1926 ulLength = ( uint32_t )
1927 ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */
1929 if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ||
1930 ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) )
1932 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1934 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );
1936 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
1938 /* Again, in a 16-bit return value there is no space to indicate an
1939 error. For incoming packets, 0x1234 will cause dropping of the packet.
1940 For outgoing packets, there is a serious problem with the
1942 return ipINVALID_LENGTH;
1944 if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )
1946 /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */
1947 usChecksum = ( uint16_t )
1948 ( ~usGenerateChecksum( 0UL,
1949 ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) );
1953 /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length
1955 usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );
1957 /* And then continue at the IPv4 source and destination addresses. */
1958 usChecksum = ( uint16_t )
1959 ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ),
1960 ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );
1962 /* Sum TCP header and data. */
1965 if( xOutgoingPacket == pdFALSE )
1967 /* This is in incoming packet. If the CRC is correct, it should be zero. */
1968 if( usChecksum == 0u )
1970 usChecksum = ( uint16_t )ipCORRECT_CRC;
1975 if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
1977 /* In case of UDP, a calculated checksum of 0x0000 is transmitted
1978 as 0xffff. A value of zero would mean that the checksum is not used. */
1979 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1981 if( xOutgoingPacket != pdFALSE )
1983 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );
1986 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
1988 usChecksum = ( uint16_t )0xffffu;
1991 usChecksum = FreeRTOS_htons( usChecksum );
1993 if( xOutgoingPacket != pdFALSE )
1995 *( pusChecksum ) = usChecksum;
1997 #if( ipconfigHAS_DEBUG_PRINTF != 0 )
1998 else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )
2000 FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",
2002 FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),
2003 FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),
2004 FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),
2005 FreeRTOS_ntohs( *pusChecksum ) ) );
2007 #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
2011 /*-----------------------------------------------------------*/
2014 * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).
2015 * The checksum algorithm is decribed as:
2016 * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the
2017 * header. For purposes of computing the checksum, the value of the checksum field is zero."
2019 * In a nutshell, that means that each 16-bit 'word' must be summed, after which
2020 * the number of 'carries' (overflows) is added to the result. If that addition
2021 * produces an overflow, that 'carry' must also be added to the final result. The final checksum
2022 * should be the bitwise 'not' (ones-complement) of the result if the packet is
2023 * meant to be transmitted, but this method simply returns the raw value, probably
2024 * because when a packet is received, the checksum is verified by checking that
2025 * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.
2027 * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.
2028 * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit
2029 * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,
2030 * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.
2031 * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.
2032 * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found
2033 * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue
2034 * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:
2035 * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];
2038 * ulSum: This argument provides a value to initialize the progressive summation
2039 * of the header's values to. It is often 0, but protocols like TCP or UDP
2040 * can have pseudo-header fields which need to be included in the checksum.
2041 * pucNextData: This argument contains the address of the first byte which this
2042 * method should process. The method's memory iterator is initialized to this value.
2043 * uxDataLengthBytes: This argument contains the number of bytes that this method
2046 uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes )
2048 xUnion32 xSum2, xSum, xTerm;
2049 xUnionPtr xSource; /* Points to first byte */
2050 xUnionPtr xLastSource; /* Points to last byte plus one */
2051 uint32_t ulAlignBits, ulCarry = 0ul;
2053 /* Small MCUs often spend up to 30% of the time doing checksum calculations
2054 This function is optimised for 32-bit CPUs; Each time it will try to fetch
2055 32-bits, sums it with an accumulator and counts the number of carries. */
2057 /* Swap the input (little endian platform only). */
2058 xSum.u32 = FreeRTOS_ntohs( ulSum );
2061 xSource.u8ptr = ( uint8_t * ) pucNextData;
2062 ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */
2064 /* If byte (8-bit) aligned... */
2065 if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) )
2067 xTerm.u8[ 1 ] = *( xSource.u8ptr );
2068 ( xSource.u8ptr )++;
2069 uxDataLengthBytes--;
2070 /* Now xSource is word (16-bit) aligned. */
2073 /* If half-word (16-bit) aligned... */
2074 if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) )
2076 xSum.u32 += *(xSource.u16ptr);
2077 ( xSource.u16ptr )++;
2078 uxDataLengthBytes -= 2u;
2079 /* Now xSource is word (32-bit) aligned. */
2082 /* Word (32-bit) aligned, do the most part. */
2083 xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u;
2085 /* In this loop, four 32-bit additions will be done, in total 16 bytes.
2086 Indexing with constants (0,1,2,3) gives faster code than using
2088 while( xSource.u32ptr < xLastSource.u32ptr )
2090 /* Use a secondary Sum2, just to see if the addition produced an
2092 xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];
2093 if( xSum2.u32 < xSum.u32 )
2098 /* Now add the secondary sum to the major sum, and remember if there was
2100 xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];
2101 if( xSum2.u32 > xSum.u32 )
2106 /* And do the same trick once again for indexes 2 and 3 */
2107 xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];
2108 if( xSum2.u32 < xSum.u32 )
2113 xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];
2115 if( xSum2.u32 > xSum.u32 )
2120 /* And finally advance the pointer 4 * 4 = 16 bytes. */
2121 xSource.u32ptr += 4;
2124 /* Now add all carries. */
2125 xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;
2127 uxDataLengthBytes %= 16u;
2128 xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) );
2130 /* Half-word aligned. */
2131 while( xSource.u16ptr < xLastSource.u16ptr )
2133 /* At least one more short. */
2134 xSum.u32 += xSource.u16ptr[ 0 ];
2138 if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u ) /* Maybe one more ? */
2140 xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];
2142 xSum.u32 += xTerm.u32;
2144 /* Now add all carries again. */
2145 xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
2147 /* The previous summation might have given a 16-bit carry. */
2148 xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
2150 if( ( ulAlignBits & 1u ) != 0u )
2152 /* Quite unlikely, but pucNextData might be non-aligned, which would
2153 mean that a checksum is calculated starting at an odd position. */
2154 xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 );
2157 /* swap the output (little endian platform only). */
2158 return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) );
2160 /*-----------------------------------------------------------*/
2162 void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend )
2164 EthernetHeader_t *pxEthernetHeader;
2166 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
2167 NetworkBufferDescriptor_t *pxNewBuffer;
2170 #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
2172 if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
2176 FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )pxNetworkBuffer->xDataLength ) );
2177 for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
2179 pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
2181 pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
2186 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )
2188 if( xReleaseAfterSend == pdFALSE )
2190 pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
2191 xReleaseAfterSend = pdTRUE;
2192 pxNetworkBuffer = pxNewBuffer;
2195 if( pxNetworkBuffer != NULL )
2198 pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
2200 /* Swap source and destination MAC addresses. */
2201 memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );
2202 memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
2205 xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
2208 /*-----------------------------------------------------------*/
2210 uint32_t FreeRTOS_GetIPAddress( void )
2212 /* Returns the IP address of the NIC. */
2213 return *ipLOCAL_IP_ADDRESS_POINTER;
2215 /*-----------------------------------------------------------*/
2217 void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )
2219 /* Sets the IP address of the NIC. */
2220 *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress;
2222 /*-----------------------------------------------------------*/
2224 uint32_t FreeRTOS_GetGatewayAddress( void )
2226 return xNetworkAddressing.ulGatewayAddress;
2228 /*-----------------------------------------------------------*/
2230 uint32_t FreeRTOS_GetDNSServerAddress( void )
2232 return xNetworkAddressing.ulDNSServerAddress;
2234 /*-----------------------------------------------------------*/
2236 uint32_t FreeRTOS_GetNetmask( void )
2238 return xNetworkAddressing.ulNetMask;
2240 /*-----------------------------------------------------------*/
2242 void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] )
2244 /* Copy the MAC address at the start of the default packet header fragment. */
2245 memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );
2247 /*-----------------------------------------------------------*/
2249 const uint8_t * FreeRTOS_GetMACAddress( void )
2251 return ipLOCAL_MAC_ADDRESS;
2253 /*-----------------------------------------------------------*/
2255 void FreeRTOS_SetNetmask ( uint32_t ulNetmask )
2257 xNetworkAddressing.ulNetMask = ulNetmask;
2259 /*-----------------------------------------------------------*/
2261 void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress )
2263 xNetworkAddressing.ulGatewayAddress = ulGatewayAddress;
2265 /*-----------------------------------------------------------*/
2267 #if( ipconfigUSE_DHCP == 1 )
2268 void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
2270 if( xEnableState != pdFALSE )
2272 xDHCPTimer.bActive = pdTRUE_UNSIGNED;
2276 xDHCPTimer.bActive = pdFALSE_UNSIGNED;
2279 #endif /* ipconfigUSE_DHCP */
2280 /*-----------------------------------------------------------*/
2282 #if( ipconfigUSE_DHCP == 1 )
2283 void vIPReloadDHCPTimer( uint32_t ulLeaseTime )
2285 prvIPTimerReload( &xDHCPTimer, ulLeaseTime );
2287 #endif /* ipconfigUSE_DHCP */
2288 /*-----------------------------------------------------------*/
2290 #if( ipconfigDNS_USE_CALLBACKS == 1 )
2291 void vIPSetDnsTimerEnableState( BaseType_t xEnableState )
2293 if( xEnableState != 0 )
2295 xDNSTimer.bActive = pdTRUE;
2299 xDNSTimer.bActive = pdFALSE;
2302 #endif /* ipconfigUSE_DHCP */
2303 /*-----------------------------------------------------------*/
2305 #if( ipconfigDNS_USE_CALLBACKS != 0 )
2306 void vIPReloadDNSTimer( uint32_t ulCheckTime )
2308 prvIPTimerReload( &xDNSTimer, ulCheckTime );
2310 #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
2311 /*-----------------------------------------------------------*/
2313 BaseType_t xIPIsNetworkTaskReady( void )
2315 return xIPTaskInitialised;
2317 /*-----------------------------------------------------------*/
2319 BaseType_t FreeRTOS_IsNetworkUp( void )
2323 /*-----------------------------------------------------------*/
2325 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
2326 UBaseType_t uxGetMinimumIPQueueSpace( void )
2328 return uxQueueMinimumSpace;
2331 /*-----------------------------------------------------------*/
2333 /* Provide access to private members for verification. */
2334 #ifdef FREERTOS_TCP_ENABLE_VERIFICATION
2335 #include "aws_freertos_ip_verification_access_ip_define.h"