diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c')
-rw-r--r-- | FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c | 4674 |
1 files changed, 2337 insertions, 2337 deletions
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c index c94f55dd7..48e632a01 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c @@ -1,2337 +1,2337 @@ -/*
- * FreeRTOS+TCP V2.2.0
- * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * http://aws.amazon.com/freertos
- * http://www.FreeRTOS.org
- */
-
-/* Standard includes. */
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-/* FreeRTOS includes. */
-#include "FreeRTOS.h"
-#include "task.h"
-#include "queue.h"
-#include "semphr.h"
-
-/* FreeRTOS+TCP includes. */
-#include "FreeRTOS_IP.h"
-#include "FreeRTOS_Sockets.h"
-#include "FreeRTOS_IP_Private.h"
-#include "FreeRTOS_ARP.h"
-#include "FreeRTOS_UDP_IP.h"
-#include "FreeRTOS_TCP_IP.h"
-#include "FreeRTOS_DHCP.h"
-#include "NetworkInterface.h"
-#include "NetworkBufferManagement.h"
-#include "FreeRTOS_DNS.h"
-
-
-/* Used to ensure the structure packing is having the desired effect. The
-'volatile' is used to prevent compiler warnings about comparing a constant with
-a constant. */
-#define ipEXPECTED_EthernetHeader_t_SIZE ( ( size_t ) 14 )
-#define ipEXPECTED_ARPHeader_t_SIZE ( ( size_t ) 28 )
-#define ipEXPECTED_IPHeader_t_SIZE ( ( size_t ) 20 )
-#define ipEXPECTED_IGMPHeader__SIZE ( ( size_t ) 8 )
-#define ipEXPECTED_ICMPHeader_t_SIZE ( ( size_t ) 8 )
-#define ipEXPECTED_UDPHeader_t_SIZE ( ( size_t ) 8 )
-#define ipEXPECTED_TCPHeader_t_SIZE ( ( size_t ) 20 )
-
-
-/* ICMP protocol definitions. */
-#define ipICMP_ECHO_REQUEST ( ( uint8_t ) 8 )
-#define ipICMP_ECHO_REPLY ( ( uint8_t ) 0 )
-
-
-/* Time delay between repeated attempts to initialise the network hardware. */
-#ifndef ipINITIALISATION_RETRY_DELAY
- #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) )
-#endif
-
-/* Defines how often the ARP timer callback function is executed. The time is
-shorted in the Windows simulator as simulated time is not real time. */
-#ifndef ipARP_TIMER_PERIOD_MS
- #ifdef _WINDOWS_
- #define ipARP_TIMER_PERIOD_MS ( 500 ) /* For windows simulator builds. */
- #else
- #define ipARP_TIMER_PERIOD_MS ( 10000 )
- #endif
-#endif
-
-#ifndef iptraceIP_TASK_STARTING
- #define iptraceIP_TASK_STARTING() do {} while( 0 )
-#endif
-
-#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) )
- /* When initialising the TCP timer,
- give it an initial time-out of 1 second. */
- #define ipTCP_TIMER_PERIOD_MS ( 1000 )
-#endif
-
-/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet
-driver will filter incoming packets and only pass the stack those packets it
-considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can
-be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0
-then the Ethernet driver will pass all received packets to the stack, and the
-stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING
-needs to call eConsiderFrameForProcessing. */
-#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0
- #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
-#else
- #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
-#endif
-
-/* The character used to fill ICMP echo requests, and therefore also the
-character expected to fill ICMP echo replies. */
-#define ipECHO_DATA_FILL_BYTE 'x'
-
-#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
- /* The bits in the two byte IP header field that make up the fragment offset value. */
- #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff0f )
-#else
- /* The bits in the two byte IP header field that make up the fragment offset value. */
- #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff )
-#endif /* ipconfigBYTE_ORDER */
-
-/* The maximum time the IP task is allowed to remain in the Blocked state if no
-events are posted to the network event queue. */
-#ifndef ipconfigMAX_IP_TASK_SLEEP_TIME
- #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) )
-#endif
-
-/* When a new TCP connection is established, the value of
-'ulNextInitialSequenceNumber' will be used as the initial sequence number. It
-is very important that at start-up, 'ulNextInitialSequenceNumber' contains a
-random value. Also its value must be increased continuously in time, to prevent
-a third party guessing the next sequence number and take-over a TCP connection.
-It is advised to increment it by 1 ever 4us, which makes about 256 times
-per ms: */
-#define ipINITIAL_SEQUENCE_NUMBER_FACTOR 256UL
-
-/* Returned as the (invalid) checksum when the protocol being checked is not
-handled. The value is chosen simply to be easy to spot when debugging. */
-#define ipUNHANDLED_PROTOCOL 0x4321u
-
-/* Returned to indicate a valid checksum when the checksum does not need to be
-calculated. */
-#define ipCORRECT_CRC 0xffffu
-
-/* Returned as the (invalid) checksum when the length of the data being checked
-had an invalid length. */
-#define ipINVALID_LENGTH 0x1234u
-
-/*-----------------------------------------------------------*/
-
-typedef struct xIP_TIMER
-{
- uint32_t
- bActive : 1, /* This timer is running and must be processed. */
- bExpired : 1; /* Timer has expired and a task must be processed. */
- TimeOut_t xTimeOut;
- TickType_t ulRemainingTime;
- TickType_t ulReloadTime;
-} IPTimer_t;
-
-/* Used in checksum calculation. */
-typedef union _xUnion32
-{
- uint32_t u32;
- uint16_t u16[ 2 ];
- uint8_t u8[ 4 ];
-} xUnion32;
-
-/* Used in checksum calculation. */
-typedef union _xUnionPtr
-{
- uint32_t *u32ptr;
- uint16_t *u16ptr;
- uint8_t *u8ptr;
-} xUnionPtr;
-
-/*-----------------------------------------------------------*/
-
-/*
- * The main TCP/IP stack processing task. This task receives commands/events
- * from the network hardware drivers and tasks that are using sockets. It also
- * maintains a set of protocol timers.
- */
-static void prvIPTask( void *pvParameters );
-
-/*
- * Called when new data is available from the network interface.
- */
-static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer );
-
-/*
- * Process incoming IP packets.
- */
-static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer );
-
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
- /*
- * Process incoming ICMP packets.
- */
- static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket );
-#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
-
-/*
- * Turns around an incoming ping request to convert it into a ping reply.
- */
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
- static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket );
-#endif /* ipconfigREPLY_TO_INCOMING_PINGS */
-
-/*
- * Processes incoming ping replies. The application callback function
- * vApplicationPingReplyHook() is called with the results.
- */
-#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
- static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket );
-#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
-
-/*
- * Called to create a network connection when the stack is first started, or
- * when the network connection is lost.
- */
-static void prvProcessNetworkDownEvent( void );
-
-/*
- * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout
- * processing is required.
- */
-static void prvCheckNetworkTimers( void );
-
-/*
- * Determine how long the IP task can sleep for, which depends on when the next
- * periodic or timeout processing must be performed.
- */
-static TickType_t prvCalculateSleepTime( void );
-
-/*
- * The network card driver has received a packet. In the case that it is part
- * of a linked packet chain, walk through it to handle every message.
- */
-static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer );
-
-/*
- * Utility functions for the light weight IP timers.
- */
-static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime );
-static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer );
-static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime );
-
-static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
- NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength );
-
-/*-----------------------------------------------------------*/
-
-/* The queue used to pass events into the IP-task for processing. */
-QueueHandle_t xNetworkEventQueue = NULL;
-
-/*_RB_ Requires comment. */
-uint16_t usPacketIdentifier = 0U;
-
-/* For convenience, a MAC address of all 0xffs is defined const for quick
-reference. */
-const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
-
-/* Structure that stores the netmask, gateway address and DNS server addresses. */
-NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 };
-
-/* Default values for the above struct in case DHCP
-does not lead to a confirmed request. */
-NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 };
-
-/* Used to ensure network down events cannot be missed when they cannot be
-posted to the network event queue because the network event queue is already
-full. */
-static BaseType_t xNetworkDownEventPending = pdFALSE;
-
-/* Stores the handle of the task that handles the stack. The handle is used
-(indirectly) by some utility function to determine if the utility function is
-being called by a task (in which case it is ok to block) or by the IP task
-itself (in which case it is not ok to block). */
-static TaskHandle_t xIPTaskHandle = NULL;
-
-#if( ipconfigUSE_TCP != 0 )
- /* Set to a non-zero value if one or more TCP message have been processed
- within the last round. */
- static BaseType_t xProcessedTCPMessage;
-#endif
-
-/* Simple set to pdTRUE or pdFALSE depending on whether the network is up or
-down (connected, not connected) respectively. */
-static BaseType_t xNetworkUp = pdFALSE;
-
-/*
-A timer for each of the following processes, all of which need attention on a
-regular basis:
- 1. ARP, to check its table entries
- 2. DPHC, to send requests and to renew a reservation
- 3. TCP, to check for timeouts, resends
- 4. DNS, to check for timeouts when looking-up a domain.
- */
-static IPTimer_t xARPTimer;
-#if( ipconfigUSE_DHCP != 0 )
- static IPTimer_t xDHCPTimer;
-#endif
-#if( ipconfigUSE_TCP != 0 )
- static IPTimer_t xTCPTimer;
-#endif
-#if( ipconfigDNS_USE_CALLBACKS != 0 )
- static IPTimer_t xDNSTimer;
-#endif
-
-/* Set to pdTRUE when the IP task is ready to start processing packets. */
-static BaseType_t xIPTaskInitialised = pdFALSE;
-
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
- /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */
- static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH;
-#endif
-
-/*-----------------------------------------------------------*/
-
-static void prvIPTask( void *pvParameters )
-{
-IPStackEvent_t xReceivedEvent;
-TickType_t xNextIPSleep;
-FreeRTOS_Socket_t *pxSocket;
-struct freertos_sockaddr xAddress;
-
- /* Just to prevent compiler warnings about unused parameters. */
- ( void ) pvParameters;
-
- /* A possibility to set some additional task properties. */
- iptraceIP_TASK_STARTING();
-
- /* Generate a dummy message to say that the network connection has gone
- down. This will cause this task to initialise the network interface. After
- this it is the responsibility of the network interface hardware driver to
- send this message if a previously connected network is disconnected. */
- FreeRTOS_NetworkDown();
-
- #if( ipconfigUSE_TCP == 1 )
- {
- /* Initialise the TCP timer. */
- prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) );
- }
- #endif
-
- /* Initialisation is complete and events can now be processed. */
- xIPTaskInitialised = pdTRUE;
-
- FreeRTOS_debug_printf( ( "prvIPTask started\n" ) );
-
- /* Loop, processing IP events. */
- for( ;; )
- {
- ipconfigWATCHDOG_TIMER();
-
- /* Check the ARP, DHCP and TCP timers to see if there is any periodic
- or timeout processing to perform. */
- prvCheckNetworkTimers();
-
- /* Calculate the acceptable maximum sleep time. */
- xNextIPSleep = prvCalculateSleepTime();
-
- /* Wait until there is something to do. If the following call exits
- * due to a time out rather than a message being received, set a
- * 'NoEvent' value. */
- if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE )
- {
- xReceivedEvent.eEventType = eNoEvent;
- }
-
- #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
- {
- if( xReceivedEvent.eEventType != eNoEvent )
- {
- UBaseType_t uxCount;
-
- uxCount = uxQueueSpacesAvailable( xNetworkEventQueue );
- if( uxQueueMinimumSpace > uxCount )
- {
- uxQueueMinimumSpace = uxCount;
- }
- }
- }
- #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
-
- iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType );
-
- switch( xReceivedEvent.eEventType )
- {
- case eNetworkDownEvent :
- /* Attempt to establish a connection. */
- xNetworkUp = pdFALSE;
- prvProcessNetworkDownEvent();
- break;
-
- case eNetworkRxEvent:
- /* The network hardware driver has received a new packet. A
- pointer to the received buffer is located in the pvData member
- of the received event structure. */
- prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
- break;
-
- case eNetworkTxEvent:
- /* Send a network packet. The ownership will be transferred to
- the driver, which will release it after delivery. */
- xNetworkInterfaceOutput( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ), pdTRUE );
- break;
-
- case eARPTimerEvent :
- /* The ARP timer has expired, process the ARP cache. */
- vARPAgeCache();
- break;
-
- case eSocketBindEvent:
- /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket
- to a port. The port number is communicated in the socket field
- usLocalPort. vSocketBind() will actually bind the socket and the
- API will unblock as soon as the eSOCKET_BOUND event is
- triggered. */
- pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );
- xAddress.sin_addr = 0u; /* For the moment. */
- xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort );
- pxSocket->usLocalPort = 0u;
- vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE );
-
- /* Before 'eSocketBindEvent' was sent it was tested that
- ( xEventGroup != NULL ) so it can be used now to wake up the
- user. */
- pxSocket->xEventBits |= eSOCKET_BOUND;
- vSocketWakeUpUser( pxSocket );
- break;
-
- case eSocketCloseEvent :
- /* The user API FreeRTOS_closesocket() has sent a message to the
- IP-task to actually close a socket. This is handled in
- vSocketClose(). As the socket gets closed, there is no way to
- report back to the API, so the API won't wait for the result */
- vSocketClose( ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ) );
- break;
-
- case eStackTxEvent :
- /* The network stack has generated a packet to send. A
- pointer to the generated buffer is located in the pvData
- member of the received event structure. */
- vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) );
- break;
-
- case eDHCPEvent:
- /* The DHCP state machine needs processing. */
- #if( ipconfigUSE_DHCP == 1 )
- {
- vDHCPProcess( pdFALSE );
- }
- #endif /* ipconfigUSE_DHCP */
- break;
-
- case eSocketSelectEvent :
- /* FreeRTOS_select() has got unblocked by a socket event,
- vSocketSelect() will check which sockets actually have an event
- and update the socket field xSocketBits. */
- #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
- {
- vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) );
- }
- #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */
- break;
-
- case eSocketSignalEvent :
- #if( ipconfigSUPPORT_SIGNALS != 0 )
- {
- /* Some task wants to signal the user of this socket in
- order to interrupt a call to recv() or a call to select(). */
- FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData );
- }
- #endif /* ipconfigSUPPORT_SIGNALS */
- break;
-
- case eTCPTimerEvent :
- #if( ipconfigUSE_TCP == 1 )
- {
- /* Simply mark the TCP timer as expired so it gets processed
- the next time prvCheckNetworkTimers() is called. */
- xTCPTimer.bExpired = pdTRUE_UNSIGNED;
- }
- #endif /* ipconfigUSE_TCP */
- break;
-
- case eTCPAcceptEvent:
- /* The API FreeRTOS_accept() was called, the IP-task will now
- check if the listening socket (communicated in pvData) actually
- received a new connection. */
- #if( ipconfigUSE_TCP == 1 )
- {
- pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData );
-
- if( xTCPCheckNewClient( pxSocket ) != pdFALSE )
- {
- pxSocket->xEventBits |= eSOCKET_ACCEPT;
- vSocketWakeUpUser( pxSocket );
- }
- }
- #endif /* ipconfigUSE_TCP */
- break;
-
- case eTCPNetStat:
- /* FreeRTOS_netstat() was called to have the IP-task print an
- overview of all sockets and their connections */
- #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) )
- {
- vTCPNetStat();
- }
- #endif /* ipconfigUSE_TCP */
- break;
-
- default :
- /* Should not get here. */
- break;
- }
-
- if( xNetworkDownEventPending != pdFALSE )
- {
- /* A network down event could not be posted to the network event
- queue because the queue was full. Try posting again. */
- FreeRTOS_NetworkDown();
- }
- }
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t xIsCallingFromIPTask( void )
-{
-BaseType_t xReturn;
-
- if( xTaskGetCurrentTaskHandle() == xIPTaskHandle )
- {
- xReturn = pdTRUE;
- }
- else
- {
- xReturn = pdFALSE;
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer )
-{
- #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 )
- {
- /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one
- buffer will be sent at a time. This is the default way for +TCP to pass
- messages from the MAC to the TCP/IP stack. */
- prvProcessEthernetPacket( pxBuffer );
- }
- #else /* ipconfigUSE_LINKED_RX_MESSAGES */
- {
- NetworkBufferDescriptor_t *pxNextBuffer;
-
- /* An optimisation that is useful when there is high network traffic.
- Instead of passing received packets into the IP task one at a time the
- network interface can chain received packets together and pass them into
- the IP task in one go. The packets are chained using the pxNextBuffer
- member. The loop below walks through the chain processing each packet
- in the chain in turn. */
- do
- {
- /* Store a pointer to the buffer after pxBuffer for use later on. */
- pxNextBuffer = pxBuffer->pxNextBuffer;
-
- /* Make it NULL to avoid using it later on. */
- pxBuffer->pxNextBuffer = NULL;
-
- prvProcessEthernetPacket( pxBuffer );
- pxBuffer = pxNextBuffer;
-
- /* While there is another packet in the chain. */
- } while( pxBuffer != NULL );
- }
- #endif /* ipconfigUSE_LINKED_RX_MESSAGES */
-}
-/*-----------------------------------------------------------*/
-
-static TickType_t prvCalculateSleepTime( void )
-{
-TickType_t xMaximumSleepTime;
-
- /* Start with the maximum sleep time, then check this against the remaining
- time in any other timers that are active. */
- xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME;
-
- if( xARPTimer.bActive != pdFALSE_UNSIGNED )
- {
- if( xARPTimer.ulRemainingTime < xMaximumSleepTime )
- {
- xMaximumSleepTime = xARPTimer.ulReloadTime;
- }
- }
-
- #if( ipconfigUSE_DHCP == 1 )
- {
- if( xDHCPTimer.bActive != pdFALSE_UNSIGNED )
- {
- if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime )
- {
- xMaximumSleepTime = xDHCPTimer.ulRemainingTime;
- }
- }
- }
- #endif /* ipconfigUSE_DHCP */
-
- #if( ipconfigUSE_TCP == 1 )
- {
- if( xTCPTimer.ulRemainingTime < xMaximumSleepTime )
- {
- xMaximumSleepTime = xTCPTimer.ulRemainingTime;
- }
- }
- #endif
-
- #if( ipconfigDNS_USE_CALLBACKS != 0 )
- {
- if( xDNSTimer.bActive != pdFALSE )
- {
- if( xDNSTimer.ulRemainingTime < xMaximumSleepTime )
- {
- xMaximumSleepTime = xDNSTimer.ulRemainingTime;
- }
- }
- }
- #endif
-
- return xMaximumSleepTime;
-}
-/*-----------------------------------------------------------*/
-
-static void prvCheckNetworkTimers( void )
-{
- /* Is it time for ARP processing? */
- if( prvIPTimerCheck( &xARPTimer ) != pdFALSE )
- {
- xSendEventToIPTask( eARPTimerEvent );
- }
-
- #if( ipconfigUSE_DHCP == 1 )
- {
- /* Is it time for DHCP processing? */
- if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE )
- {
- xSendEventToIPTask( eDHCPEvent );
- }
- }
- #endif /* ipconfigUSE_DHCP */
-
- #if( ipconfigDNS_USE_CALLBACKS != 0 )
- {
- extern void vDNSCheckCallBack( void *pvSearchID );
-
- /* Is it time for DNS processing? */
- if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE )
- {
- vDNSCheckCallBack( NULL );
- }
- }
- #endif /* ipconfigDNS_USE_CALLBACKS */
-
- #if( ipconfigUSE_TCP == 1 )
- {
- BaseType_t xWillSleep;
- TickType_t xNextTime;
- BaseType_t xCheckTCPSockets;
-
- if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u )
- {
- xWillSleep = pdTRUE;
- }
- else
- {
- xWillSleep = pdFALSE;
- }
-
- /* Sockets need to be checked if the TCP timer has expired. */
- xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer );
-
- /* Sockets will also be checked if there are TCP messages but the
- message queue is empty (indicated by xWillSleep being true). */
- if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) )
- {
- xCheckTCPSockets = pdTRUE;
- }
-
- if( xCheckTCPSockets != pdFALSE )
- {
- /* Attend to the sockets, returning the period after which the
- check must be repeated. */
- xNextTime = xTCPTimerCheck( xWillSleep );
- prvIPTimerStart( &xTCPTimer, xNextTime );
- xProcessedTCPMessage = 0;
- }
- }
- #endif /* ipconfigUSE_TCP == 1 */
-}
-/*-----------------------------------------------------------*/
-
-static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime )
-{
- vTaskSetTimeOutState( &pxTimer->xTimeOut );
- pxTimer->ulRemainingTime = xTime;
-
- if( xTime == ( TickType_t ) 0 )
- {
- pxTimer->bExpired = pdTRUE_UNSIGNED;
- }
- else
- {
- pxTimer->bExpired = pdFALSE_UNSIGNED;
- }
-
- pxTimer->bActive = pdTRUE_UNSIGNED;
-}
-/*-----------------------------------------------------------*/
-
-static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime )
-{
- pxTimer->ulReloadTime = xTime;
- prvIPTimerStart( pxTimer, xTime );
-}
-/*-----------------------------------------------------------*/
-
-static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer )
-{
-BaseType_t xReturn;
-
- if( pxTimer->bActive == pdFALSE_UNSIGNED )
- {
- /* The timer is not enabled. */
- xReturn = pdFALSE;
- }
- else
- {
- /* The timer might have set the bExpired flag already, if not, check the
- value of xTimeOut against ulRemainingTime. */
- if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) ||
- ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) )
- {
- prvIPTimerStart( pxTimer, pxTimer->ulReloadTime );
- xReturn = pdTRUE;
- }
- else
- {
- xReturn = pdFALSE;
- }
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_NetworkDown( void )
-{
-static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
-const TickType_t xDontBlock = ( TickType_t ) 0;
-
- /* Simply send the network task the appropriate event. */
- if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS )
- {
- /* Could not send the message, so it is still pending. */
- xNetworkDownEventPending = pdTRUE;
- }
- else
- {
- /* Message was sent so it is not pending. */
- xNetworkDownEventPending = pdFALSE;
- }
-
- iptraceNETWORK_DOWN();
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t FreeRTOS_NetworkDownFromISR( void )
-{
-static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
-BaseType_t xHigherPriorityTaskWoken = pdFALSE;
-
- /* Simply send the network task the appropriate event. */
- if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS )
- {
- xNetworkDownEventPending = pdTRUE;
- }
- else
- {
- xNetworkDownEventPending = pdFALSE;
- }
-
- iptraceNETWORK_DOWN();
-
- return xHigherPriorityTaskWoken;
-}
-/*-----------------------------------------------------------*/
-
-void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks )
-{
-NetworkBufferDescriptor_t *pxNetworkBuffer;
-void *pvReturn;
-
- /* Cap the block time. The reason for this is explained where
- ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official
- FreeRTOSIPConfig.h header file is being used). */
- if( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS )
- {
- xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS;
- }
-
- /* Obtain a network buffer with the required amount of storage. */
- pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks );
-
- if( pxNetworkBuffer != NULL )
- {
- /* Set the actual packet size in case a bigger buffer was returned. */
- pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + xRequestedSizeBytes;
-
- /* Leave space for the UPD header. */
- pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
- }
- else
- {
- pvReturn = NULL;
- }
-
- return ( void * ) pvReturn;
-}
-/*-----------------------------------------------------------*/
-
-NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer,
- size_t uxNewLength )
-{
-NetworkBufferDescriptor_t * pxNewBuffer;
-
- /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1.
- The transmit routine wants to have ownership of the network buffer
- descriptor, because it will pass the buffer straight to DMA. */
- pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 );
-
- if( pxNewBuffer != NULL )
- {
- /* Set the actual packet size in case a bigger buffer than requested
- was returned. */
- pxNewBuffer->xDataLength = uxNewLength;
-
- /* Copy the original packet information. */
- pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress;
- pxNewBuffer->usPort = pxNetworkBuffer->usPort;
- pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort;
- memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength );
- }
-
- return pxNewBuffer;
-}
-/*-----------------------------------------------------------*/
-
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 )
-
- NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer )
- {
- uint8_t *pucBuffer;
- NetworkBufferDescriptor_t *pxResult;
-
- if( pvBuffer == NULL )
- {
- pxResult = NULL;
- }
- else
- {
- /* Obtain the network buffer from the zero copy pointer. */
- pucBuffer = ( uint8_t * ) pvBuffer;
-
- /* The input here is a pointer to a payload buffer. Subtract the
- size of the header in the network buffer, usually 8 + 2 bytes. */
- pucBuffer -= ipBUFFER_PADDING;
-
- /* Here a pointer was placed to the network descriptor. As a
- pointer is dereferenced, make sure it is well aligned. */
- if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 )
- {
- pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );
- }
- else
- {
- pxResult = NULL;
- }
- }
-
- return pxResult;
- }
-
-#endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */
-/*-----------------------------------------------------------*/
-
-NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer )
-{
-uint8_t *pucBuffer;
-NetworkBufferDescriptor_t *pxResult;
-
- if( pvBuffer == NULL )
- {
- pxResult = NULL;
- }
- else
- {
- /* Obtain the network buffer from the zero copy pointer. */
- pucBuffer = ( uint8_t * ) pvBuffer;
-
- /* The input here is a pointer to a payload buffer. Subtract
- the total size of a UDP/IP header plus the size of the header in
- the network buffer, usually 8 + 2 bytes. */
- pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING );
-
- /* Here a pointer was placed to the network descriptor,
- As a pointer is dereferenced, make sure it is well aligned */
- if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 )
- {
- /* The following statement may trigger a:
- warning: cast increases required alignment of target type [-Wcast-align].
- It has been confirmed though that the alignment is suitable. */
- pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer );
- }
- else
- {
- pxResult = NULL;
- }
- }
-
- return pxResult;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer )
-{
- vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) );
-}
-/*-----------------------------------------------------------*/
-
-/*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */
-/*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high.
- As that bug has been repaired, there is not an urgent reason to warn.
- It is better though to use the advised priority scheme. */
-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 ] )
-{
-BaseType_t xReturn = pdFALSE;
-
- /* This function should only be called once. */
- configASSERT( xIPIsNetworkTaskReady() == pdFALSE );
- configASSERT( xNetworkEventQueue == NULL );
- configASSERT( xIPTaskHandle == NULL );
-
- /* Check structure packing is correct. */
- configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE );
- configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE );
- configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE );
- configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE );
- configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE );
-
- /* Attempt to create the queue used to communicate with the IP task. */
- xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) );
- configASSERT( xNetworkEventQueue );
-
- if( xNetworkEventQueue != NULL )
- {
- #if ( configQUEUE_REGISTRY_SIZE > 0 )
- {
- /* A queue registry is normally used to assist a kernel aware
- debugger. If one is in use then it will be helpful for the debugger
- to show information about the network event queue. */
- vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" );
- }
- #endif /* configQUEUE_REGISTRY_SIZE */
-
- if( xNetworkBuffersInitialise() == pdPASS )
- {
- /* Store the local IP and MAC address. */
- xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] );
- xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] );
- xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] );
- xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] );
- xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
-
- memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) );
-
- #if ipconfigUSE_DHCP == 1
- {
- /* The IP address is not set until DHCP completes. */
- *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL;
- }
- #else
- {
- /* The IP address is set from the value passed in. */
- *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
-
- /* Added to prevent ARP flood to gateway. Ensure the
- gateway is on the same subnet as the IP address. */
- if( xNetworkAddressing.ulGatewayAddress != 0ul )
- {
- configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) );
- }
- }
- #endif /* ipconfigUSE_DHCP == 1 */
-
- /* The MAC address is stored in the start of the default packet
- header fragment, which is used when sending UDP packets. */
- memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
-
- /* Prepare the sockets interface. */
- xReturn = vNetworkSocketsInit();
-
- if( pdTRUE == xReturn )
- {
- /* Create the task that processes Ethernet and stack events. */
- xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle );
- }
- }
- else
- {
- FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") );
-
- /* Clean up. */
- vQueueDelete( xNetworkEventQueue );
- xNetworkEventQueue = NULL;
- }
- }
- else
- {
- FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") );
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress )
-{
- /* Return the address configuration to the caller. */
-
- if( pulIPAddress != NULL )
- {
- *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
- }
-
- if( pulNetMask != NULL )
- {
- *pulNetMask = xNetworkAddressing.ulNetMask;
- }
-
- if( pulGatewayAddress != NULL )
- {
- *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress;
- }
-
- if( pulDNSServerAddress != NULL )
- {
- *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress;
- }
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress )
-{
- /* Update the address configuration. */
-
- if( pulIPAddress != NULL )
- {
- *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress;
- }
-
- if( pulNetMask != NULL )
- {
- xNetworkAddressing.ulNetMask = *pulNetMask;
- }
-
- if( pulGatewayAddress != NULL )
- {
- xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress;
- }
-
- if( pulDNSServerAddress != NULL )
- {
- xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress;
- }
-}
-/*-----------------------------------------------------------*/
-
-#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
-
- BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks )
- {
- NetworkBufferDescriptor_t *pxNetworkBuffer;
- ICMPHeader_t *pxICMPHeader;
- BaseType_t xReturn = pdFAIL;
- static uint16_t usSequenceNumber = 0;
- uint8_t *pucChar;
- IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL };
-
- if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) )
- {
- pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks );
-
- if( pxNetworkBuffer != NULL )
- {
- pxICMPHeader = ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] );
- usSequenceNumber++;
-
- /* Fill in the basic header information. */
- pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST;
- pxICMPHeader->ucTypeOfService = 0;
- pxICMPHeader->usIdentifier = usSequenceNumber;
- pxICMPHeader->usSequenceNumber = usSequenceNumber;
-
- /* Find the start of the data. */
- pucChar = ( uint8_t * ) pxICMPHeader;
- pucChar += sizeof( ICMPHeader_t );
-
- /* Just memset the data to a fixed value. */
- memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend );
-
- /* The message is complete, IP and checksum's are handled by
- vProcessGeneratedUDPPacket */
- pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT;
- pxNetworkBuffer->ulIPAddress = ulIPAddress;
- pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA;
- /* xDataLength is the size of the total packet, including the Ethernet header. */
- pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPPacket_t );
-
- /* Send to the stack. */
- xStackTxEvent.pvData = pxNetworkBuffer;
-
- if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS )
- {
- vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
- iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT );
- }
- else
- {
- xReturn = usSequenceNumber;
- }
- }
- }
- else
- {
- /* The requested number of bytes will not fit in the available space
- in the network buffer. */
- }
-
- return xReturn;
- }
-
-#endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */
-/*-----------------------------------------------------------*/
-
-BaseType_t xSendEventToIPTask( eIPEvent_t eEvent )
-{
-IPStackEvent_t xEventMessage;
-const TickType_t xDontBlock = ( TickType_t ) 0;
-
- xEventMessage.eEventType = eEvent;
- xEventMessage.pvData = ( void* )NULL;
-
- return xSendEventStructToIPTask( &xEventMessage, xDontBlock );
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout )
-{
-BaseType_t xReturn, xSendMessage;
-
- if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) )
- {
- /* Only allow eNetworkDownEvent events if the IP task is not ready
- yet. Not going to attempt to send the message so the send failed. */
- xReturn = pdFAIL;
- }
- else
- {
- xSendMessage = pdTRUE;
-
- #if( ipconfigUSE_TCP == 1 )
- {
- if( pxEvent->eEventType == eTCPTimerEvent )
- {
- /* TCP timer events are sent to wake the timer task when
- xTCPTimer has expired, but there is no point sending them if the
- IP task is already awake processing other message. */
- xTCPTimer.bExpired = pdTRUE_UNSIGNED;
-
- if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0u )
- {
- /* Not actually going to send the message but this is not a
- failure as the message didn't need to be sent. */
- xSendMessage = pdFALSE;
- }
- }
- }
- #endif /* ipconfigUSE_TCP */
-
- if( xSendMessage != pdFALSE )
- {
- /* The IP task cannot block itself while waiting for itself to
- respond. */
- if( ( xIsCallingFromIPTask() == pdTRUE ) && ( xTimeout > ( TickType_t ) 0 ) )
- {
- xTimeout = ( TickType_t ) 0;
- }
-
- xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout );
-
- if( xReturn == pdFAIL )
- {
- /* A message should have been sent to the IP task, but wasn't. */
- FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) );
- iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType );
- }
- }
- else
- {
- /* It was not necessary to send the message to process the event so
- even though the message was not sent the call was successful. */
- xReturn = pdPASS;
- }
- }
-
- return xReturn;
-}
-/*-----------------------------------------------------------*/
-
-eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer )
-{
-eFrameProcessingResult_t eReturn;
-const EthernetHeader_t *pxEthernetHeader;
-
- pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer;
-
- if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 )
- {
- /* The packet was directed to this node directly - process it. */
- eReturn = eProcessBuffer;
- }
- else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
- {
- /* The packet was a broadcast - process it. */
- eReturn = eProcessBuffer;
- }
- else
-#if( ipconfigUSE_LLMNR == 1 )
- if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
- {
- /* The packet is a request for LLMNR - process it. */
- eReturn = eProcessBuffer;
- }
- else
-#endif /* ipconfigUSE_LLMNR */
- {
- /* The packet was not a broadcast, or for this node, just release
- the buffer without taking any other action. */
- eReturn = eReleaseBuffer;
- }
-
- #if( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 )
- {
- uint16_t usFrameType;
-
- if( eReturn == eProcessBuffer )
- {
- usFrameType = pxEthernetHeader->usFrameType;
- usFrameType = FreeRTOS_ntohs( usFrameType );
-
- if( usFrameType <= 0x600U )
- {
- /* Not an Ethernet II frame. */
- eReturn = eReleaseBuffer;
- }
- }
- }
- #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */
-
- return eReturn;
-}
-/*-----------------------------------------------------------*/
-
-static void prvProcessNetworkDownEvent( void )
-{
- /* Stop the ARP timer while there is no network. */
- xARPTimer.bActive = pdFALSE_UNSIGNED;
-
- #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
- {
- static BaseType_t xCallEventHook = pdFALSE;
-
- /* The first network down event is generated by the IP stack itself to
- initialise the network hardware, so do not call the network down event
- the first time through. */
- if( xCallEventHook == pdTRUE )
- {
- vApplicationIPNetworkEventHook( eNetworkDown );
- }
- xCallEventHook = pdTRUE;
- }
- #endif
-
- /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122,
- treat network down as a "delivery problem" and flush the ARP cache for this
- interface. */
- FreeRTOS_ClearARP( );
-
- /* The network has been disconnected (or is being initialised for the first
- time). Perform whatever hardware processing is necessary to bring it up
- again, or wait for it to be available again. This is hardware dependent. */
- if( xNetworkInterfaceInitialise() != pdPASS )
- {
- /* Ideally the network interface initialisation function will only
- return when the network is available. In case this is not the case,
- wait a while before retrying the initialisation. */
- vTaskDelay( ipINITIALISATION_RETRY_DELAY );
- FreeRTOS_NetworkDown();
- }
- else
- {
- /* Set remaining time to 0 so it will become active immediately. */
- #if ipconfigUSE_DHCP == 1
- {
- /* The network is not up until DHCP has completed. */
- vDHCPProcess( pdTRUE );
- xSendEventToIPTask( eDHCPEvent );
- }
- #else
- {
- /* Perform any necessary 'network up' processing. */
- vIPNetworkUpCalls();
- }
- #endif
- }
-}
-/*-----------------------------------------------------------*/
-
-void vIPNetworkUpCalls( void )
-{
- xNetworkUp = pdTRUE;
-
- #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 )
- {
- vApplicationIPNetworkEventHook( eNetworkUp );
- }
- #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */
-
- #if( ipconfigDNS_USE_CALLBACKS != 0 )
- {
- /* The following function is declared in FreeRTOS_DNS.c and 'private' to
- this library */
- extern void vDNSInitialise( void );
- vDNSInitialise();
- }
- #endif /* ipconfigDNS_USE_CALLBACKS != 0 */
-
- /* Set remaining time to 0 so it will become active immediately. */
- prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) );
-}
-/*-----------------------------------------------------------*/
-
-static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
-{
-EthernetHeader_t *pxEthernetHeader;
-eFrameProcessingResult_t eReturned = eReleaseBuffer;
-
- configASSERT( pxNetworkBuffer );
-
- /* Interpret the Ethernet frame. */
- if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) )
- {
- eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer );
- pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer );
-
- if( eReturned == eProcessBuffer )
- {
- /* Interpret the received Ethernet packet. */
- switch( pxEthernetHeader->usFrameType )
- {
- case ipARP_FRAME_TYPE:
- /* The Ethernet frame contains an ARP packet. */
- if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) )
- {
- eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer );
- }
- else
- {
- eReturned = eReleaseBuffer;
- }
- break;
-
- case ipIPv4_FRAME_TYPE:
- /* The Ethernet frame contains an IP packet. */
- if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) )
- {
- eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer );
- }
- else
- {
- eReturned = eReleaseBuffer;
- }
- break;
-
- default:
- /* No other packet types are handled. Nothing to do. */
- eReturned = eReleaseBuffer;
- break;
- }
- }
- }
-
- /* Perform any actions that resulted from processing the Ethernet frame. */
- switch( eReturned )
- {
- case eReturnEthernetFrame :
- /* The Ethernet frame will have been updated (maybe it was
- an ARP request or a PING request?) and should be sent back to
- its source. */
- vReturnEthernetFrame( pxNetworkBuffer, pdTRUE );
- /* parameter pdTRUE: the buffer must be released once
- the frame has been transmitted */
- break;
-
- case eFrameConsumed :
- /* The frame is in use somewhere, don't release the buffer
- yet. */
- break;
-
- default :
- /* The frame is not being used anywhere, and the
- NetworkBufferDescriptor_t structure containing the frame should
- just be released back to the list of free buffers. */
- vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
- break;
- }
-}
-/*-----------------------------------------------------------*/
-
-static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket,
- NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength )
-{
-eFrameProcessingResult_t eReturn = eProcessBuffer;
-
-#if( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) )
- const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
-#else
- /* or else, the parameter won't be used and the function will be optimised
- away */
- ( void ) pxIPPacket;
-#endif
-
- #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 )
- {
- /* In systems with a very small amount of RAM, it might be advantageous
- to have incoming messages checked earlier, by the network card driver.
- This method may decrease the usage of sparse network buffers. */
- uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress;
-
- /* Ensure that the incoming packet is not fragmented (only outgoing
- packets can be fragmented) as these are the only handled IP frames
- currently. */
- if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U )
- {
- /* Can not handle, fragmented packet. */
- eReturn = eReleaseBuffer;
- }
- /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes
- * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */
- else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) )
- {
- /* Can not handle, unknown or invalid header version. */
- eReturn = eReleaseBuffer;
- }
- /* Is the packet for this IP address? */
- else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) &&
- /* Is it the global broadcast address 255.255.255.255 ? */
- ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) &&
- /* Is it a specific broadcast address 192.168.1.255 ? */
- ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) &&
- #if( ipconfigUSE_LLMNR == 1 )
- /* Is it the LLMNR multicast address? */
- ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) &&
- #endif
- /* Or (during DHCP negotiation) we have no IP-address yet? */
- ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) )
- {
- /* Packet is not for this node, release it */
- eReturn = eReleaseBuffer;
- }
- }
- #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */
-
- #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 )
- {
- /* Some drivers of NIC's with checksum-offloading will enable the above
- define, so that the checksum won't be checked again here */
- if (eReturn == eProcessBuffer )
- {
- /* Is the IP header checksum correct? */
- if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) &&
- ( usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) )
- {
- /* Check sum in IP-header not correct. */
- eReturn = eReleaseBuffer;
- }
- /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */
- else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC )
- {
- /* Protocol checksum not accepted. */
- eReturn = eReleaseBuffer;
- }
- }
- }
- #else
- {
- /* to avoid warning unused parameters */
- ( void ) pxNetworkBuffer;
- ( void ) uxHeaderLength;
- }
- #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */
-
- return eReturn;
-}
-/*-----------------------------------------------------------*/
-
-static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer )
-{
-eFrameProcessingResult_t eReturn;
-IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader );
-UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 );
-uint8_t ucProtocol;
-
- /* Bound the calculated header length: take away the Ethernet header size,
- then check if the IP header is claiming to be longer than the remaining
- total packet size. Also check for minimal header field length. */
- if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) ||
- ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) )
- {
- return eReleaseBuffer;
- }
-
- ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
- /* Check if the IP headers are acceptable and if it has our destination. */
- eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength );
-
- if( eReturn == eProcessBuffer )
- {
- if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER )
- {
- /* All structs of headers expect a IP header size of 20 bytes
- * IP header options were included, we'll ignore them and cut them out
- * Note: IP options are mostly use in Multi-cast protocols */
- const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER;
- /* From: the previous start of UDP/ICMP/TCP data */
- uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength);
- /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */
- uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER);
- /* How many: total length minus the options and the lower headers */
- const size_t xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER;
-
- memmove( pucTarget, pucSource, xMoveLen );
- pxNetworkBuffer->xDataLength -= optlen;
-
- /* Fix-up new version/header length field in IP packet. */
- pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */
- ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */
- }
-
- /* Add the IP and MAC addresses to the ARP table if they are not
- already there - otherwise refresh the age of the existing
- entry. */
- if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP )
- {
- /* Refresh the ARP cache with the IP/MAC-address of the received packet
- * For UDP packets, this will be done later in xProcessReceivedUDPPacket()
- * as soon as know that the message will be handled by someone
- * This will prevent that the ARP cache will get overwritten
- * with the IP-address of useless broadcast packets
- */
- vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress );
- }
- switch( ucProtocol )
- {
- case ipPROTOCOL_ICMP :
- /* The IP packet contained an ICMP frame. Don't bother
- checking the ICMP checksum, as if it is wrong then the
- wrong data will also be returned, and the source of the
- ping will know something went wrong because it will not
- be able to validate what it receives. */
- #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
- {
- if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) )
- {
- ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer );
- if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER )
- {
- eReturn = prvProcessICMPPacket( pxICMPPacket );
- }
- }
- else
- {
- eReturn = eReleaseBuffer;
- }
- }
- #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
- break;
-
- case ipPROTOCOL_UDP :
- {
- /* The IP packet contained a UDP frame. */
- UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
-
- /* Only proceed if the payload length indicated in the header
- appears to be valid. */
- if ( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) && ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) >= sizeof( UDPHeader_t ) ) )
- {
- size_t uxPayloadSize_1, uxPayloadSize_2;
- /* The UDP payload size can be calculated by subtracting the
- * header size from `xDataLength`.
- * However, the `xDataLength` may be longer that expected,
- * e.g. when a small packet is padded with zero's.
- * The UDP header contains a field `usLength` reflecting
- * the payload size plus the UDP header ( 8 bytes ).
- * Set `xDataLength` to the size of the headers,
- * plus the lower of the two calculated payload sizes.
- */
-
- uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
- uxPayloadSize_2 = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t );
- if( uxPayloadSize_1 > uxPayloadSize_2 )
- {
- pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t );
- }
-
- /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */
- pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort;
- pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress;
-
- /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM:
- * In some cases, the upper-layer checksum has been calculated
- * by the NIC driver.
- *
- * Pass the packet payload to the UDP sockets implementation. */
- if( xProcessReceivedUDPPacket( pxNetworkBuffer,
- pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS )
- {
- eReturn = eFrameConsumed;
- }
- }
- else
- {
- eReturn = eReleaseBuffer;
- }
- }
- break;
-
-#if ipconfigUSE_TCP == 1
- case ipPROTOCOL_TCP :
- {
-
- if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS )
- {
- eReturn = eFrameConsumed;
- }
-
- /* Setting this variable will cause xTCPTimerCheck()
- to be called just before the IP-task blocks. */
- xProcessedTCPMessage++;
- }
- break;
-#endif
- default :
- /* Not a supported frame type. */
- break;
- }
- }
-
- return eReturn;
-}
-/*-----------------------------------------------------------*/
-
-#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
-
- static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket )
- {
- ePingReplyStatus_t eStatus = eSuccess;
- uint16_t usDataLength, usCount;
- uint8_t *pucByte;
-
- /* Find the total length of the IP packet. */
- usDataLength = pxICMPPacket->xIPHeader.usLength;
- usDataLength = FreeRTOS_ntohs( usDataLength );
-
- /* Remove the length of the IP headers to obtain the length of the ICMP
- message itself. */
- usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER );
-
- /* Remove the length of the ICMP header, to obtain the length of
- data contained in the ping. */
- usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER );
-
- /* Checksum has already been checked before in prvProcessIPPacket */
-
- /* Find the first byte of the data within the ICMP packet. */
- pucByte = ( uint8_t * ) pxICMPPacket;
- pucByte += sizeof( ICMPPacket_t );
-
- /* Check each byte. */
- for( usCount = 0; usCount < usDataLength; usCount++ )
- {
- if( *pucByte != ipECHO_DATA_FILL_BYTE )
- {
- eStatus = eInvalidData;
- break;
- }
-
- pucByte++;
- }
-
- /* Call back into the application to pass it the result. */
- vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier );
- }
-
-#endif
-/*-----------------------------------------------------------*/
-
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
-
- static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket )
- {
- ICMPHeader_t *pxICMPHeader;
- IPHeader_t *pxIPHeader;
- uint16_t usRequest;
-
- pxICMPHeader = &( pxICMPPacket->xICMPHeader );
- pxIPHeader = &( pxICMPPacket->xIPHeader );
-
- /* HT:endian: changed back */
- iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress );
-
- /* The checksum can be checked here - but a ping reply should be
- returned even if the checksum is incorrect so the other end can
- tell that the ping was received - even if the ping reply contains
- invalid data. */
- pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY;
- pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress;
- pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER;
-
- /* Update the checksum because the ucTypeOfMessage member in the header
- has been changed to ipICMP_ECHO_REPLY. This is faster than calling
- usGenerateChecksum(). */
-
- /* due to compiler warning "integer operation result is out of range" */
-
- usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 );
-
- if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) )
- {
- pxICMPHeader->usChecksum = ( uint16_t )
- ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +
- FreeRTOS_htons( usRequest + 1UL ) );
- }
- else
- {
- pxICMPHeader->usChecksum = ( uint16_t )
- ( ( ( uint32_t ) pxICMPHeader->usChecksum ) +
- FreeRTOS_htons( usRequest ) );
- }
- return eReturnEthernetFrame;
- }
-
-#endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */
-/*-----------------------------------------------------------*/
-
-#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
-
- static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket )
- {
- eFrameProcessingResult_t eReturn = eReleaseBuffer;
-
- iptraceICMP_PACKET_RECEIVED();
- switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage )
- {
- case ipICMP_ECHO_REQUEST :
- #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 )
- {
- eReturn = prvProcessICMPEchoRequest( pxICMPPacket );
- }
- #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */
- break;
-
- case ipICMP_ECHO_REPLY :
- #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
- {
- prvProcessICMPEchoReply( pxICMPPacket );
- }
- #endif /* ipconfigSUPPORT_OUTGOING_PINGS */
- break;
-
- default :
- break;
- }
-
- return eReturn;
- }
-
-#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */
-/*-----------------------------------------------------------*/
-
-uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket )
-{
-uint32_t ulLength;
-uint16_t usChecksum, *pusChecksum;
-const IPPacket_t * pxIPPacket;
-UBaseType_t uxIPHeaderLength;
-ProtocolPacket_t *pxProtPack;
-uint8_t ucProtocol;
-#if( ipconfigHAS_DEBUG_PRINTF != 0 )
- const char *pcType;
-#endif
-
- /* Check for minimum packet size. */
- if( uxBufferLength < sizeof( IPPacket_t ) )
- {
- return ipINVALID_LENGTH;
- }
-
- /* Parse the packet length. */
- pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer;
-
- /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header
- Length field contains the length of the internet header in 32-bit words. */
- uxIPHeaderLength = ( UBaseType_t ) ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) );
-
- /* Check for minimum packet size. */
- if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER )
- {
- return ipINVALID_LENGTH;
- }
- if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) )
- {
- return ipINVALID_LENGTH;
- }
-
- /* Identify the next protocol. */
- ucProtocol = pxIPPacket->xIPHeader.ucProtocol;
-
- /* N.B., if this IP packet header includes Options, then the following
- assignment results in a pointer into the protocol packet with the Ethernet
- and IP headers incorrectly aligned. However, either way, the "third"
- protocol (Layer 3 or 4) header will be aligned, which is the convenience
- of this calculation. */
- pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) );
-
- /* Switch on the Layer 3/4 protocol. */
- if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP )
- {
- if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) )
- {
- return ipINVALID_LENGTH;
- }
-
- pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) );
- #if( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- pcType = "UDP";
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
- }
- else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP )
- {
- if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) )
- {
- return ipINVALID_LENGTH;
- }
-
- pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) );
- #if( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- pcType = "TCP";
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
- }
- else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) ||
- ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) )
- {
- if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) )
- {
- return ipINVALID_LENGTH;
- }
-
- pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) );
- #if( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP )
- {
- pcType = "ICMP";
- }
- else
- {
- pcType = "IGMP";
- }
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
- }
- else
- {
- /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */
- return ipUNHANDLED_PROTOCOL;
- }
-
- /* The protocol and checksum field have been identified. Check the direction
- of the packet. */
- if( xOutgoingPacket != pdFALSE )
- {
- /* This is an outgoing packet. Before calculating the checksum, set it
- to zero. */
- *( pusChecksum ) = 0u;
- }
- else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
- {
- /* Sender hasn't set the checksum, no use to calculate it. */
- return ipCORRECT_CRC;
- }
-
- ulLength = ( uint32_t )
- ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */
-
- if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) ||
- ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) )
- {
- #if( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) );
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
-
- /* Again, in a 16-bit return value there is no space to indicate an
- error. For incoming packets, 0x1234 will cause dropping of the packet.
- For outgoing packets, there is a serious problem with the
- format/length */
- return ipINVALID_LENGTH;
- }
- if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP )
- {
- /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */
- usChecksum = ( uint16_t )
- ( ~usGenerateChecksum( 0UL,
- ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) );
- }
- else
- {
- /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length
- fields */
- usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) );
-
- /* And then continue at the IPv4 source and destination addresses. */
- usChecksum = ( uint16_t )
- ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ),
- ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) );
-
- /* Sum TCP header and data. */
- }
-
- if( xOutgoingPacket == pdFALSE )
- {
- /* This is in incoming packet. If the CRC is correct, it should be zero. */
- if( usChecksum == 0u )
- {
- usChecksum = ( uint16_t )ipCORRECT_CRC;
- }
- }
- else
- {
- if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) )
- {
- /* In case of UDP, a calculated checksum of 0x0000 is transmitted
- as 0xffff. A value of zero would mean that the checksum is not used. */
- #if( ipconfigHAS_DEBUG_PRINTF != 0 )
- {
- if( xOutgoingPacket != pdFALSE )
- {
- FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) );
- }
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
-
- usChecksum = ( uint16_t )0xffffu;
- }
- }
- usChecksum = FreeRTOS_htons( usChecksum );
-
- if( xOutgoingPacket != pdFALSE )
- {
- *( pusChecksum ) = usChecksum;
- }
- #if( ipconfigHAS_DEBUG_PRINTF != 0 )
- else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) )
- {
- FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n",
- pcType,
- FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ),
- FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ),
- FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ),
- FreeRTOS_ntohs( *pusChecksum ) ) );
- }
- #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */
-
- return usChecksum;
-}
-/*-----------------------------------------------------------*/
-
-/**
- * This method generates a checksum for a given IPv4 header, per RFC791 (page 14).
- * The checksum algorithm is decribed as:
- * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the
- * header. For purposes of computing the checksum, the value of the checksum field is zero."
- *
- * In a nutshell, that means that each 16-bit 'word' must be summed, after which
- * the number of 'carries' (overflows) is added to the result. If that addition
- * produces an overflow, that 'carry' must also be added to the final result. The final checksum
- * should be the bitwise 'not' (ones-complement) of the result if the packet is
- * meant to be transmitted, but this method simply returns the raw value, probably
- * because when a packet is received, the checksum is verified by checking that
- * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum.
- *
- * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd.
- * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit
- * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary,
- * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'.
- * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'.
- * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found
- * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue
- * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like:
- * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ];
- *
- * Arguments:
- * ulSum: This argument provides a value to initialize the progressive summation
- * of the header's values to. It is often 0, but protocols like TCP or UDP
- * can have pseudo-header fields which need to be included in the checksum.
- * pucNextData: This argument contains the address of the first byte which this
- * method should process. The method's memory iterator is initialized to this value.
- * uxDataLengthBytes: This argument contains the number of bytes that this method
- * should process.
- */
-uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes )
-{
-xUnion32 xSum2, xSum, xTerm;
-xUnionPtr xSource; /* Points to first byte */
-xUnionPtr xLastSource; /* Points to last byte plus one */
-uint32_t ulAlignBits, ulCarry = 0ul;
-
- /* Small MCUs often spend up to 30% of the time doing checksum calculations
- This function is optimised for 32-bit CPUs; Each time it will try to fetch
- 32-bits, sums it with an accumulator and counts the number of carries. */
-
- /* Swap the input (little endian platform only). */
- xSum.u32 = FreeRTOS_ntohs( ulSum );
- xTerm.u32 = 0ul;
-
- xSource.u8ptr = ( uint8_t * ) pucNextData;
- ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */
-
- /* If byte (8-bit) aligned... */
- if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) )
- {
- xTerm.u8[ 1 ] = *( xSource.u8ptr );
- ( xSource.u8ptr )++;
- uxDataLengthBytes--;
- /* Now xSource is word (16-bit) aligned. */
- }
-
- /* If half-word (16-bit) aligned... */
- if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) )
- {
- xSum.u32 += *(xSource.u16ptr);
- ( xSource.u16ptr )++;
- uxDataLengthBytes -= 2u;
- /* Now xSource is word (32-bit) aligned. */
- }
-
- /* Word (32-bit) aligned, do the most part. */
- xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u;
-
- /* In this loop, four 32-bit additions will be done, in total 16 bytes.
- Indexing with constants (0,1,2,3) gives faster code than using
- post-increments. */
- while( xSource.u32ptr < xLastSource.u32ptr )
- {
- /* Use a secondary Sum2, just to see if the addition produced an
- overflow. */
- xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ];
- if( xSum2.u32 < xSum.u32 )
- {
- ulCarry++;
- }
-
- /* Now add the secondary sum to the major sum, and remember if there was
- a carry. */
- xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ];
- if( xSum2.u32 > xSum.u32 )
- {
- ulCarry++;
- }
-
- /* And do the same trick once again for indexes 2 and 3 */
- xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ];
- if( xSum2.u32 < xSum.u32 )
- {
- ulCarry++;
- }
-
- xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ];
-
- if( xSum2.u32 > xSum.u32 )
- {
- ulCarry++;
- }
-
- /* And finally advance the pointer 4 * 4 = 16 bytes. */
- xSource.u32ptr += 4;
- }
-
- /* Now add all carries. */
- xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry;
-
- uxDataLengthBytes %= 16u;
- xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) );
-
- /* Half-word aligned. */
- while( xSource.u16ptr < xLastSource.u16ptr )
- {
- /* At least one more short. */
- xSum.u32 += xSource.u16ptr[ 0 ];
- xSource.u16ptr++;
- }
-
- if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u ) /* Maybe one more ? */
- {
- xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ];
- }
- xSum.u32 += xTerm.u32;
-
- /* Now add all carries again. */
- xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
-
- /* The previous summation might have given a 16-bit carry. */
- xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ];
-
- if( ( ulAlignBits & 1u ) != 0u )
- {
- /* Quite unlikely, but pucNextData might be non-aligned, which would
- mean that a checksum is calculated starting at an odd position. */
- xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 );
- }
-
- /* swap the output (little endian platform only). */
- return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) );
-}
-/*-----------------------------------------------------------*/
-
-void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend )
-{
-EthernetHeader_t *pxEthernetHeader;
-
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
- NetworkBufferDescriptor_t *pxNewBuffer;
-#endif
-
- #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
- {
- if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
- {
- BaseType_t xIndex;
-
- FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )pxNetworkBuffer->xDataLength ) );
- for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
- {
- pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u;
- }
- pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
- }
- }
- #endif
-
-#if( ipconfigZERO_COPY_TX_DRIVER != 0 )
-
- if( xReleaseAfterSend == pdFALSE )
- {
- pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength );
- xReleaseAfterSend = pdTRUE;
- pxNetworkBuffer = pxNewBuffer;
- }
-
- if( pxNetworkBuffer != NULL )
-#endif
- {
- pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
-
- /* Swap source and destination MAC addresses. */
- memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) );
- memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES );
-
- /* Send! */
- xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend );
- }
-}
-/*-----------------------------------------------------------*/
-
-uint32_t FreeRTOS_GetIPAddress( void )
-{
- /* Returns the IP address of the NIC. */
- return *ipLOCAL_IP_ADDRESS_POINTER;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_SetIPAddress( uint32_t ulIPAddress )
-{
- /* Sets the IP address of the NIC. */
- *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress;
-}
-/*-----------------------------------------------------------*/
-
-uint32_t FreeRTOS_GetGatewayAddress( void )
-{
- return xNetworkAddressing.ulGatewayAddress;
-}
-/*-----------------------------------------------------------*/
-
-uint32_t FreeRTOS_GetDNSServerAddress( void )
-{
- return xNetworkAddressing.ulDNSServerAddress;
-}
-/*-----------------------------------------------------------*/
-
-uint32_t FreeRTOS_GetNetmask( void )
-{
- return xNetworkAddressing.ulNetMask;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] )
-{
- /* Copy the MAC address at the start of the default packet header fragment. */
- memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES );
-}
-/*-----------------------------------------------------------*/
-
-const uint8_t * FreeRTOS_GetMACAddress( void )
-{
- return ipLOCAL_MAC_ADDRESS;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_SetNetmask ( uint32_t ulNetmask )
-{
- xNetworkAddressing.ulNetMask = ulNetmask;
-}
-/*-----------------------------------------------------------*/
-
-void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress )
-{
- xNetworkAddressing.ulGatewayAddress = ulGatewayAddress;
-}
-/*-----------------------------------------------------------*/
-
-#if( ipconfigUSE_DHCP == 1 )
- void vIPSetDHCPTimerEnableState( BaseType_t xEnableState )
- {
- if( xEnableState != pdFALSE )
- {
- xDHCPTimer.bActive = pdTRUE_UNSIGNED;
- }
- else
- {
- xDHCPTimer.bActive = pdFALSE_UNSIGNED;
- }
- }
-#endif /* ipconfigUSE_DHCP */
-/*-----------------------------------------------------------*/
-
-#if( ipconfigUSE_DHCP == 1 )
- void vIPReloadDHCPTimer( uint32_t ulLeaseTime )
- {
- prvIPTimerReload( &xDHCPTimer, ulLeaseTime );
- }
-#endif /* ipconfigUSE_DHCP */
-/*-----------------------------------------------------------*/
-
-#if( ipconfigDNS_USE_CALLBACKS == 1 )
- void vIPSetDnsTimerEnableState( BaseType_t xEnableState )
- {
- if( xEnableState != 0 )
- {
- xDNSTimer.bActive = pdTRUE;
- }
- else
- {
- xDNSTimer.bActive = pdFALSE;
- }
- }
-#endif /* ipconfigUSE_DHCP */
-/*-----------------------------------------------------------*/
-
-#if( ipconfigDNS_USE_CALLBACKS != 0 )
- void vIPReloadDNSTimer( uint32_t ulCheckTime )
- {
- prvIPTimerReload( &xDNSTimer, ulCheckTime );
- }
-#endif /* ipconfigDNS_USE_CALLBACKS != 0 */
-/*-----------------------------------------------------------*/
-
-BaseType_t xIPIsNetworkTaskReady( void )
-{
- return xIPTaskInitialised;
-}
-/*-----------------------------------------------------------*/
-
-BaseType_t FreeRTOS_IsNetworkUp( void )
-{
- return xNetworkUp;
-}
-/*-----------------------------------------------------------*/
-
-#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
- UBaseType_t uxGetMinimumIPQueueSpace( void )
- {
- return uxQueueMinimumSpace;
- }
-#endif
-/*-----------------------------------------------------------*/
-
-/* Provide access to private members for verification. */
-#ifdef FREERTOS_TCP_ENABLE_VERIFICATION
- #include "aws_freertos_ip_verification_access_ip_define.h"
-#endif
-
+/* + * FreeRTOS+TCP V2.2.0 + * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://aws.amazon.com/freertos + * http://www.FreeRTOS.org + */ + +/* Standard includes. */ +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +/* FreeRTOS includes. */ +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" +#include "semphr.h" + +/* FreeRTOS+TCP includes. */ +#include "FreeRTOS_IP.h" +#include "FreeRTOS_Sockets.h" +#include "FreeRTOS_IP_Private.h" +#include "FreeRTOS_ARP.h" +#include "FreeRTOS_UDP_IP.h" +#include "FreeRTOS_TCP_IP.h" +#include "FreeRTOS_DHCP.h" +#include "NetworkInterface.h" +#include "NetworkBufferManagement.h" +#include "FreeRTOS_DNS.h" + + +/* Used to ensure the structure packing is having the desired effect. The +'volatile' is used to prevent compiler warnings about comparing a constant with +a constant. */ +#define ipEXPECTED_EthernetHeader_t_SIZE ( ( size_t ) 14 ) +#define ipEXPECTED_ARPHeader_t_SIZE ( ( size_t ) 28 ) +#define ipEXPECTED_IPHeader_t_SIZE ( ( size_t ) 20 ) +#define ipEXPECTED_IGMPHeader__SIZE ( ( size_t ) 8 ) +#define ipEXPECTED_ICMPHeader_t_SIZE ( ( size_t ) 8 ) +#define ipEXPECTED_UDPHeader_t_SIZE ( ( size_t ) 8 ) +#define ipEXPECTED_TCPHeader_t_SIZE ( ( size_t ) 20 ) + + +/* ICMP protocol definitions. */ +#define ipICMP_ECHO_REQUEST ( ( uint8_t ) 8 ) +#define ipICMP_ECHO_REPLY ( ( uint8_t ) 0 ) + + +/* Time delay between repeated attempts to initialise the network hardware. */ +#ifndef ipINITIALISATION_RETRY_DELAY + #define ipINITIALISATION_RETRY_DELAY ( pdMS_TO_TICKS( 3000 ) ) +#endif + +/* Defines how often the ARP timer callback function is executed. The time is +shorted in the Windows simulator as simulated time is not real time. */ +#ifndef ipARP_TIMER_PERIOD_MS + #ifdef _WINDOWS_ + #define ipARP_TIMER_PERIOD_MS ( 500 ) /* For windows simulator builds. */ + #else + #define ipARP_TIMER_PERIOD_MS ( 10000 ) + #endif +#endif + +#ifndef iptraceIP_TASK_STARTING + #define iptraceIP_TASK_STARTING() do {} while( 0 ) +#endif + +#if( ( ipconfigUSE_TCP == 1 ) && !defined( ipTCP_TIMER_PERIOD_MS ) ) + /* When initialising the TCP timer, + give it an initial time-out of 1 second. */ + #define ipTCP_TIMER_PERIOD_MS ( 1000 ) +#endif + +/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet +driver will filter incoming packets and only pass the stack those packets it +considers need processing. In this case ipCONSIDER_FRAME_FOR_PROCESSING() can +be #defined away. If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 0 +then the Ethernet driver will pass all received packets to the stack, and the +stack must do the filtering itself. In this case ipCONSIDER_FRAME_FOR_PROCESSING +needs to call eConsiderFrameForProcessing. */ +#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) ) +#else + #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer +#endif + +/* The character used to fill ICMP echo requests, and therefore also the +character expected to fill ICMP echo replies. */ +#define ipECHO_DATA_FILL_BYTE 'x' + +#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) + /* The bits in the two byte IP header field that make up the fragment offset value. */ + #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0xff0f ) +#else + /* The bits in the two byte IP header field that make up the fragment offset value. */ + #define ipFRAGMENT_OFFSET_BIT_MASK ( ( uint16_t ) 0x0fff ) +#endif /* ipconfigBYTE_ORDER */ + +/* The maximum time the IP task is allowed to remain in the Blocked state if no +events are posted to the network event queue. */ +#ifndef ipconfigMAX_IP_TASK_SLEEP_TIME + #define ipconfigMAX_IP_TASK_SLEEP_TIME ( pdMS_TO_TICKS( 10000UL ) ) +#endif + +/* When a new TCP connection is established, the value of +'ulNextInitialSequenceNumber' will be used as the initial sequence number. It +is very important that at start-up, 'ulNextInitialSequenceNumber' contains a +random value. Also its value must be increased continuously in time, to prevent +a third party guessing the next sequence number and take-over a TCP connection. +It is advised to increment it by 1 ever 4us, which makes about 256 times +per ms: */ +#define ipINITIAL_SEQUENCE_NUMBER_FACTOR 256UL + +/* Returned as the (invalid) checksum when the protocol being checked is not +handled. The value is chosen simply to be easy to spot when debugging. */ +#define ipUNHANDLED_PROTOCOL 0x4321u + +/* Returned to indicate a valid checksum when the checksum does not need to be +calculated. */ +#define ipCORRECT_CRC 0xffffu + +/* Returned as the (invalid) checksum when the length of the data being checked +had an invalid length. */ +#define ipINVALID_LENGTH 0x1234u + +/*-----------------------------------------------------------*/ + +typedef struct xIP_TIMER +{ + uint32_t + bActive : 1, /* This timer is running and must be processed. */ + bExpired : 1; /* Timer has expired and a task must be processed. */ + TimeOut_t xTimeOut; + TickType_t ulRemainingTime; + TickType_t ulReloadTime; +} IPTimer_t; + +/* Used in checksum calculation. */ +typedef union _xUnion32 +{ + uint32_t u32; + uint16_t u16[ 2 ]; + uint8_t u8[ 4 ]; +} xUnion32; + +/* Used in checksum calculation. */ +typedef union _xUnionPtr +{ + uint32_t *u32ptr; + uint16_t *u16ptr; + uint8_t *u8ptr; +} xUnionPtr; + +/*-----------------------------------------------------------*/ + +/* + * The main TCP/IP stack processing task. This task receives commands/events + * from the network hardware drivers and tasks that are using sockets. It also + * maintains a set of protocol timers. + */ +static void prvIPTask( void *pvParameters ); + +/* + * Called when new data is available from the network interface. + */ +static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ); + +/* + * Process incoming IP packets. + */ +static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ); + +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + /* + * Process incoming ICMP packets. + */ + static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket ); +#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ + +/* + * Turns around an incoming ping request to convert it into a ping reply. + */ +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) + static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket ); +#endif /* ipconfigREPLY_TO_INCOMING_PINGS */ + +/* + * Processes incoming ping replies. The application callback function + * vApplicationPingReplyHook() is called with the results. + */ +#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket ); +#endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + +/* + * Called to create a network connection when the stack is first started, or + * when the network connection is lost. + */ +static void prvProcessNetworkDownEvent( void ); + +/* + * Checks the ARP, DHCP and TCP timers to see if any periodic or timeout + * processing is required. + */ +static void prvCheckNetworkTimers( void ); + +/* + * Determine how long the IP task can sleep for, which depends on when the next + * periodic or timeout processing must be performed. + */ +static TickType_t prvCalculateSleepTime( void ); + +/* + * The network card driver has received a packet. In the case that it is part + * of a linked packet chain, walk through it to handle every message. + */ +static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer ); + +/* + * Utility functions for the light weight IP timers. + */ +static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime ); +static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer ); +static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime ); + +static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket, + NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength ); + +/*-----------------------------------------------------------*/ + +/* The queue used to pass events into the IP-task for processing. */ +QueueHandle_t xNetworkEventQueue = NULL; + +/*_RB_ Requires comment. */ +uint16_t usPacketIdentifier = 0U; + +/* For convenience, a MAC address of all 0xffs is defined const for quick +reference. */ +const MACAddress_t xBroadcastMACAddress = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }; + +/* Structure that stores the netmask, gateway address and DNS server addresses. */ +NetworkAddressingParameters_t xNetworkAddressing = { 0, 0, 0, 0, 0 }; + +/* Default values for the above struct in case DHCP +does not lead to a confirmed request. */ +NetworkAddressingParameters_t xDefaultAddressing = { 0, 0, 0, 0, 0 }; + +/* Used to ensure network down events cannot be missed when they cannot be +posted to the network event queue because the network event queue is already +full. */ +static BaseType_t xNetworkDownEventPending = pdFALSE; + +/* Stores the handle of the task that handles the stack. The handle is used +(indirectly) by some utility function to determine if the utility function is +being called by a task (in which case it is ok to block) or by the IP task +itself (in which case it is not ok to block). */ +static TaskHandle_t xIPTaskHandle = NULL; + +#if( ipconfigUSE_TCP != 0 ) + /* Set to a non-zero value if one or more TCP message have been processed + within the last round. */ + static BaseType_t xProcessedTCPMessage; +#endif + +/* Simple set to pdTRUE or pdFALSE depending on whether the network is up or +down (connected, not connected) respectively. */ +static BaseType_t xNetworkUp = pdFALSE; + +/* +A timer for each of the following processes, all of which need attention on a +regular basis: + 1. ARP, to check its table entries + 2. DPHC, to send requests and to renew a reservation + 3. TCP, to check for timeouts, resends + 4. DNS, to check for timeouts when looking-up a domain. + */ +static IPTimer_t xARPTimer; +#if( ipconfigUSE_DHCP != 0 ) + static IPTimer_t xDHCPTimer; +#endif +#if( ipconfigUSE_TCP != 0 ) + static IPTimer_t xTCPTimer; +#endif +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + static IPTimer_t xDNSTimer; +#endif + +/* Set to pdTRUE when the IP task is ready to start processing packets. */ +static BaseType_t xIPTaskInitialised = pdFALSE; + +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + /* Keep track of the lowest amount of space in 'xNetworkEventQueue'. */ + static UBaseType_t uxQueueMinimumSpace = ipconfigEVENT_QUEUE_LENGTH; +#endif + +/*-----------------------------------------------------------*/ + +static void prvIPTask( void *pvParameters ) +{ +IPStackEvent_t xReceivedEvent; +TickType_t xNextIPSleep; +FreeRTOS_Socket_t *pxSocket; +struct freertos_sockaddr xAddress; + + /* Just to prevent compiler warnings about unused parameters. */ + ( void ) pvParameters; + + /* A possibility to set some additional task properties. */ + iptraceIP_TASK_STARTING(); + + /* Generate a dummy message to say that the network connection has gone + down. This will cause this task to initialise the network interface. After + this it is the responsibility of the network interface hardware driver to + send this message if a previously connected network is disconnected. */ + FreeRTOS_NetworkDown(); + + #if( ipconfigUSE_TCP == 1 ) + { + /* Initialise the TCP timer. */ + prvIPTimerReload( &xTCPTimer, pdMS_TO_TICKS( ipTCP_TIMER_PERIOD_MS ) ); + } + #endif + + /* Initialisation is complete and events can now be processed. */ + xIPTaskInitialised = pdTRUE; + + FreeRTOS_debug_printf( ( "prvIPTask started\n" ) ); + + /* Loop, processing IP events. */ + for( ;; ) + { + ipconfigWATCHDOG_TIMER(); + + /* Check the ARP, DHCP and TCP timers to see if there is any periodic + or timeout processing to perform. */ + prvCheckNetworkTimers(); + + /* Calculate the acceptable maximum sleep time. */ + xNextIPSleep = prvCalculateSleepTime(); + + /* Wait until there is something to do. If the following call exits + * due to a time out rather than a message being received, set a + * 'NoEvent' value. */ + if ( xQueueReceive( xNetworkEventQueue, ( void * ) &xReceivedEvent, xNextIPSleep ) == pdFALSE ) + { + xReceivedEvent.eEventType = eNoEvent; + } + + #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + { + if( xReceivedEvent.eEventType != eNoEvent ) + { + UBaseType_t uxCount; + + uxCount = uxQueueSpacesAvailable( xNetworkEventQueue ); + if( uxQueueMinimumSpace > uxCount ) + { + uxQueueMinimumSpace = uxCount; + } + } + } + #endif /* ipconfigCHECK_IP_QUEUE_SPACE */ + + iptraceNETWORK_EVENT_RECEIVED( xReceivedEvent.eEventType ); + + switch( xReceivedEvent.eEventType ) + { + case eNetworkDownEvent : + /* Attempt to establish a connection. */ + xNetworkUp = pdFALSE; + prvProcessNetworkDownEvent(); + break; + + case eNetworkRxEvent: + /* The network hardware driver has received a new packet. A + pointer to the received buffer is located in the pvData member + of the received event structure. */ + prvHandleEthernetPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) ); + break; + + case eNetworkTxEvent: + /* Send a network packet. The ownership will be transferred to + the driver, which will release it after delivery. */ + xNetworkInterfaceOutput( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ), pdTRUE ); + break; + + case eARPTimerEvent : + /* The ARP timer has expired, process the ARP cache. */ + vARPAgeCache(); + break; + + case eSocketBindEvent: + /* FreeRTOS_bind (a user API) wants the IP-task to bind a socket + to a port. The port number is communicated in the socket field + usLocalPort. vSocketBind() will actually bind the socket and the + API will unblock as soon as the eSOCKET_BOUND event is + triggered. */ + pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ); + xAddress.sin_addr = 0u; /* For the moment. */ + xAddress.sin_port = FreeRTOS_ntohs( pxSocket->usLocalPort ); + pxSocket->usLocalPort = 0u; + vSocketBind( pxSocket, &xAddress, sizeof( xAddress ), pdFALSE ); + + /* Before 'eSocketBindEvent' was sent it was tested that + ( xEventGroup != NULL ) so it can be used now to wake up the + user. */ + pxSocket->xEventBits |= eSOCKET_BOUND; + vSocketWakeUpUser( pxSocket ); + break; + + case eSocketCloseEvent : + /* The user API FreeRTOS_closesocket() has sent a message to the + IP-task to actually close a socket. This is handled in + vSocketClose(). As the socket gets closed, there is no way to + report back to the API, so the API won't wait for the result */ + vSocketClose( ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ) ); + break; + + case eStackTxEvent : + /* The network stack has generated a packet to send. A + pointer to the generated buffer is located in the pvData + member of the received event structure. */ + vProcessGeneratedUDPPacket( ( NetworkBufferDescriptor_t * ) ( xReceivedEvent.pvData ) ); + break; + + case eDHCPEvent: + /* The DHCP state machine needs processing. */ + #if( ipconfigUSE_DHCP == 1 ) + { + vDHCPProcess( pdFALSE ); + } + #endif /* ipconfigUSE_DHCP */ + break; + + case eSocketSelectEvent : + /* FreeRTOS_select() has got unblocked by a socket event, + vSocketSelect() will check which sockets actually have an event + and update the socket field xSocketBits. */ + #if( ipconfigSUPPORT_SELECT_FUNCTION == 1 ) + { + vSocketSelect( ( SocketSelect_t * ) ( xReceivedEvent.pvData ) ); + } + #endif /* ipconfigSUPPORT_SELECT_FUNCTION == 1 */ + break; + + case eSocketSignalEvent : + #if( ipconfigSUPPORT_SIGNALS != 0 ) + { + /* Some task wants to signal the user of this socket in + order to interrupt a call to recv() or a call to select(). */ + FreeRTOS_SignalSocket( ( Socket_t ) xReceivedEvent.pvData ); + } + #endif /* ipconfigSUPPORT_SIGNALS */ + break; + + case eTCPTimerEvent : + #if( ipconfigUSE_TCP == 1 ) + { + /* Simply mark the TCP timer as expired so it gets processed + the next time prvCheckNetworkTimers() is called. */ + xTCPTimer.bExpired = pdTRUE_UNSIGNED; + } + #endif /* ipconfigUSE_TCP */ + break; + + case eTCPAcceptEvent: + /* The API FreeRTOS_accept() was called, the IP-task will now + check if the listening socket (communicated in pvData) actually + received a new connection. */ + #if( ipconfigUSE_TCP == 1 ) + { + pxSocket = ( FreeRTOS_Socket_t * ) ( xReceivedEvent.pvData ); + + if( xTCPCheckNewClient( pxSocket ) != pdFALSE ) + { + pxSocket->xEventBits |= eSOCKET_ACCEPT; + vSocketWakeUpUser( pxSocket ); + } + } + #endif /* ipconfigUSE_TCP */ + break; + + case eTCPNetStat: + /* FreeRTOS_netstat() was called to have the IP-task print an + overview of all sockets and their connections */ + #if( ( ipconfigUSE_TCP == 1 ) && ( ipconfigHAS_PRINTF == 1 ) ) + { + vTCPNetStat(); + } + #endif /* ipconfigUSE_TCP */ + break; + + default : + /* Should not get here. */ + break; + } + + if( xNetworkDownEventPending != pdFALSE ) + { + /* A network down event could not be posted to the network event + queue because the queue was full. Try posting again. */ + FreeRTOS_NetworkDown(); + } + } +} +/*-----------------------------------------------------------*/ + +BaseType_t xIsCallingFromIPTask( void ) +{ +BaseType_t xReturn; + + if( xTaskGetCurrentTaskHandle() == xIPTaskHandle ) + { + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +static void prvHandleEthernetPacket( NetworkBufferDescriptor_t *pxBuffer ) +{ + #if( ipconfigUSE_LINKED_RX_MESSAGES == 0 ) + { + /* When ipconfigUSE_LINKED_RX_MESSAGES is not set to 0 then only one + buffer will be sent at a time. This is the default way for +TCP to pass + messages from the MAC to the TCP/IP stack. */ + prvProcessEthernetPacket( pxBuffer ); + } + #else /* ipconfigUSE_LINKED_RX_MESSAGES */ + { + NetworkBufferDescriptor_t *pxNextBuffer; + + /* An optimisation that is useful when there is high network traffic. + Instead of passing received packets into the IP task one at a time the + network interface can chain received packets together and pass them into + the IP task in one go. The packets are chained using the pxNextBuffer + member. The loop below walks through the chain processing each packet + in the chain in turn. */ + do + { + /* Store a pointer to the buffer after pxBuffer for use later on. */ + pxNextBuffer = pxBuffer->pxNextBuffer; + + /* Make it NULL to avoid using it later on. */ + pxBuffer->pxNextBuffer = NULL; + + prvProcessEthernetPacket( pxBuffer ); + pxBuffer = pxNextBuffer; + + /* While there is another packet in the chain. */ + } while( pxBuffer != NULL ); + } + #endif /* ipconfigUSE_LINKED_RX_MESSAGES */ +} +/*-----------------------------------------------------------*/ + +static TickType_t prvCalculateSleepTime( void ) +{ +TickType_t xMaximumSleepTime; + + /* Start with the maximum sleep time, then check this against the remaining + time in any other timers that are active. */ + xMaximumSleepTime = ipconfigMAX_IP_TASK_SLEEP_TIME; + + if( xARPTimer.bActive != pdFALSE_UNSIGNED ) + { + if( xARPTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xARPTimer.ulReloadTime; + } + } + + #if( ipconfigUSE_DHCP == 1 ) + { + if( xDHCPTimer.bActive != pdFALSE_UNSIGNED ) + { + if( xDHCPTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xDHCPTimer.ulRemainingTime; + } + } + } + #endif /* ipconfigUSE_DHCP */ + + #if( ipconfigUSE_TCP == 1 ) + { + if( xTCPTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xTCPTimer.ulRemainingTime; + } + } + #endif + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + if( xDNSTimer.bActive != pdFALSE ) + { + if( xDNSTimer.ulRemainingTime < xMaximumSleepTime ) + { + xMaximumSleepTime = xDNSTimer.ulRemainingTime; + } + } + } + #endif + + return xMaximumSleepTime; +} +/*-----------------------------------------------------------*/ + +static void prvCheckNetworkTimers( void ) +{ + /* Is it time for ARP processing? */ + if( prvIPTimerCheck( &xARPTimer ) != pdFALSE ) + { + xSendEventToIPTask( eARPTimerEvent ); + } + + #if( ipconfigUSE_DHCP == 1 ) + { + /* Is it time for DHCP processing? */ + if( prvIPTimerCheck( &xDHCPTimer ) != pdFALSE ) + { + xSendEventToIPTask( eDHCPEvent ); + } + } + #endif /* ipconfigUSE_DHCP */ + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + extern void vDNSCheckCallBack( void *pvSearchID ); + + /* Is it time for DNS processing? */ + if( prvIPTimerCheck( &xDNSTimer ) != pdFALSE ) + { + vDNSCheckCallBack( NULL ); + } + } + #endif /* ipconfigDNS_USE_CALLBACKS */ + + #if( ipconfigUSE_TCP == 1 ) + { + BaseType_t xWillSleep; + TickType_t xNextTime; + BaseType_t xCheckTCPSockets; + + if( uxQueueMessagesWaiting( xNetworkEventQueue ) == 0u ) + { + xWillSleep = pdTRUE; + } + else + { + xWillSleep = pdFALSE; + } + + /* Sockets need to be checked if the TCP timer has expired. */ + xCheckTCPSockets = prvIPTimerCheck( &xTCPTimer ); + + /* Sockets will also be checked if there are TCP messages but the + message queue is empty (indicated by xWillSleep being true). */ + if( ( xProcessedTCPMessage != pdFALSE ) && ( xWillSleep != pdFALSE ) ) + { + xCheckTCPSockets = pdTRUE; + } + + if( xCheckTCPSockets != pdFALSE ) + { + /* Attend to the sockets, returning the period after which the + check must be repeated. */ + xNextTime = xTCPTimerCheck( xWillSleep ); + prvIPTimerStart( &xTCPTimer, xNextTime ); + xProcessedTCPMessage = 0; + } + } + #endif /* ipconfigUSE_TCP == 1 */ +} +/*-----------------------------------------------------------*/ + +static void prvIPTimerStart( IPTimer_t *pxTimer, TickType_t xTime ) +{ + vTaskSetTimeOutState( &pxTimer->xTimeOut ); + pxTimer->ulRemainingTime = xTime; + + if( xTime == ( TickType_t ) 0 ) + { + pxTimer->bExpired = pdTRUE_UNSIGNED; + } + else + { + pxTimer->bExpired = pdFALSE_UNSIGNED; + } + + pxTimer->bActive = pdTRUE_UNSIGNED; +} +/*-----------------------------------------------------------*/ + +static void prvIPTimerReload( IPTimer_t *pxTimer, TickType_t xTime ) +{ + pxTimer->ulReloadTime = xTime; + prvIPTimerStart( pxTimer, xTime ); +} +/*-----------------------------------------------------------*/ + +static BaseType_t prvIPTimerCheck( IPTimer_t *pxTimer ) +{ +BaseType_t xReturn; + + if( pxTimer->bActive == pdFALSE_UNSIGNED ) + { + /* The timer is not enabled. */ + xReturn = pdFALSE; + } + else + { + /* The timer might have set the bExpired flag already, if not, check the + value of xTimeOut against ulRemainingTime. */ + if( ( pxTimer->bExpired != pdFALSE_UNSIGNED ) || + ( xTaskCheckForTimeOut( &( pxTimer->xTimeOut ), &( pxTimer->ulRemainingTime ) ) != pdFALSE ) ) + { + prvIPTimerStart( pxTimer, pxTimer->ulReloadTime ); + xReturn = pdTRUE; + } + else + { + xReturn = pdFALSE; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_NetworkDown( void ) +{ +static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL }; +const TickType_t xDontBlock = ( TickType_t ) 0; + + /* Simply send the network task the appropriate event. */ + if( xSendEventStructToIPTask( &xNetworkDownEvent, xDontBlock ) != pdPASS ) + { + /* Could not send the message, so it is still pending. */ + xNetworkDownEventPending = pdTRUE; + } + else + { + /* Message was sent so it is not pending. */ + xNetworkDownEventPending = pdFALSE; + } + + iptraceNETWORK_DOWN(); +} +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_NetworkDownFromISR( void ) +{ +static const IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL }; +BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + /* Simply send the network task the appropriate event. */ + if( xQueueSendToBackFromISR( xNetworkEventQueue, &xNetworkDownEvent, &xHigherPriorityTaskWoken ) != pdPASS ) + { + xNetworkDownEventPending = pdTRUE; + } + else + { + xNetworkDownEventPending = pdFALSE; + } + + iptraceNETWORK_DOWN(); + + return xHigherPriorityTaskWoken; +} +/*-----------------------------------------------------------*/ + +void *FreeRTOS_GetUDPPayloadBuffer( size_t xRequestedSizeBytes, TickType_t xBlockTimeTicks ) +{ +NetworkBufferDescriptor_t *pxNetworkBuffer; +void *pvReturn; + + /* Cap the block time. The reason for this is explained where + ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS is defined (assuming an official + FreeRTOSIPConfig.h header file is being used). */ + if( xBlockTimeTicks > ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ) + { + xBlockTimeTicks = ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS; + } + + /* Obtain a network buffer with the required amount of storage. */ + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + xRequestedSizeBytes, xBlockTimeTicks ); + + if( pxNetworkBuffer != NULL ) + { + /* Set the actual packet size in case a bigger buffer was returned. */ + pxNetworkBuffer->xDataLength = sizeof( UDPPacket_t ) + xRequestedSizeBytes; + + /* Leave space for the UPD header. */ + pvReturn = ( void * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] ); + } + else + { + pvReturn = NULL; + } + + return ( void * ) pvReturn; +} +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxDuplicateNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer, + size_t uxNewLength ) +{ +NetworkBufferDescriptor_t * pxNewBuffer; + + /* This function is only used when 'ipconfigZERO_COPY_TX_DRIVER' is set to 1. + The transmit routine wants to have ownership of the network buffer + descriptor, because it will pass the buffer straight to DMA. */ + pxNewBuffer = pxGetNetworkBufferWithDescriptor( uxNewLength, ( TickType_t ) 0 ); + + if( pxNewBuffer != NULL ) + { + /* Set the actual packet size in case a bigger buffer than requested + was returned. */ + pxNewBuffer->xDataLength = uxNewLength; + + /* Copy the original packet information. */ + pxNewBuffer->ulIPAddress = pxNetworkBuffer->ulIPAddress; + pxNewBuffer->usPort = pxNetworkBuffer->usPort; + pxNewBuffer->usBoundPort = pxNetworkBuffer->usBoundPort; + memcpy( pxNewBuffer->pucEthernetBuffer, pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer->xDataLength ); + } + + return pxNewBuffer; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) || ( ipconfigZERO_COPY_RX_DRIVER != 0 ) + + NetworkBufferDescriptor_t *pxPacketBuffer_to_NetworkBuffer( const void *pvBuffer ) + { + uint8_t *pucBuffer; + NetworkBufferDescriptor_t *pxResult; + + if( pvBuffer == NULL ) + { + pxResult = NULL; + } + else + { + /* Obtain the network buffer from the zero copy pointer. */ + pucBuffer = ( uint8_t * ) pvBuffer; + + /* The input here is a pointer to a payload buffer. Subtract the + size of the header in the network buffer, usually 8 + 2 bytes. */ + pucBuffer -= ipBUFFER_PADDING; + + /* Here a pointer was placed to the network descriptor. As a + pointer is dereferenced, make sure it is well aligned. */ + if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - ( size_t ) 1 ) ) == ( uint32_t ) 0 ) + { + pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer ); + } + else + { + pxResult = NULL; + } + } + + return pxResult; + } + +#endif /* ipconfigZERO_COPY_TX_DRIVER != 0 */ +/*-----------------------------------------------------------*/ + +NetworkBufferDescriptor_t *pxUDPPayloadBuffer_to_NetworkBuffer( void *pvBuffer ) +{ +uint8_t *pucBuffer; +NetworkBufferDescriptor_t *pxResult; + + if( pvBuffer == NULL ) + { + pxResult = NULL; + } + else + { + /* Obtain the network buffer from the zero copy pointer. */ + pucBuffer = ( uint8_t * ) pvBuffer; + + /* The input here is a pointer to a payload buffer. Subtract + the total size of a UDP/IP header plus the size of the header in + the network buffer, usually 8 + 2 bytes. */ + pucBuffer -= ( sizeof( UDPPacket_t ) + ipBUFFER_PADDING ); + + /* Here a pointer was placed to the network descriptor, + As a pointer is dereferenced, make sure it is well aligned */ + if( ( ( ( uint32_t ) pucBuffer ) & ( sizeof( pucBuffer ) - 1 ) ) == 0 ) + { + /* The following statement may trigger a: + warning: cast increases required alignment of target type [-Wcast-align]. + It has been confirmed though that the alignment is suitable. */ + pxResult = * ( ( NetworkBufferDescriptor_t ** ) pucBuffer ); + } + else + { + pxResult = NULL; + } + } + + return pxResult; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_ReleaseUDPPayloadBuffer( void *pvBuffer ) +{ + vReleaseNetworkBufferAndDescriptor( pxUDPPayloadBuffer_to_NetworkBuffer( pvBuffer ) ); +} +/*-----------------------------------------------------------*/ + +/*_RB_ Should we add an error or assert if the task priorities are set such that the servers won't function as expected? */ +/*_HT_ There was a bug in FreeRTOS_TCP_IP.c that only occurred when the applications' priority was too high. + As that bug has been repaired, there is not an urgent reason to warn. + It is better though to use the advised priority scheme. */ +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 ] ) +{ +BaseType_t xReturn = pdFALSE; + + /* This function should only be called once. */ + configASSERT( xIPIsNetworkTaskReady() == pdFALSE ); + configASSERT( xNetworkEventQueue == NULL ); + configASSERT( xIPTaskHandle == NULL ); + + /* Check structure packing is correct. */ + configASSERT( sizeof( EthernetHeader_t ) == ipEXPECTED_EthernetHeader_t_SIZE ); + configASSERT( sizeof( ARPHeader_t ) == ipEXPECTED_ARPHeader_t_SIZE ); + configASSERT( sizeof( IPHeader_t ) == ipEXPECTED_IPHeader_t_SIZE ); + configASSERT( sizeof( ICMPHeader_t ) == ipEXPECTED_ICMPHeader_t_SIZE ); + configASSERT( sizeof( UDPHeader_t ) == ipEXPECTED_UDPHeader_t_SIZE ); + + /* Attempt to create the queue used to communicate with the IP task. */ + xNetworkEventQueue = xQueueCreate( ( UBaseType_t ) ipconfigEVENT_QUEUE_LENGTH, ( UBaseType_t ) sizeof( IPStackEvent_t ) ); + configASSERT( xNetworkEventQueue ); + + if( xNetworkEventQueue != NULL ) + { + #if ( configQUEUE_REGISTRY_SIZE > 0 ) + { + /* A queue registry is normally used to assist a kernel aware + debugger. If one is in use then it will be helpful for the debugger + to show information about the network event queue. */ + vQueueAddToRegistry( xNetworkEventQueue, "NetEvnt" ); + } + #endif /* configQUEUE_REGISTRY_SIZE */ + + if( xNetworkBuffersInitialise() == pdPASS ) + { + /* Store the local IP and MAC address. */ + xNetworkAddressing.ulDefaultIPAddress = FreeRTOS_inet_addr_quick( ucIPAddress[ 0 ], ucIPAddress[ 1 ], ucIPAddress[ 2 ], ucIPAddress[ 3 ] ); + xNetworkAddressing.ulNetMask = FreeRTOS_inet_addr_quick( ucNetMask[ 0 ], ucNetMask[ 1 ], ucNetMask[ 2 ], ucNetMask[ 3 ] ); + xNetworkAddressing.ulGatewayAddress = FreeRTOS_inet_addr_quick( ucGatewayAddress[ 0 ], ucGatewayAddress[ 1 ], ucGatewayAddress[ 2 ], ucGatewayAddress[ 3 ] ); + xNetworkAddressing.ulDNSServerAddress = FreeRTOS_inet_addr_quick( ucDNSServerAddress[ 0 ], ucDNSServerAddress[ 1 ], ucDNSServerAddress[ 2 ], ucDNSServerAddress[ 3 ] ); + xNetworkAddressing.ulBroadcastAddress = ( xNetworkAddressing.ulDefaultIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask; + + memcpy( &xDefaultAddressing, &xNetworkAddressing, sizeof( xDefaultAddressing ) ); + + #if ipconfigUSE_DHCP == 1 + { + /* The IP address is not set until DHCP completes. */ + *ipLOCAL_IP_ADDRESS_POINTER = 0x00UL; + } + #else + { + /* The IP address is set from the value passed in. */ + *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress; + + /* Added to prevent ARP flood to gateway. Ensure the + gateway is on the same subnet as the IP address. */ + if( xNetworkAddressing.ulGatewayAddress != 0ul ) + { + configASSERT( ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) == ( xNetworkAddressing.ulGatewayAddress & xNetworkAddressing.ulNetMask ) ); + } + } + #endif /* ipconfigUSE_DHCP == 1 */ + + /* The MAC address is stored in the start of the default packet + header fragment, which is used when sending UDP packets. */ + memcpy( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) ucMACAddress, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + + /* Prepare the sockets interface. */ + xReturn = vNetworkSocketsInit(); + + if( pdTRUE == xReturn ) + { + /* Create the task that processes Ethernet and stack events. */ + xReturn = xTaskCreate( prvIPTask, "IP-task", ( uint16_t )ipconfigIP_TASK_STACK_SIZE_WORDS, NULL, ( UBaseType_t )ipconfigIP_TASK_PRIORITY, &xIPTaskHandle ); + } + } + else + { + FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: xNetworkBuffersInitialise() failed\n") ); + + /* Clean up. */ + vQueueDelete( xNetworkEventQueue ); + xNetworkEventQueue = NULL; + } + } + else + { + FreeRTOS_debug_printf( ( "FreeRTOS_IPInit: Network event queue could not be created\n") ); + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_GetAddressConfiguration( uint32_t *pulIPAddress, uint32_t *pulNetMask, uint32_t *pulGatewayAddress, uint32_t *pulDNSServerAddress ) +{ + /* Return the address configuration to the caller. */ + + if( pulIPAddress != NULL ) + { + *pulIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + } + + if( pulNetMask != NULL ) + { + *pulNetMask = xNetworkAddressing.ulNetMask; + } + + if( pulGatewayAddress != NULL ) + { + *pulGatewayAddress = xNetworkAddressing.ulGatewayAddress; + } + + if( pulDNSServerAddress != NULL ) + { + *pulDNSServerAddress = xNetworkAddressing.ulDNSServerAddress; + } +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetAddressConfiguration( const uint32_t *pulIPAddress, const uint32_t *pulNetMask, const uint32_t *pulGatewayAddress, const uint32_t *pulDNSServerAddress ) +{ + /* Update the address configuration. */ + + if( pulIPAddress != NULL ) + { + *ipLOCAL_IP_ADDRESS_POINTER = *pulIPAddress; + } + + if( pulNetMask != NULL ) + { + xNetworkAddressing.ulNetMask = *pulNetMask; + } + + if( pulGatewayAddress != NULL ) + { + xNetworkAddressing.ulGatewayAddress = *pulGatewayAddress; + } + + if( pulDNSServerAddress != NULL ) + { + xNetworkAddressing.ulDNSServerAddress = *pulDNSServerAddress; + } +} +/*-----------------------------------------------------------*/ + +#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + BaseType_t FreeRTOS_SendPingRequest( uint32_t ulIPAddress, size_t xNumberOfBytesToSend, TickType_t xBlockTimeTicks ) + { + NetworkBufferDescriptor_t *pxNetworkBuffer; + ICMPHeader_t *pxICMPHeader; + BaseType_t xReturn = pdFAIL; + static uint16_t usSequenceNumber = 0; + uint8_t *pucChar; + IPStackEvent_t xStackTxEvent = { eStackTxEvent, NULL }; + + if( (xNumberOfBytesToSend >= 1 ) && ( xNumberOfBytesToSend < ( ( ipconfigNETWORK_MTU - sizeof( IPHeader_t ) ) - sizeof( ICMPHeader_t ) ) ) && ( uxGetNumberOfFreeNetworkBuffers() >= 3 ) ) + { + pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( xNumberOfBytesToSend + sizeof( ICMPPacket_t ), xBlockTimeTicks ); + + if( pxNetworkBuffer != NULL ) + { + pxICMPHeader = ( ICMPHeader_t * ) &( pxNetworkBuffer->pucEthernetBuffer[ ipIP_PAYLOAD_OFFSET ] ); + usSequenceNumber++; + + /* Fill in the basic header information. */ + pxICMPHeader->ucTypeOfMessage = ipICMP_ECHO_REQUEST; + pxICMPHeader->ucTypeOfService = 0; + pxICMPHeader->usIdentifier = usSequenceNumber; + pxICMPHeader->usSequenceNumber = usSequenceNumber; + + /* Find the start of the data. */ + pucChar = ( uint8_t * ) pxICMPHeader; + pucChar += sizeof( ICMPHeader_t ); + + /* Just memset the data to a fixed value. */ + memset( ( void * ) pucChar, ( int ) ipECHO_DATA_FILL_BYTE, xNumberOfBytesToSend ); + + /* The message is complete, IP and checksum's are handled by + vProcessGeneratedUDPPacket */ + pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ] = FREERTOS_SO_UDPCKSUM_OUT; + pxNetworkBuffer->ulIPAddress = ulIPAddress; + pxNetworkBuffer->usPort = ipPACKET_CONTAINS_ICMP_DATA; + /* xDataLength is the size of the total packet, including the Ethernet header. */ + pxNetworkBuffer->xDataLength = xNumberOfBytesToSend + sizeof( ICMPPacket_t ); + + /* Send to the stack. */ + xStackTxEvent.pvData = pxNetworkBuffer; + + if( xSendEventStructToIPTask( &xStackTxEvent, xBlockTimeTicks) != pdPASS ) + { + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + iptraceSTACK_TX_EVENT_LOST( ipSTACK_TX_EVENT ); + } + else + { + xReturn = usSequenceNumber; + } + } + } + else + { + /* The requested number of bytes will not fit in the available space + in the network buffer. */ + } + + return xReturn; + } + +#endif /* ipconfigSUPPORT_OUTGOING_PINGS == 1 */ +/*-----------------------------------------------------------*/ + +BaseType_t xSendEventToIPTask( eIPEvent_t eEvent ) +{ +IPStackEvent_t xEventMessage; +const TickType_t xDontBlock = ( TickType_t ) 0; + + xEventMessage.eEventType = eEvent; + xEventMessage.pvData = ( void* )NULL; + + return xSendEventStructToIPTask( &xEventMessage, xDontBlock ); +} +/*-----------------------------------------------------------*/ + +BaseType_t xSendEventStructToIPTask( const IPStackEvent_t *pxEvent, TickType_t xTimeout ) +{ +BaseType_t xReturn, xSendMessage; + + if( ( xIPIsNetworkTaskReady() == pdFALSE ) && ( pxEvent->eEventType != eNetworkDownEvent ) ) + { + /* Only allow eNetworkDownEvent events if the IP task is not ready + yet. Not going to attempt to send the message so the send failed. */ + xReturn = pdFAIL; + } + else + { + xSendMessage = pdTRUE; + + #if( ipconfigUSE_TCP == 1 ) + { + if( pxEvent->eEventType == eTCPTimerEvent ) + { + /* TCP timer events are sent to wake the timer task when + xTCPTimer has expired, but there is no point sending them if the + IP task is already awake processing other message. */ + xTCPTimer.bExpired = pdTRUE_UNSIGNED; + + if( uxQueueMessagesWaiting( xNetworkEventQueue ) != 0u ) + { + /* Not actually going to send the message but this is not a + failure as the message didn't need to be sent. */ + xSendMessage = pdFALSE; + } + } + } + #endif /* ipconfigUSE_TCP */ + + if( xSendMessage != pdFALSE ) + { + /* The IP task cannot block itself while waiting for itself to + respond. */ + if( ( xIsCallingFromIPTask() == pdTRUE ) && ( xTimeout > ( TickType_t ) 0 ) ) + { + xTimeout = ( TickType_t ) 0; + } + + xReturn = xQueueSendToBack( xNetworkEventQueue, pxEvent, xTimeout ); + + if( xReturn == pdFAIL ) + { + /* A message should have been sent to the IP task, but wasn't. */ + FreeRTOS_debug_printf( ( "xSendEventStructToIPTask: CAN NOT ADD %d\n", pxEvent->eEventType ) ); + iptraceSTACK_TX_EVENT_LOST( pxEvent->eEventType ); + } + } + else + { + /* It was not necessary to send the message to process the event so + even though the message was not sent the call was successful. */ + xReturn = pdPASS; + } + } + + return xReturn; +} +/*-----------------------------------------------------------*/ + +eFrameProcessingResult_t eConsiderFrameForProcessing( const uint8_t * const pucEthernetBuffer ) +{ +eFrameProcessingResult_t eReturn; +const EthernetHeader_t *pxEthernetHeader; + + pxEthernetHeader = ( const EthernetHeader_t * ) pucEthernetBuffer; + + if( memcmp( ( void * ) ipLOCAL_MAC_ADDRESS, ( void * ) &( pxEthernetHeader->xDestinationAddress ), sizeof( MACAddress_t ) ) == 0 ) + { + /* The packet was directed to this node directly - process it. */ + eReturn = eProcessBuffer; + } + else if( memcmp( ( void * ) xBroadcastMACAddress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 ) + { + /* The packet was a broadcast - process it. */ + eReturn = eProcessBuffer; + } + else +#if( ipconfigUSE_LLMNR == 1 ) + if( memcmp( ( void * ) xLLMNR_MacAdress.ucBytes, ( void * ) pxEthernetHeader->xDestinationAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 ) + { + /* The packet is a request for LLMNR - process it. */ + eReturn = eProcessBuffer; + } + else +#endif /* ipconfigUSE_LLMNR */ + { + /* The packet was not a broadcast, or for this node, just release + the buffer without taking any other action. */ + eReturn = eReleaseBuffer; + } + + #if( ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 ) + { + uint16_t usFrameType; + + if( eReturn == eProcessBuffer ) + { + usFrameType = pxEthernetHeader->usFrameType; + usFrameType = FreeRTOS_ntohs( usFrameType ); + + if( usFrameType <= 0x600U ) + { + /* Not an Ethernet II frame. */ + eReturn = eReleaseBuffer; + } + } + } + #endif /* ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES == 1 */ + + return eReturn; +} +/*-----------------------------------------------------------*/ + +static void prvProcessNetworkDownEvent( void ) +{ + /* Stop the ARP timer while there is no network. */ + xARPTimer.bActive = pdFALSE_UNSIGNED; + + #if ipconfigUSE_NETWORK_EVENT_HOOK == 1 + { + static BaseType_t xCallEventHook = pdFALSE; + + /* The first network down event is generated by the IP stack itself to + initialise the network hardware, so do not call the network down event + the first time through. */ + if( xCallEventHook == pdTRUE ) + { + vApplicationIPNetworkEventHook( eNetworkDown ); + } + xCallEventHook = pdTRUE; + } + #endif + + /* Per the ARP Cache Validation section of https://tools.ietf.org/html/rfc1122, + treat network down as a "delivery problem" and flush the ARP cache for this + interface. */ + FreeRTOS_ClearARP( ); + + /* The network has been disconnected (or is being initialised for the first + time). Perform whatever hardware processing is necessary to bring it up + again, or wait for it to be available again. This is hardware dependent. */ + if( xNetworkInterfaceInitialise() != pdPASS ) + { + /* Ideally the network interface initialisation function will only + return when the network is available. In case this is not the case, + wait a while before retrying the initialisation. */ + vTaskDelay( ipINITIALISATION_RETRY_DELAY ); + FreeRTOS_NetworkDown(); + } + else + { + /* Set remaining time to 0 so it will become active immediately. */ + #if ipconfigUSE_DHCP == 1 + { + /* The network is not up until DHCP has completed. */ + vDHCPProcess( pdTRUE ); + xSendEventToIPTask( eDHCPEvent ); + } + #else + { + /* Perform any necessary 'network up' processing. */ + vIPNetworkUpCalls(); + } + #endif + } +} +/*-----------------------------------------------------------*/ + +void vIPNetworkUpCalls( void ) +{ + xNetworkUp = pdTRUE; + + #if( ipconfigUSE_NETWORK_EVENT_HOOK == 1 ) + { + vApplicationIPNetworkEventHook( eNetworkUp ); + } + #endif /* ipconfigUSE_NETWORK_EVENT_HOOK */ + + #if( ipconfigDNS_USE_CALLBACKS != 0 ) + { + /* The following function is declared in FreeRTOS_DNS.c and 'private' to + this library */ + extern void vDNSInitialise( void ); + vDNSInitialise(); + } + #endif /* ipconfigDNS_USE_CALLBACKS != 0 */ + + /* Set remaining time to 0 so it will become active immediately. */ + prvIPTimerReload( &xARPTimer, pdMS_TO_TICKS( ipARP_TIMER_PERIOD_MS ) ); +} +/*-----------------------------------------------------------*/ + +static void prvProcessEthernetPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +EthernetHeader_t *pxEthernetHeader; +eFrameProcessingResult_t eReturned = eReleaseBuffer; + + configASSERT( pxNetworkBuffer ); + + /* Interpret the Ethernet frame. */ + if( pxNetworkBuffer->xDataLength >= sizeof( EthernetHeader_t ) ) + { + eReturned = ipCONSIDER_FRAME_FOR_PROCESSING( pxNetworkBuffer->pucEthernetBuffer ); + pxEthernetHeader = ( EthernetHeader_t * )( pxNetworkBuffer->pucEthernetBuffer ); + + if( eReturned == eProcessBuffer ) + { + /* Interpret the received Ethernet packet. */ + switch( pxEthernetHeader->usFrameType ) + { + case ipARP_FRAME_TYPE: + /* The Ethernet frame contains an ARP packet. */ + if( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) ) + { + eReturned = eARPProcessPacket( ( ARPPacket_t * )pxNetworkBuffer->pucEthernetBuffer ); + } + else + { + eReturned = eReleaseBuffer; + } + break; + + case ipIPv4_FRAME_TYPE: + /* The Ethernet frame contains an IP packet. */ + if( pxNetworkBuffer->xDataLength >= sizeof( IPPacket_t ) ) + { + eReturned = prvProcessIPPacket( ( IPPacket_t * )pxNetworkBuffer->pucEthernetBuffer, pxNetworkBuffer ); + } + else + { + eReturned = eReleaseBuffer; + } + break; + + default: + /* No other packet types are handled. Nothing to do. */ + eReturned = eReleaseBuffer; + break; + } + } + } + + /* Perform any actions that resulted from processing the Ethernet frame. */ + switch( eReturned ) + { + case eReturnEthernetFrame : + /* The Ethernet frame will have been updated (maybe it was + an ARP request or a PING request?) and should be sent back to + its source. */ + vReturnEthernetFrame( pxNetworkBuffer, pdTRUE ); + /* parameter pdTRUE: the buffer must be released once + the frame has been transmitted */ + break; + + case eFrameConsumed : + /* The frame is in use somewhere, don't release the buffer + yet. */ + break; + + default : + /* The frame is not being used anywhere, and the + NetworkBufferDescriptor_t structure containing the frame should + just be released back to the list of free buffers. */ + vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ); + break; + } +} +/*-----------------------------------------------------------*/ + +static eFrameProcessingResult_t prvAllowIPPacket( const IPPacket_t * const pxIPPacket, + NetworkBufferDescriptor_t * const pxNetworkBuffer, UBaseType_t uxHeaderLength ) +{ +eFrameProcessingResult_t eReturn = eProcessBuffer; + +#if( ( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) || ( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) ) + const IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); +#else + /* or else, the parameter won't be used and the function will be optimised + away */ + ( void ) pxIPPacket; +#endif + + #if( ipconfigETHERNET_DRIVER_FILTERS_PACKETS == 0 ) + { + /* In systems with a very small amount of RAM, it might be advantageous + to have incoming messages checked earlier, by the network card driver. + This method may decrease the usage of sparse network buffers. */ + uint32_t ulDestinationIPAddress = pxIPHeader->ulDestinationIPAddress; + + /* Ensure that the incoming packet is not fragmented (only outgoing + packets can be fragmented) as these are the only handled IP frames + currently. */ + if( ( pxIPHeader->usFragmentOffset & ipFRAGMENT_OFFSET_BIT_MASK ) != 0U ) + { + /* Can not handle, fragmented packet. */ + eReturn = eReleaseBuffer; + } + /* 0x45 means: IPv4 with an IP header of 5 x 4 = 20 bytes + * 0x47 means: IPv4 with an IP header of 7 x 4 = 28 bytes */ + else if( ( pxIPHeader->ucVersionHeaderLength < 0x45u ) || ( pxIPHeader->ucVersionHeaderLength > 0x4Fu ) ) + { + /* Can not handle, unknown or invalid header version. */ + eReturn = eReleaseBuffer; + } + /* Is the packet for this IP address? */ + else if( ( ulDestinationIPAddress != *ipLOCAL_IP_ADDRESS_POINTER ) && + /* Is it the global broadcast address 255.255.255.255 ? */ + ( ulDestinationIPAddress != ipBROADCAST_IP_ADDRESS ) && + /* Is it a specific broadcast address 192.168.1.255 ? */ + ( ulDestinationIPAddress != xNetworkAddressing.ulBroadcastAddress ) && + #if( ipconfigUSE_LLMNR == 1 ) + /* Is it the LLMNR multicast address? */ + ( ulDestinationIPAddress != ipLLMNR_IP_ADDR ) && + #endif + /* Or (during DHCP negotiation) we have no IP-address yet? */ + ( *ipLOCAL_IP_ADDRESS_POINTER != 0UL ) ) + { + /* Packet is not for this node, release it */ + eReturn = eReleaseBuffer; + } + } + #endif /* ipconfigETHERNET_DRIVER_FILTERS_PACKETS */ + + #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 ) + { + /* Some drivers of NIC's with checksum-offloading will enable the above + define, so that the checksum won't be checked again here */ + if (eReturn == eProcessBuffer ) + { + /* Is the IP header checksum correct? */ + if( ( pxIPHeader->ucProtocol != ( uint8_t ) ipPROTOCOL_ICMP ) && + ( usGenerateChecksum( 0UL, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ( size_t ) uxHeaderLength ) != ipCORRECT_CRC ) ) + { + /* Check sum in IP-header not correct. */ + eReturn = eReleaseBuffer; + } + /* Is the upper-layer checksum (TCP/UDP/ICMP) correct? */ + else if( usGenerateProtocolChecksum( ( uint8_t * )( pxNetworkBuffer->pucEthernetBuffer ), pxNetworkBuffer->xDataLength, pdFALSE ) != ipCORRECT_CRC ) + { + /* Protocol checksum not accepted. */ + eReturn = eReleaseBuffer; + } + } + } + #else + { + /* to avoid warning unused parameters */ + ( void ) pxNetworkBuffer; + ( void ) uxHeaderLength; + } + #endif /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM == 0 */ + + return eReturn; +} +/*-----------------------------------------------------------*/ + +static eFrameProcessingResult_t prvProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ) +{ +eFrameProcessingResult_t eReturn; +IPHeader_t * pxIPHeader = &( pxIPPacket->xIPHeader ); +UBaseType_t uxHeaderLength = ( UBaseType_t ) ( ( pxIPHeader->ucVersionHeaderLength & 0x0Fu ) << 2 ); +uint8_t ucProtocol; + + /* Bound the calculated header length: take away the Ethernet header size, + then check if the IP header is claiming to be longer than the remaining + total packet size. Also check for minimal header field length. */ + if( ( uxHeaderLength > ( pxNetworkBuffer->xDataLength - ipSIZE_OF_ETH_HEADER ) ) || + ( uxHeaderLength < ipSIZE_OF_IPv4_HEADER ) ) + { + return eReleaseBuffer; + } + + ucProtocol = pxIPPacket->xIPHeader.ucProtocol; + /* Check if the IP headers are acceptable and if it has our destination. */ + eReturn = prvAllowIPPacket( pxIPPacket, pxNetworkBuffer, uxHeaderLength ); + + if( eReturn == eProcessBuffer ) + { + if( uxHeaderLength > ipSIZE_OF_IPv4_HEADER ) + { + /* All structs of headers expect a IP header size of 20 bytes + * IP header options were included, we'll ignore them and cut them out + * Note: IP options are mostly use in Multi-cast protocols */ + const size_t optlen = ( ( size_t ) uxHeaderLength ) - ipSIZE_OF_IPv4_HEADER; + /* From: the previous start of UDP/ICMP/TCP data */ + uint8_t *pucSource = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + uxHeaderLength); + /* To: the usual start of UDP/ICMP/TCP data at offset 20 from IP header */ + uint8_t *pucTarget = ( uint8_t* )(pxNetworkBuffer->pucEthernetBuffer + sizeof( EthernetHeader_t ) + ipSIZE_OF_IPv4_HEADER); + /* How many: total length minus the options and the lower headers */ + const size_t xMoveLen = pxNetworkBuffer->xDataLength - optlen - ipSIZE_OF_IPv4_HEADER - ipSIZE_OF_ETH_HEADER; + + memmove( pucTarget, pucSource, xMoveLen ); + pxNetworkBuffer->xDataLength -= optlen; + + /* Fix-up new version/header length field in IP packet. */ + pxIPHeader->ucVersionHeaderLength = ( pxIPHeader->ucVersionHeaderLength & 0xF0 ) | /* High nibble is the version. */ + ( ( ipSIZE_OF_IPv4_HEADER >> 2 ) & 0x0F ); /* Low nibble is the header size, in bytes, divided by four. */ + } + + /* Add the IP and MAC addresses to the ARP table if they are not + already there - otherwise refresh the age of the existing + entry. */ + if( ucProtocol != ( uint8_t ) ipPROTOCOL_UDP ) + { + /* Refresh the ARP cache with the IP/MAC-address of the received packet + * For UDP packets, this will be done later in xProcessReceivedUDPPacket() + * as soon as know that the message will be handled by someone + * This will prevent that the ARP cache will get overwritten + * with the IP-address of useless broadcast packets + */ + vARPRefreshCacheEntry( &( pxIPPacket->xEthernetHeader.xSourceAddress ), pxIPHeader->ulSourceIPAddress ); + } + switch( ucProtocol ) + { + case ipPROTOCOL_ICMP : + /* The IP packet contained an ICMP frame. Don't bother + checking the ICMP checksum, as if it is wrong then the + wrong data will also be returned, and the source of the + ping will know something went wrong because it will not + be able to validate what it receives. */ + #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + { + if( pxNetworkBuffer->xDataLength >= sizeof( ICMPPacket_t ) ) + { + ICMPPacket_t *pxICMPPacket = ( ICMPPacket_t * )( pxNetworkBuffer->pucEthernetBuffer ); + if( pxIPHeader->ulDestinationIPAddress == *ipLOCAL_IP_ADDRESS_POINTER ) + { + eReturn = prvProcessICMPPacket( pxICMPPacket ); + } + } + else + { + eReturn = eReleaseBuffer; + } + } + #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ + break; + + case ipPROTOCOL_UDP : + { + /* The IP packet contained a UDP frame. */ + UDPPacket_t *pxUDPPacket = ( UDPPacket_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + + /* Only proceed if the payload length indicated in the header + appears to be valid. */ + if ( ( pxNetworkBuffer->xDataLength >= sizeof( UDPPacket_t ) ) && ( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) >= sizeof( UDPHeader_t ) ) ) + { + size_t uxPayloadSize_1, uxPayloadSize_2; + /* The UDP payload size can be calculated by subtracting the + * header size from `xDataLength`. + * However, the `xDataLength` may be longer that expected, + * e.g. when a small packet is padded with zero's. + * The UDP header contains a field `usLength` reflecting + * the payload size plus the UDP header ( 8 bytes ). + * Set `xDataLength` to the size of the headers, + * plus the lower of the two calculated payload sizes. + */ + + uxPayloadSize_1 = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t ); + uxPayloadSize_2 = FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usLength ) - sizeof( UDPHeader_t ); + if( uxPayloadSize_1 > uxPayloadSize_2 ) + { + pxNetworkBuffer->xDataLength = uxPayloadSize_2 + sizeof( UDPPacket_t ); + } + + /* Fields in pxNetworkBuffer (usPort, ulIPAddress) are network order. */ + pxNetworkBuffer->usPort = pxUDPPacket->xUDPHeader.usSourcePort; + pxNetworkBuffer->ulIPAddress = pxUDPPacket->xIPHeader.ulSourceIPAddress; + + /* ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM: + * In some cases, the upper-layer checksum has been calculated + * by the NIC driver. + * + * Pass the packet payload to the UDP sockets implementation. */ + if( xProcessReceivedUDPPacket( pxNetworkBuffer, + pxUDPPacket->xUDPHeader.usDestinationPort ) == pdPASS ) + { + eReturn = eFrameConsumed; + } + } + else + { + eReturn = eReleaseBuffer; + } + } + break; + +#if ipconfigUSE_TCP == 1 + case ipPROTOCOL_TCP : + { + + if( xProcessReceivedTCPPacket( pxNetworkBuffer ) == pdPASS ) + { + eReturn = eFrameConsumed; + } + + /* Setting this variable will cause xTCPTimerCheck() + to be called just before the IP-task blocks. */ + xProcessedTCPMessage++; + } + break; +#endif + default : + /* Not a supported frame type. */ + break; + } + } + + return eReturn; +} +/*-----------------------------------------------------------*/ + +#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + static void prvProcessICMPEchoReply( ICMPPacket_t * const pxICMPPacket ) + { + ePingReplyStatus_t eStatus = eSuccess; + uint16_t usDataLength, usCount; + uint8_t *pucByte; + + /* Find the total length of the IP packet. */ + usDataLength = pxICMPPacket->xIPHeader.usLength; + usDataLength = FreeRTOS_ntohs( usDataLength ); + + /* Remove the length of the IP headers to obtain the length of the ICMP + message itself. */ + usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_IPv4_HEADER ); + + /* Remove the length of the ICMP header, to obtain the length of + data contained in the ping. */ + usDataLength = ( uint16_t ) ( ( ( uint32_t ) usDataLength ) - ipSIZE_OF_ICMP_HEADER ); + + /* Checksum has already been checked before in prvProcessIPPacket */ + + /* Find the first byte of the data within the ICMP packet. */ + pucByte = ( uint8_t * ) pxICMPPacket; + pucByte += sizeof( ICMPPacket_t ); + + /* Check each byte. */ + for( usCount = 0; usCount < usDataLength; usCount++ ) + { + if( *pucByte != ipECHO_DATA_FILL_BYTE ) + { + eStatus = eInvalidData; + break; + } + + pucByte++; + } + + /* Call back into the application to pass it the result. */ + vApplicationPingReplyHook( eStatus, pxICMPPacket->xICMPHeader.usIdentifier ); + } + +#endif +/*-----------------------------------------------------------*/ + +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) + + static eFrameProcessingResult_t prvProcessICMPEchoRequest( ICMPPacket_t * const pxICMPPacket ) + { + ICMPHeader_t *pxICMPHeader; + IPHeader_t *pxIPHeader; + uint16_t usRequest; + + pxICMPHeader = &( pxICMPPacket->xICMPHeader ); + pxIPHeader = &( pxICMPPacket->xIPHeader ); + + /* HT:endian: changed back */ + iptraceSENDING_PING_REPLY( pxIPHeader->ulSourceIPAddress ); + + /* The checksum can be checked here - but a ping reply should be + returned even if the checksum is incorrect so the other end can + tell that the ping was received - even if the ping reply contains + invalid data. */ + pxICMPHeader->ucTypeOfMessage = ( uint8_t ) ipICMP_ECHO_REPLY; + pxIPHeader->ulDestinationIPAddress = pxIPHeader->ulSourceIPAddress; + pxIPHeader->ulSourceIPAddress = *ipLOCAL_IP_ADDRESS_POINTER; + + /* Update the checksum because the ucTypeOfMessage member in the header + has been changed to ipICMP_ECHO_REPLY. This is faster than calling + usGenerateChecksum(). */ + + /* due to compiler warning "integer operation result is out of range" */ + + usRequest = ( uint16_t ) ( ( uint16_t )ipICMP_ECHO_REQUEST << 8 ); + + if( pxICMPHeader->usChecksum >= FreeRTOS_htons( 0xFFFFu - usRequest ) ) + { + pxICMPHeader->usChecksum = ( uint16_t ) + ( ( ( uint32_t ) pxICMPHeader->usChecksum ) + + FreeRTOS_htons( usRequest + 1UL ) ); + } + else + { + pxICMPHeader->usChecksum = ( uint16_t ) + ( ( ( uint32_t ) pxICMPHeader->usChecksum ) + + FreeRTOS_htons( usRequest ) ); + } + return eReturnEthernetFrame; + } + +#endif /* ipconfigREPLY_TO_INCOMING_PINGS == 1 */ +/*-----------------------------------------------------------*/ + +#if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + + static eFrameProcessingResult_t prvProcessICMPPacket( ICMPPacket_t * const pxICMPPacket ) + { + eFrameProcessingResult_t eReturn = eReleaseBuffer; + + iptraceICMP_PACKET_RECEIVED(); + switch( pxICMPPacket->xICMPHeader.ucTypeOfMessage ) + { + case ipICMP_ECHO_REQUEST : + #if ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) + { + eReturn = prvProcessICMPEchoRequest( pxICMPPacket ); + } + #endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) */ + break; + + case ipICMP_ECHO_REPLY : + #if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) + { + prvProcessICMPEchoReply( pxICMPPacket ); + } + #endif /* ipconfigSUPPORT_OUTGOING_PINGS */ + break; + + default : + break; + } + + return eReturn; + } + +#endif /* ( ipconfigREPLY_TO_INCOMING_PINGS == 1 ) || ( ipconfigSUPPORT_OUTGOING_PINGS == 1 ) */ +/*-----------------------------------------------------------*/ + +uint16_t usGenerateProtocolChecksum( const uint8_t * const pucEthernetBuffer, size_t uxBufferLength, BaseType_t xOutgoingPacket ) +{ +uint32_t ulLength; +uint16_t usChecksum, *pusChecksum; +const IPPacket_t * pxIPPacket; +UBaseType_t uxIPHeaderLength; +ProtocolPacket_t *pxProtPack; +uint8_t ucProtocol; +#if( ipconfigHAS_DEBUG_PRINTF != 0 ) + const char *pcType; +#endif + + /* Check for minimum packet size. */ + if( uxBufferLength < sizeof( IPPacket_t ) ) + { + return ipINVALID_LENGTH; + } + + /* Parse the packet length. */ + pxIPPacket = ( const IPPacket_t * ) pucEthernetBuffer; + + /* Per https://tools.ietf.org/html/rfc791, the four-bit Internet Header + Length field contains the length of the internet header in 32-bit words. */ + uxIPHeaderLength = ( UBaseType_t ) ( sizeof( uint32_t ) * ( pxIPPacket->xIPHeader.ucVersionHeaderLength & 0x0Fu ) ); + + /* Check for minimum packet size. */ + if( uxBufferLength < sizeof( IPPacket_t ) + uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) + { + return ipINVALID_LENGTH; + } + if( uxBufferLength < ( size_t ) ( ipSIZE_OF_ETH_HEADER + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) ) ) + { + return ipINVALID_LENGTH; + } + + /* Identify the next protocol. */ + ucProtocol = pxIPPacket->xIPHeader.ucProtocol; + + /* N.B., if this IP packet header includes Options, then the following + assignment results in a pointer into the protocol packet with the Ethernet + and IP headers incorrectly aligned. However, either way, the "third" + protocol (Layer 3 or 4) header will be aligned, which is the convenience + of this calculation. */ + pxProtPack = ( ProtocolPacket_t * ) ( pucEthernetBuffer + ( uxIPHeaderLength - ipSIZE_OF_IPv4_HEADER ) ); + + /* Switch on the Layer 3/4 protocol. */ + if( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) + { + if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_UDP_HEADER ) ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xUDPPacket.xUDPHeader.usChecksum ) ); + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + pcType = "UDP"; + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + } + else if( ucProtocol == ( uint8_t ) ipPROTOCOL_TCP ) + { + if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_TCP_HEADER ) ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xTCPPacket.xTCPHeader.usChecksum ) ); + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + pcType = "TCP"; + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + } + else if( ( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) || + ( ucProtocol == ( uint8_t ) ipPROTOCOL_IGMP ) ) + { + if( uxBufferLength < ( uxIPHeaderLength + ipSIZE_OF_ETH_HEADER + ipSIZE_OF_ICMP_HEADER ) ) + { + return ipINVALID_LENGTH; + } + + pusChecksum = ( uint16_t * ) ( &( pxProtPack->xICMPPacket.xICMPHeader.usChecksum ) ); + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) + { + pcType = "ICMP"; + } + else + { + pcType = "IGMP"; + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + } + else + { + /* Unhandled protocol, other than ICMP, IGMP, UDP, or TCP. */ + return ipUNHANDLED_PROTOCOL; + } + + /* The protocol and checksum field have been identified. Check the direction + of the packet. */ + if( xOutgoingPacket != pdFALSE ) + { + /* This is an outgoing packet. Before calculating the checksum, set it + to zero. */ + *( pusChecksum ) = 0u; + } + else if( ( *pusChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) ) + { + /* Sender hasn't set the checksum, no use to calculate it. */ + return ipCORRECT_CRC; + } + + ulLength = ( uint32_t ) + ( FreeRTOS_ntohs( pxIPPacket->xIPHeader.usLength ) - ( ( uint16_t ) uxIPHeaderLength ) ); /* normally minus 20 */ + + if( ( ulLength < sizeof( pxProtPack->xUDPPacket.xUDPHeader ) ) || + ( ulLength > ( uint32_t )( ipconfigNETWORK_MTU - uxIPHeaderLength ) ) ) + { + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: len invalid: %lu\n", pcType, ulLength ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + /* Again, in a 16-bit return value there is no space to indicate an + error. For incoming packets, 0x1234 will cause dropping of the packet. + For outgoing packets, there is a serious problem with the + format/length */ + return ipINVALID_LENGTH; + } + if( ucProtocol <= ( uint8_t ) ipPROTOCOL_IGMP ) + { + /* ICMP/IGMP do not have a pseudo header for CRC-calculation. */ + usChecksum = ( uint16_t ) + ( ~usGenerateChecksum( 0UL, + ( uint8_t * ) &( pxProtPack->xTCPPacket.xTCPHeader ), ( size_t ) ulLength ) ); + } + else + { + /* For UDP and TCP, sum the pseudo header, i.e. IP protocol + length + fields */ + usChecksum = ( uint16_t ) ( ulLength + ( ( uint16_t ) ucProtocol ) ); + + /* And then continue at the IPv4 source and destination addresses. */ + usChecksum = ( uint16_t ) + ( ~usGenerateChecksum( ( uint32_t ) usChecksum, ( uint8_t * )&( pxIPPacket->xIPHeader.ulSourceIPAddress ), + ( 2u * sizeof( pxIPPacket->xIPHeader.ulSourceIPAddress ) + ulLength ) ) ); + + /* Sum TCP header and data. */ + } + + if( xOutgoingPacket == pdFALSE ) + { + /* This is in incoming packet. If the CRC is correct, it should be zero. */ + if( usChecksum == 0u ) + { + usChecksum = ( uint16_t )ipCORRECT_CRC; + } + } + else + { + if( ( usChecksum == 0u ) && ( ucProtocol == ( uint8_t ) ipPROTOCOL_UDP ) ) + { + /* In case of UDP, a calculated checksum of 0x0000 is transmitted + as 0xffff. A value of zero would mean that the checksum is not used. */ + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + { + if( xOutgoingPacket != pdFALSE ) + { + FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: crc swap: %04X\n", pcType, usChecksum ) ); + } + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + usChecksum = ( uint16_t )0xffffu; + } + } + usChecksum = FreeRTOS_htons( usChecksum ); + + if( xOutgoingPacket != pdFALSE ) + { + *( pusChecksum ) = usChecksum; + } + #if( ipconfigHAS_DEBUG_PRINTF != 0 ) + else if( ( xOutgoingPacket == pdFALSE ) && ( usChecksum != ipCORRECT_CRC ) ) + { + FreeRTOS_debug_printf( ( "usGenerateProtocolChecksum[%s]: ID %04X: from %lxip to %lxip bad crc: %04X\n", + pcType, + FreeRTOS_ntohs( pxIPPacket->xIPHeader.usIdentification ), + FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulSourceIPAddress ), + FreeRTOS_ntohl( pxIPPacket->xIPHeader.ulDestinationIPAddress ), + FreeRTOS_ntohs( *pusChecksum ) ) ); + } + #endif /* ipconfigHAS_DEBUG_PRINTF != 0 */ + + return usChecksum; +} +/*-----------------------------------------------------------*/ + +/** + * This method generates a checksum for a given IPv4 header, per RFC791 (page 14). + * The checksum algorithm is decribed as: + * "[T]he 16 bit one's complement of the one's complement sum of all 16 bit words in the + * header. For purposes of computing the checksum, the value of the checksum field is zero." + * + * In a nutshell, that means that each 16-bit 'word' must be summed, after which + * the number of 'carries' (overflows) is added to the result. If that addition + * produces an overflow, that 'carry' must also be added to the final result. The final checksum + * should be the bitwise 'not' (ones-complement) of the result if the packet is + * meant to be transmitted, but this method simply returns the raw value, probably + * because when a packet is received, the checksum is verified by checking that + * ((received & calculated) == 0) without applying a bitwise 'not' to the 'calculated' checksum. + * + * This logic is optimized for microcontrollers which have limited resources, so the logic looks odd. + * It iterates over the full range of 16-bit words, but it does so by processing several 32-bit + * words at once whenever possible. Its first step is to align the memory pointer to a 32-bit boundary, + * after which it runs a fast loop to process multiple 32-bit words at once and adding their 'carries'. + * Finally, it finishes up by processing any remaining 16-bit words, and adding up all of the 'carries'. + * With 32-bit arithmetic, the number of 16-bit 'carries' produced by sequential additions can be found + * by looking at the 16 most-significant bits of the 32-bit integer, since a 32-bit int will continue + * counting up instead of overflowing after 16 bits. That is why the actual checksum calculations look like: + * union.u32 = ( uint32_t ) union.u16[ 0 ] + union.u16[ 1 ]; + * + * Arguments: + * ulSum: This argument provides a value to initialize the progressive summation + * of the header's values to. It is often 0, but protocols like TCP or UDP + * can have pseudo-header fields which need to be included in the checksum. + * pucNextData: This argument contains the address of the first byte which this + * method should process. The method's memory iterator is initialized to this value. + * uxDataLengthBytes: This argument contains the number of bytes that this method + * should process. + */ +uint16_t usGenerateChecksum( uint32_t ulSum, const uint8_t * pucNextData, size_t uxDataLengthBytes ) +{ +xUnion32 xSum2, xSum, xTerm; +xUnionPtr xSource; /* Points to first byte */ +xUnionPtr xLastSource; /* Points to last byte plus one */ +uint32_t ulAlignBits, ulCarry = 0ul; + + /* Small MCUs often spend up to 30% of the time doing checksum calculations + This function is optimised for 32-bit CPUs; Each time it will try to fetch + 32-bits, sums it with an accumulator and counts the number of carries. */ + + /* Swap the input (little endian platform only). */ + xSum.u32 = FreeRTOS_ntohs( ulSum ); + xTerm.u32 = 0ul; + + xSource.u8ptr = ( uint8_t * ) pucNextData; + ulAlignBits = ( ( ( uint32_t ) pucNextData ) & 0x03u ); /* gives 0, 1, 2, or 3 */ + + /* If byte (8-bit) aligned... */ + if( ( ( ulAlignBits & 1ul ) != 0ul ) && ( uxDataLengthBytes >= ( size_t ) 1 ) ) + { + xTerm.u8[ 1 ] = *( xSource.u8ptr ); + ( xSource.u8ptr )++; + uxDataLengthBytes--; + /* Now xSource is word (16-bit) aligned. */ + } + + /* If half-word (16-bit) aligned... */ + if( ( ( ulAlignBits == 1u ) || ( ulAlignBits == 2u ) ) && ( uxDataLengthBytes >= 2u ) ) + { + xSum.u32 += *(xSource.u16ptr); + ( xSource.u16ptr )++; + uxDataLengthBytes -= 2u; + /* Now xSource is word (32-bit) aligned. */ + } + + /* Word (32-bit) aligned, do the most part. */ + xLastSource.u32ptr = ( xSource.u32ptr + ( uxDataLengthBytes / 4u ) ) - 3u; + + /* In this loop, four 32-bit additions will be done, in total 16 bytes. + Indexing with constants (0,1,2,3) gives faster code than using + post-increments. */ + while( xSource.u32ptr < xLastSource.u32ptr ) + { + /* Use a secondary Sum2, just to see if the addition produced an + overflow. */ + xSum2.u32 = xSum.u32 + xSource.u32ptr[ 0 ]; + if( xSum2.u32 < xSum.u32 ) + { + ulCarry++; + } + + /* Now add the secondary sum to the major sum, and remember if there was + a carry. */ + xSum.u32 = xSum2.u32 + xSource.u32ptr[ 1 ]; + if( xSum2.u32 > xSum.u32 ) + { + ulCarry++; + } + + /* And do the same trick once again for indexes 2 and 3 */ + xSum2.u32 = xSum.u32 + xSource.u32ptr[ 2 ]; + if( xSum2.u32 < xSum.u32 ) + { + ulCarry++; + } + + xSum.u32 = xSum2.u32 + xSource.u32ptr[ 3 ]; + + if( xSum2.u32 > xSum.u32 ) + { + ulCarry++; + } + + /* And finally advance the pointer 4 * 4 = 16 bytes. */ + xSource.u32ptr += 4; + } + + /* Now add all carries. */ + xSum.u32 = ( uint32_t )xSum.u16[ 0 ] + xSum.u16[ 1 ] + ulCarry; + + uxDataLengthBytes %= 16u; + xLastSource.u8ptr = ( uint8_t * ) ( xSource.u8ptr + ( uxDataLengthBytes & ~( ( size_t ) 1 ) ) ); + + /* Half-word aligned. */ + while( xSource.u16ptr < xLastSource.u16ptr ) + { + /* At least one more short. */ + xSum.u32 += xSource.u16ptr[ 0 ]; + xSource.u16ptr++; + } + + if( ( uxDataLengthBytes & ( size_t ) 1 ) != 0u ) /* Maybe one more ? */ + { + xTerm.u8[ 0 ] = xSource.u8ptr[ 0 ]; + } + xSum.u32 += xTerm.u32; + + /* Now add all carries again. */ + xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ]; + + /* The previous summation might have given a 16-bit carry. */ + xSum.u32 = ( uint32_t ) xSum.u16[ 0 ] + xSum.u16[ 1 ]; + + if( ( ulAlignBits & 1u ) != 0u ) + { + /* Quite unlikely, but pucNextData might be non-aligned, which would + mean that a checksum is calculated starting at an odd position. */ + xSum.u32 = ( ( xSum.u32 & 0xffu ) << 8 ) | ( ( xSum.u32 & 0xff00u ) >> 8 ); + } + + /* swap the output (little endian platform only). */ + return FreeRTOS_htons( ( (uint16_t) xSum.u32 ) ); +} +/*-----------------------------------------------------------*/ + +void vReturnEthernetFrame( NetworkBufferDescriptor_t * pxNetworkBuffer, BaseType_t xReleaseAfterSend ) +{ +EthernetHeader_t *pxEthernetHeader; + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + NetworkBufferDescriptor_t *pxNewBuffer; +#endif + + #if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES ) + { + BaseType_t xIndex; + + FreeRTOS_printf( ( "vReturnEthernetFrame: length %lu\n", ( uint32_t )pxNetworkBuffer->xDataLength ) ); + for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ ) + { + pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0u; + } + pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; + } + } + #endif + +#if( ipconfigZERO_COPY_TX_DRIVER != 0 ) + + if( xReleaseAfterSend == pdFALSE ) + { + pxNewBuffer = pxDuplicateNetworkBufferWithDescriptor( pxNetworkBuffer, ( BaseType_t ) pxNetworkBuffer->xDataLength ); + xReleaseAfterSend = pdTRUE; + pxNetworkBuffer = pxNewBuffer; + } + + if( pxNetworkBuffer != NULL ) +#endif + { + pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer ); + + /* Swap source and destination MAC addresses. */ + memcpy( ( void * ) &( pxEthernetHeader->xDestinationAddress ), ( void * ) &( pxEthernetHeader->xSourceAddress ), sizeof( pxEthernetHeader->xDestinationAddress ) ); + memcpy( ( void * ) &( pxEthernetHeader->xSourceAddress) , ( void * ) ipLOCAL_MAC_ADDRESS, ( size_t ) ipMAC_ADDRESS_LENGTH_BYTES ); + + /* Send! */ + xNetworkInterfaceOutput( pxNetworkBuffer, xReleaseAfterSend ); + } +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetIPAddress( void ) +{ + /* Returns the IP address of the NIC. */ + return *ipLOCAL_IP_ADDRESS_POINTER; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetIPAddress( uint32_t ulIPAddress ) +{ + /* Sets the IP address of the NIC. */ + *ipLOCAL_IP_ADDRESS_POINTER = ulIPAddress; +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetGatewayAddress( void ) +{ + return xNetworkAddressing.ulGatewayAddress; +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetDNSServerAddress( void ) +{ + return xNetworkAddressing.ulDNSServerAddress; +} +/*-----------------------------------------------------------*/ + +uint32_t FreeRTOS_GetNetmask( void ) +{ + return xNetworkAddressing.ulNetMask; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_UpdateMACAddress( const uint8_t ucMACAddress[ipMAC_ADDRESS_LENGTH_BYTES] ) +{ + /* Copy the MAC address at the start of the default packet header fragment. */ + memcpy( ( void * )ipLOCAL_MAC_ADDRESS, ( void * )ucMACAddress, ( size_t )ipMAC_ADDRESS_LENGTH_BYTES ); +} +/*-----------------------------------------------------------*/ + +const uint8_t * FreeRTOS_GetMACAddress( void ) +{ + return ipLOCAL_MAC_ADDRESS; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetNetmask ( uint32_t ulNetmask ) +{ + xNetworkAddressing.ulNetMask = ulNetmask; +} +/*-----------------------------------------------------------*/ + +void FreeRTOS_SetGatewayAddress ( uint32_t ulGatewayAddress ) +{ + xNetworkAddressing.ulGatewayAddress = ulGatewayAddress; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DHCP == 1 ) + void vIPSetDHCPTimerEnableState( BaseType_t xEnableState ) + { + if( xEnableState != pdFALSE ) + { + xDHCPTimer.bActive = pdTRUE_UNSIGNED; + } + else + { + xDHCPTimer.bActive = pdFALSE_UNSIGNED; + } + } +#endif /* ipconfigUSE_DHCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigUSE_DHCP == 1 ) + void vIPReloadDHCPTimer( uint32_t ulLeaseTime ) + { + prvIPTimerReload( &xDHCPTimer, ulLeaseTime ); + } +#endif /* ipconfigUSE_DHCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigDNS_USE_CALLBACKS == 1 ) + void vIPSetDnsTimerEnableState( BaseType_t xEnableState ) + { + if( xEnableState != 0 ) + { + xDNSTimer.bActive = pdTRUE; + } + else + { + xDNSTimer.bActive = pdFALSE; + } + } +#endif /* ipconfigUSE_DHCP */ +/*-----------------------------------------------------------*/ + +#if( ipconfigDNS_USE_CALLBACKS != 0 ) + void vIPReloadDNSTimer( uint32_t ulCheckTime ) + { + prvIPTimerReload( &xDNSTimer, ulCheckTime ); + } +#endif /* ipconfigDNS_USE_CALLBACKS != 0 */ +/*-----------------------------------------------------------*/ + +BaseType_t xIPIsNetworkTaskReady( void ) +{ + return xIPTaskInitialised; +} +/*-----------------------------------------------------------*/ + +BaseType_t FreeRTOS_IsNetworkUp( void ) +{ + return xNetworkUp; +} +/*-----------------------------------------------------------*/ + +#if( ipconfigCHECK_IP_QUEUE_SPACE != 0 ) + UBaseType_t uxGetMinimumIPQueueSpace( void ) + { + return uxQueueMinimumSpace; + } +#endif +/*-----------------------------------------------------------*/ + +/* Provide access to private members for verification. */ +#ifdef FREERTOS_TCP_ENABLE_VERIFICATION + #include "aws_freertos_ip_verification_access_ip_define.h" +#endif + |